sys/types.h ==> sys/param.h
[dragonfly.git] / sys / net / if_arcsubr.c
1 /*      $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $   */
2 /*      $FreeBSD: src/sys/net/if_arcsubr.c,v 1.1.2.5 2003/02/05 18:42:15 fjoe Exp $ */
3 /*      $DragonFly: src/sys/net/Attic/if_arcsubr.c,v 1.13 2005/01/23 20:23:22 joerg Exp $ */
4
5 /*
6  * Copyright (c) 1994, 1995 Ignatios Souvatzis
7  * Copyright (c) 1982, 1989, 1993
8  *      The Regents of the University of California.  All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *      This product includes software developed by the University of
21  *      California, Berkeley and its contributors.
22  * 4. Neither the name of the University nor the names of its contributors
23  *    may be used to endorse or promote products derived from this software
24  *    without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
27  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
30  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * from: NetBSD: if_ethersubr.c,v 1.9 1994/06/29 06:36:11 cgd Exp
39  *       @(#)if_ethersubr.c     8.1 (Berkeley) 6/10/93
40  *
41  */
42 #include "opt_inet.h"
43 #include "opt_inet6.h"
44 #include "opt_ipx.h"
45
46 #include <sys/param.h>
47 #include <sys/systm.h>
48 #include <sys/kernel.h>
49 #include <sys/malloc.h>
50 #include <sys/mbuf.h>
51 #include <sys/protosw.h>
52 #include <sys/socket.h>
53 #include <sys/sockio.h>
54 #include <sys/errno.h>
55 #include <sys/syslog.h>
56
57 #include <machine/cpu.h>
58
59 #include <net/if.h>
60 #include <net/netisr.h>
61 #include <net/route.h>
62 #include <net/if_dl.h>
63 #include <net/if_types.h>
64 #include <net/if_arc.h>
65 #include <net/if_arp.h>
66 #include <net/bpf.h>
67
68 #if defined(INET) || defined(INET6)
69 #include <netinet/in.h>
70 #include <netinet/in_var.h>
71 #include <netinet/if_ether.h>
72 #endif
73
74 #ifdef INET6
75 #include <netinet6/nd6.h>
76 #endif
77
78 #ifdef IPX
79 #include <netproto/ipx/ipx.h>
80 #include <netproto/ipx/ipx_if.h>
81 #endif
82
83 MODULE_VERSION(arcnet, 1);
84
85 #define ARCNET_ALLOW_BROKEN_ARP
86
87 static struct mbuf *arc_defrag (struct ifnet *, struct mbuf *);
88 static int arc_resolvemulti (struct ifnet *, struct sockaddr **,
89                                  struct sockaddr *);
90 static void     arc_input(struct ifnet *, struct mbuf *);
91 static int      arc_output(struct ifnet *, struct mbuf *, struct sockaddr *,
92                            struct rtentry *);
93
94 #define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
95
96 #define gotoerr(e) { error = (e); goto bad;}
97 #define SIN(s)  ((struct sockaddr_in *)s)
98 #define SIPX(s) ((struct sockaddr_ipx *)s)
99
100 const uint8_t   arcbroadcastaddr[1] = {0};
101
102 /*
103  * ARCnet output routine.
104  * Encapsulate a packet of type family for the local net.
105  * Assumes that ifp is actually pointer to arccom structure.
106  */
107 static int
108 arc_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
109            struct rtentry *rt)
110 {
111         struct arc_header       *ah;
112         int                     error;
113         u_int8_t                atype, adst;
114         int                     loop_copy = 0;
115         int                     isphds;
116
117         if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
118                 return (ENETDOWN);      /* m, m1 aren't initialized yet */
119
120         switch (dst->sa_family) {
121 #ifdef INET
122         case AF_INET:
123
124                 /*
125                  * For now, use the simple IP addr -> ARCnet addr mapping
126                  */
127                 if (m->m_flags & (M_BCAST|M_MCAST))
128                         adst = ifp->if_broadcastaddr[0];
129                 else if (ifp->if_flags & IFF_NOARP)
130                         adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
131                 else if (!arpresolve(ifp, rt, m, dst, &adst))
132                         return 0;       /* not resolved yet */
133
134                 atype = (ifp->if_flags & IFF_LINK0) ?
135                         ARCTYPE_IP_OLD : ARCTYPE_IP;
136                 break;
137 #endif
138 #ifdef INET6
139         case AF_INET6:
140                 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
141                         return (0); /* it must be impossible, but... */
142                 atype = ARCTYPE_INET6;
143                 break;
144 #endif
145 #ifdef IPX
146         case AF_IPX:
147                 adst = SIPX(dst)->sipx_addr.x_host.c_host[5];
148                 atype = ARCTYPE_IPX;
149                 if (adst == 0xff)
150                         adst = ifp->if_broadcastaddr[0];
151                 break;
152 #endif
153
154         case AF_UNSPEC:
155                 loop_copy = -1;
156                 ah = (struct arc_header *)dst->sa_data;
157                 adst = ah->arc_dhost;
158                 atype = ah->arc_type;
159
160                 if (atype == ARCTYPE_ARP) {
161                         atype = (ifp->if_flags & IFF_LINK0) ?
162                             ARCTYPE_ARP_OLD: ARCTYPE_ARP;
163
164 #ifdef ARCNET_ALLOW_BROKEN_ARP
165                         /*
166                          * XXX It's not clear per RFC826 if this is needed, but
167                          * "assigned numbers" say this is wrong.
168                          * However, e.g., AmiTCP 3.0Beta used it... we make this
169                          * switchable for emergency cases. Not perfect, but...
170                          */
171                         if (ifp->if_flags & IFF_LINK2)
172                                 mtod(m, struct arphdr *)->ar_pro = atype - 1;
173 #endif
174                 }
175                 break;
176
177         default:
178                 printf("%s: can't handle af%d\n", ifp->if_xname,
179                     dst->sa_family);
180                 gotoerr(EAFNOSUPPORT);
181         }
182
183         isphds = arc_isphds(atype);
184         M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, MB_DONTWAIT);
185         if (m == NULL)
186                 gotoerr(ENOBUFS);
187         ah = mtod(m, struct arc_header *);
188         ah->arc_type = atype;
189         ah->arc_dhost = adst;
190         ah->arc_shost = *IF_LLADDR(ifp);
191         ah->arc_shost = ARC_LLADDR(ifp);
192         if (isphds) {
193                 ah->arc_flag = 0;
194                 ah->arc_seqid = 0;
195         }
196
197         if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
198                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
199                         struct mbuf *n = m_copypacket(m, MB_DONTWAIT);
200
201                         if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
202                 } else if (ah->arc_dhost == ah->arc_shost) {
203                         if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
204                         return (0);     /* XXX */
205                 }
206         }
207
208         BPF_MTAP(ifp, m);
209
210         if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
211                 m = NULL;
212                 gotoerr(ENOBUFS);
213         }
214
215         return (0);
216
217 bad:
218         if (m != NULL)
219                 m_freem(m);
220         return (error);
221 }
222
223 void
224 arc_frag_init(ifp)
225         struct ifnet *ifp;
226 {
227         struct arccom *ac;
228
229         ac = (struct arccom *)ifp;
230         ac->curr_frag = 0;
231 }
232
233 struct mbuf *
234 arc_frag_next(ifp)
235         struct ifnet *ifp;
236 {
237         struct arccom *ac;
238         struct mbuf *m;
239         struct arc_header *ah;
240
241         ac = (struct arccom *)ifp;
242         if ((m = ac->curr_frag) == 0) {
243                 int tfrags;
244
245                 /* dequeue new packet */
246                 IF_DEQUEUE(&ifp->if_snd, m);
247                 if (m == 0)
248                         return 0;
249
250                 ah = mtod(m, struct arc_header *);
251                 if (!arc_isphds(ah->arc_type))
252                         return m;
253
254                 ++ac->ac_seqid;         /* make the seqid unique */
255                 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
256                 ac->fsflag = 2 * tfrags - 3;
257                 ac->sflag = 0;
258                 ac->rsflag = ac->fsflag;
259                 ac->arc_dhost = ah->arc_dhost;
260                 ac->arc_shost = ah->arc_shost;
261                 ac->arc_type = ah->arc_type;
262
263                 m_adj(m, ARC_HDRNEWLEN);
264                 ac->curr_frag = m;
265         }
266
267         /* split out next fragment and return it */
268         if (ac->sflag < ac->fsflag) {
269                 /* we CAN'T have short packets here */
270                 ac->curr_frag = m_split(m, ARC_MAX_DATA, MB_DONTWAIT);
271                 if (ac->curr_frag == 0) {
272                         m_freem(m);
273                         return 0;
274                 }
275
276                 M_PREPEND(m, ARC_HDRNEWLEN, MB_DONTWAIT);
277                 if (m == 0) {
278                         m_freem(ac->curr_frag);
279                         ac->curr_frag = 0;
280                         return 0;
281                 }
282
283                 ah = mtod(m, struct arc_header *);
284                 ah->arc_flag = ac->rsflag;
285                 ah->arc_seqid = ac->ac_seqid;
286
287                 ac->sflag += 2;
288                 ac->rsflag = ac->sflag;
289         } else if ((m->m_pkthdr.len >=
290             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
291             (m->m_pkthdr.len <=
292             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
293                 ac->curr_frag = 0;
294
295                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, MB_DONTWAIT);
296                 if (m == 0)
297                         return 0;
298
299                 ah = mtod(m, struct arc_header *);
300                 ah->arc_flag = 0xFF;
301                 ah->arc_seqid = 0xFFFF;
302                 ah->arc_type2 = ac->arc_type;
303                 ah->arc_flag2 = ac->sflag;
304                 ah->arc_seqid2 = ac->ac_seqid;
305         } else {
306                 ac->curr_frag = 0;
307
308                 M_PREPEND(m, ARC_HDRNEWLEN, MB_DONTWAIT);
309                 if (m == 0)
310                         return 0;
311
312                 ah = mtod(m, struct arc_header *);
313                 ah->arc_flag = ac->sflag;
314                 ah->arc_seqid = ac->ac_seqid;
315         }
316
317         ah->arc_dhost = ac->arc_dhost;
318         ah->arc_shost = ac->arc_shost;
319         ah->arc_type = ac->arc_type;
320
321         return m;
322 }
323
324 /*
325  * Defragmenter. Returns mbuf if last packet found, else
326  * NULL. frees imcoming mbuf as necessary.
327  */
328
329 __inline struct mbuf *
330 arc_defrag(ifp, m)
331         struct ifnet *ifp;
332         struct mbuf *m;
333 {
334         struct arc_header *ah, *ah1;
335         struct arccom *ac;
336         struct ac_frag *af;
337         struct mbuf *m1;
338         char *s;
339         int newflen;
340         u_char src,dst,typ;
341
342         ac = (struct arccom *)ifp;
343
344         if (m->m_len < ARC_HDRNEWLEN) {
345                 m = m_pullup(m, ARC_HDRNEWLEN);
346                 if (m == NULL) {
347                         ++ifp->if_ierrors;
348                         return NULL;
349                 }
350         }
351
352         ah = mtod(m, struct arc_header *);
353         typ = ah->arc_type;
354
355         if (!arc_isphds(typ))
356                 return m;
357
358         src = ah->arc_shost;
359         dst = ah->arc_dhost;
360
361         if (ah->arc_flag == 0xff) {
362                 m_adj(m, 4);
363
364                 if (m->m_len < ARC_HDRNEWLEN) {
365                         m = m_pullup(m, ARC_HDRNEWLEN);
366                         if (m == NULL) {
367                                 ++ifp->if_ierrors;
368                                 return NULL;
369                         }
370                 }
371
372                 ah = mtod(m, struct arc_header *);
373         }
374
375         af = &ac->ac_fragtab[src];
376         m1 = af->af_packet;
377         s = "debug code error";
378
379         if (ah->arc_flag & 1) {
380                 /*
381                  * first fragment. We always initialize, which is
382                  * about the right thing to do, as we only want to
383                  * accept one fragmented packet per src at a time.
384                  */
385                 if (m1 != NULL)
386                         m_freem(m1);
387
388                 af->af_packet = m;
389                 m1 = m;
390                 af->af_maxflag = ah->arc_flag;
391                 af->af_lastseen = 0;
392                 af->af_seqid = ah->arc_seqid;
393
394                 return NULL;
395                 /* notreached */
396         } else {
397                 /* check for unfragmented packet */
398                 if (ah->arc_flag == 0)
399                         return m;
400
401                 /* do we have a first packet from that src? */
402                 if (m1 == NULL) {
403                         s = "no first frag";
404                         goto outofseq;
405                 }
406
407                 ah1 = mtod(m1, struct arc_header *);
408
409                 if (ah->arc_seqid != ah1->arc_seqid) {
410                         s = "seqid differs";
411                         goto outofseq;
412                 }
413
414                 if (typ != ah1->arc_type) {
415                         s = "type differs";
416                         goto outofseq;
417                 }
418
419                 if (dst != ah1->arc_dhost) {
420                         s = "dest host differs";
421                         goto outofseq;
422                 }
423
424                 /* typ, seqid and dst are ok here. */
425
426                 if (ah->arc_flag == af->af_lastseen) {
427                         m_freem(m);
428                         return NULL;
429                 }
430
431                 if (ah->arc_flag == af->af_lastseen + 2) {
432                         /* ok, this is next fragment */
433                         af->af_lastseen = ah->arc_flag;
434                         m_adj(m,ARC_HDRNEWLEN);
435
436                         /*
437                          * m_cat might free the first mbuf (with pkthdr)
438                          * in 2nd chain; therefore:
439                          */
440
441                         newflen = m->m_pkthdr.len;
442
443                         m_cat(m1,m);
444
445                         m1->m_pkthdr.len += newflen;
446
447                         /* is it the last one? */
448                         if (af->af_lastseen > af->af_maxflag) {
449                                 af->af_packet = NULL;
450                                 return (m1);
451                         } else
452                                 return NULL;
453                 }
454                 s = "other reason";
455                 /* if all else fails, it is out of sequence, too */
456         }
457 outofseq:
458         if (m1 != NULL) {
459                 m_freem(m1);
460                 af->af_packet = NULL;
461         }
462
463         if (m != NULL)
464                 m_freem(m);
465
466         log(LOG_INFO,"%s: got out of seq. packet: %s\n",
467             ifp->if_xname, s);
468
469         return NULL;
470 }
471
472 /*
473  * return 1 if Packet Header Definition Standard, else 0.
474  * For now: old IP, old ARP aren't obviously. Lacking correct information,
475  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
476  * (Apple and Novell corporations were involved, among others, in PHDS work).
477  * Easiest is to assume that everybody else uses that, too.
478  */
479 int
480 arc_isphds(type)
481         u_int8_t type;
482 {
483         return (type != ARCTYPE_IP_OLD &&
484                 type != ARCTYPE_ARP_OLD &&
485                 type != ARCTYPE_DIAGNOSE);
486 }
487
488 /*
489  * Process a received Arcnet packet;
490  * the packet is in the mbuf chain m with
491  * the ARCnet header.
492  */
493 static void
494 arc_input(struct ifnet *ifp, struct mbuf *m)
495 {
496         struct arc_header *ah;
497         int isr;
498         u_int8_t atype;
499
500         if (!(ifp->if_flags & IFF_UP)) {
501                 m_freem(m);
502                 return;
503         }
504
505         /* possibly defragment: */
506         m = arc_defrag(ifp, m);
507         if (m == NULL)
508                 return;
509
510         BPF_MTAP(ifp, m);
511
512         ah = mtod(m, struct arc_header *);
513         /* does this belong to us? */
514         if (!(ifp->if_flags & IFF_PROMISC) &&
515             ah->arc_dhost != ifp->if_broadcastaddr[0] &&
516             ah->arc_dhost != ARC_LLADDR(ifp)) {
517                 m_freem(m);
518                 return;
519         }
520
521         ifp->if_ibytes += m->m_pkthdr.len;
522
523         if (ah->arc_dhost == ifp->if_broadcastaddr[0]) {
524                 m->m_flags |= M_BCAST|M_MCAST;
525                 ifp->if_imcasts++;
526         }
527
528         atype = ah->arc_type;
529         switch (atype) {
530 #ifdef INET
531         case ARCTYPE_IP:
532                 m_adj(m, ARC_HDRNEWLEN);
533                 if (ipflow_fastforward(m))
534                         return;
535                 isr = NETISR_IP;
536                 break;
537
538         case ARCTYPE_IP_OLD:
539                 m_adj(m, ARC_HDRLEN);
540                 if (ipflow_fastforward(m))
541                         return;
542                 isr = NETISR_IP;
543                 break;
544
545         case ARCTYPE_ARP:
546                 if (ifp->if_flags & IFF_NOARP) {
547                         /* Discard packet if ARP is disabled on interface */
548                         m_freem(m);
549                         return;
550                 }
551                 m_adj(m, ARC_HDRNEWLEN);
552                 isr = NETISR_ARP;
553 #ifdef ARCNET_ALLOW_BROKEN_ARP
554                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
555 #endif
556                 break;
557
558         case ARCTYPE_ARP_OLD:
559                 if (ifp->if_flags & IFF_NOARP) {
560                         /* Discard packet if ARP is disabled on interface */
561                         m_freem(m);
562                         return;
563                 }
564                 m_adj(m, ARC_HDRLEN);
565                 isr = NETISR_ARP;
566 #ifdef ARCNET_ALLOW_BROKEN_ARP
567                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
568 #endif
569                 break;
570 #endif
571 #ifdef INET6
572         case ARCTYPE_INET6:
573                 m_adj(m, ARC_HDRNEWLEN);
574                 isr = NETISR_IPV6;
575                 break;
576 #endif
577 #ifdef IPX
578         case ARCTYPE_IPX:
579                 m_adj(m, ARC_HDRNEWLEN);
580                 isr = NETISR_IPX;
581                 break;
582 #endif
583         default:
584                 m_freem(m);
585                 return;
586         }
587
588         netisr_dispatch(isr, m);
589 }
590
591 /*
592  * Register (new) link level address.
593  */
594 void
595 arc_storelladdr(ifp, lla)
596         struct ifnet *ifp;
597         u_int8_t lla;
598 {
599         ARC_LLADDR(ifp) = lla;
600 }
601
602 /*
603  * Perform common duties while attaching to interface list
604  */
605 void
606 arc_ifattach(ifp, lla)
607         struct ifnet *ifp;
608         u_int8_t lla;
609 {
610         struct ifaddr *ifa;
611         struct sockaddr_dl *sdl;
612         struct arccom *ac;
613
614         ifp->if_input = arc_input;
615         ifp->if_output = arc_output;
616         if_attach(ifp);
617         ifp->if_type = IFT_ARCNET;
618         ifp->if_addrlen = 1;
619         ifp->if_broadcastaddr = arcbroadcastaddr;
620         ifp->if_hdrlen = ARC_HDRLEN;
621         ifp->if_mtu = 1500;
622         ifp->if_resolvemulti = arc_resolvemulti;
623         if (ifp->if_baudrate == 0)
624                 ifp->if_baudrate = 2500000;
625 #if defined(__DragonFly__) || __FreeBSD_version < 500000
626         ifa = ifnet_addrs[ifp->if_index - 1];
627 #else
628         ifa = ifaddr_byindex(ifp->if_index);
629 #endif
630         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
631         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
632         sdl->sdl_type = IFT_ARCNET;
633         sdl->sdl_alen = ifp->if_addrlen;
634
635         if (ifp->if_flags & IFF_BROADCAST)
636                 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
637
638         ac = (struct arccom *)ifp;
639         ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
640         if (lla == 0) {
641                 /* XXX this message isn't entirely clear, to me -- cgd */
642                 log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
643                    ifp->if_xname, ifp->if_xname);
644         }
645         arc_storelladdr(ifp, lla);
646
647         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
648 }
649
650 void
651 arc_ifdetach(ifp)
652         struct ifnet *ifp;
653 {
654         bpfdetach(ifp);
655         if_detach(ifp);
656 }
657
658 int
659 arc_ioctl(ifp, command, data)
660         struct ifnet *ifp;
661         int command;
662         caddr_t data;
663 {
664         struct ifaddr *ifa = (struct ifaddr *) data;
665         struct ifreq *ifr = (struct ifreq *) data;
666         int error = 0;
667
668         switch (command) {
669         case SIOCSIFADDR:
670                 ifp->if_flags |= IFF_UP;
671                 switch (ifa->ifa_addr->sa_family) {
672 #ifdef INET
673                 case AF_INET:
674                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
675                         arp_ifinit(ifp, ifa);
676                         break;
677 #endif
678 #ifdef IPX
679                 /*
680                  * XXX This code is probably wrong
681                  */
682                 case AF_IPX:
683                 {
684                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
685
686                         if (ipx_nullhost(*ina))
687                                 ina->x_host.c_host[5] = ARC_LLADDR(ifp);
688                         else
689                                 arc_storelladdr(ifp, ina->x_host.c_host[5]);
690
691                         /*
692                          * Set new address
693                          */
694                         ifp->if_init(ifp->if_softc);
695                         break;
696                 }
697 #endif
698                 default:
699                         ifp->if_init(ifp->if_softc);
700                         break;
701                 }
702                 break;
703
704         case SIOCGIFADDR:
705                 {
706                         struct sockaddr *sa;
707
708                         sa = (struct sockaddr *) &ifr->ifr_data;
709                         *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
710                 }
711                 break;
712
713         case SIOCADDMULTI:
714         case SIOCDELMULTI:
715                 if (ifr == NULL)
716                         error = EAFNOSUPPORT;
717                 else {
718                         switch (ifr->ifr_addr.sa_family) {
719                         case AF_INET:
720                         case AF_INET6:
721                                 error = 0;
722                                 break;
723                         default:
724                                 error = EAFNOSUPPORT;
725                                 break;
726                         }
727                 }
728                 break;
729
730         case SIOCSIFMTU:
731                 /*
732                  * Set the interface MTU.
733                  * mtu can't be larger than ARCMTU for RFC1051
734                  * and can't be larger than ARC_PHDS_MTU
735                  */
736                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
737                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
738                         error = EINVAL;
739                 else
740                         ifp->if_mtu = ifr->ifr_mtu;
741                 break;
742         }
743
744         return (error);
745 }
746
747 /* based on ether_resolvemulti() */
748 int
749 arc_resolvemulti(ifp, llsa, sa)
750         struct ifnet *ifp;
751         struct sockaddr **llsa;
752         struct sockaddr *sa;
753 {
754         struct sockaddr_dl *sdl;
755         struct sockaddr_in *sin;
756 #ifdef INET6
757         struct sockaddr_in6 *sin6;
758 #endif
759
760         switch(sa->sa_family) {
761         case AF_LINK:
762                 /*
763                 * No mapping needed. Just check that it's a valid MC address.
764                 */
765                 sdl = (struct sockaddr_dl *)sa;
766                 if (*LLADDR(sdl) != ifp->if_broadcastaddr[0])
767                         return EADDRNOTAVAIL;
768                 *llsa = 0;
769                 return 0;
770 #ifdef INET
771         case AF_INET:
772                 sin = (struct sockaddr_in *)sa;
773                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
774                         return EADDRNOTAVAIL;
775                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
776                        M_WAITOK|M_ZERO);
777                 sdl->sdl_len = sizeof *sdl;
778                 sdl->sdl_family = AF_LINK;
779                 sdl->sdl_index = ifp->if_index;
780                 sdl->sdl_type = IFT_ARCNET;
781                 sdl->sdl_alen = ARC_ADDR_LEN;
782                 *LLADDR(sdl) = 0;
783                 *llsa = (struct sockaddr *)sdl;
784                 return 0;
785 #endif
786 #ifdef INET6
787         case AF_INET6:
788                 sin6 = (struct sockaddr_in6 *)sa;
789                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
790                         /*
791                          * An IP6 address of 0 means listen to all
792                          * of the Ethernet multicast address used for IP6.
793                          * (This is used for multicast routers.)
794                          */
795                         ifp->if_flags |= IFF_ALLMULTI;
796                         *llsa = 0;
797                         return 0;
798                 }
799                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
800                         return EADDRNOTAVAIL;
801                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
802                        M_WAITOK|M_ZERO);
803                 sdl->sdl_len = sizeof *sdl;
804                 sdl->sdl_family = AF_LINK;
805                 sdl->sdl_index = ifp->if_index;
806                 sdl->sdl_type = IFT_ARCNET;
807                 sdl->sdl_alen = ARC_ADDR_LEN;
808                 *LLADDR(sdl) = 0;
809                 *llsa = (struct sockaddr *)sdl;
810                 return 0;
811 #endif
812
813         default:
814                 /*
815                  * Well, the text isn't quite right, but it's the name
816                  * that counts...
817                  */
818                 return EAFNOSUPPORT;
819         }
820 }