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