Merge from vendor branch DHCP:
[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.11 2004/12/21 02:54:14 hsu 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 senderr(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                 senderr(EAFNOSUPPORT);
181         }
182
183         isphds = arc_isphds(atype);
184         M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, MB_DONTWAIT);
185         if (m == NULL)
186                 senderr(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         if (ifp->if_bpf)
209                 bpf_mtap(ifp, m);
210
211         if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
212                 m = 0;
213                 senderr(ENOBUFS);
214         }
215
216         return (0);
217
218 bad:
219         if (m)
220                 m_freem(m);
221         return (error);
222 }
223
224 void
225 arc_frag_init(ifp)
226         struct ifnet *ifp;
227 {
228         struct arccom *ac;
229
230         ac = (struct arccom *)ifp;
231         ac->curr_frag = 0;
232 }
233
234 struct mbuf *
235 arc_frag_next(ifp)
236         struct ifnet *ifp;
237 {
238         struct arccom *ac;
239         struct mbuf *m;
240         struct arc_header *ah;
241
242         ac = (struct arccom *)ifp;
243         if ((m = ac->curr_frag) == 0) {
244                 int tfrags;
245
246                 /* dequeue new packet */
247                 IF_DEQUEUE(&ifp->if_snd, m);
248                 if (m == 0)
249                         return 0;
250
251                 ah = mtod(m, struct arc_header *);
252                 if (!arc_isphds(ah->arc_type))
253                         return m;
254
255                 ++ac->ac_seqid;         /* make the seqid unique */
256                 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
257                 ac->fsflag = 2 * tfrags - 3;
258                 ac->sflag = 0;
259                 ac->rsflag = ac->fsflag;
260                 ac->arc_dhost = ah->arc_dhost;
261                 ac->arc_shost = ah->arc_shost;
262                 ac->arc_type = ah->arc_type;
263
264                 m_adj(m, ARC_HDRNEWLEN);
265                 ac->curr_frag = m;
266         }
267
268         /* split out next fragment and return it */
269         if (ac->sflag < ac->fsflag) {
270                 /* we CAN'T have short packets here */
271                 ac->curr_frag = m_split(m, ARC_MAX_DATA, MB_DONTWAIT);
272                 if (ac->curr_frag == 0) {
273                         m_freem(m);
274                         return 0;
275                 }
276
277                 M_PREPEND(m, ARC_HDRNEWLEN, MB_DONTWAIT);
278                 if (m == 0) {
279                         m_freem(ac->curr_frag);
280                         ac->curr_frag = 0;
281                         return 0;
282                 }
283
284                 ah = mtod(m, struct arc_header *);
285                 ah->arc_flag = ac->rsflag;
286                 ah->arc_seqid = ac->ac_seqid;
287
288                 ac->sflag += 2;
289                 ac->rsflag = ac->sflag;
290         } else if ((m->m_pkthdr.len >=
291             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
292             (m->m_pkthdr.len <=
293             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
294                 ac->curr_frag = 0;
295
296                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, MB_DONTWAIT);
297                 if (m == 0)
298                         return 0;
299
300                 ah = mtod(m, struct arc_header *);
301                 ah->arc_flag = 0xFF;
302                 ah->arc_seqid = 0xFFFF;
303                 ah->arc_type2 = ac->arc_type;
304                 ah->arc_flag2 = ac->sflag;
305                 ah->arc_seqid2 = ac->ac_seqid;
306         } else {
307                 ac->curr_frag = 0;
308
309                 M_PREPEND(m, ARC_HDRNEWLEN, MB_DONTWAIT);
310                 if (m == 0)
311                         return 0;
312
313                 ah = mtod(m, struct arc_header *);
314                 ah->arc_flag = ac->sflag;
315                 ah->arc_seqid = ac->ac_seqid;
316         }
317
318         ah->arc_dhost = ac->arc_dhost;
319         ah->arc_shost = ac->arc_shost;
320         ah->arc_type = ac->arc_type;
321
322         return m;
323 }
324
325 /*
326  * Defragmenter. Returns mbuf if last packet found, else
327  * NULL. frees imcoming mbuf as necessary.
328  */
329
330 __inline struct mbuf *
331 arc_defrag(ifp, m)
332         struct ifnet *ifp;
333         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) {
460                 m_freem(m1);
461                 af->af_packet = NULL;
462         }
463
464         if (m)
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(type)
482         u_int8_t type;
483 {
484         return (type != ARCTYPE_IP_OLD &&
485                 type != ARCTYPE_ARP_OLD &&
486                 type != ARCTYPE_DIAGNOSE);
487 }
488
489 /*
490  * Process a received Arcnet packet;
491  * the packet is in the mbuf chain m with
492  * the ARCnet header.
493  */
494 static void
495 arc_input(struct ifnet *ifp, struct mbuf *m)
496 {
497         struct arc_header *ah;
498         int isr;
499         u_int8_t atype;
500
501         if ((ifp->if_flags & IFF_UP) == 0) {
502                 m_freem(m);
503                 return;
504         }
505
506         /* possibly defragment: */
507         m = arc_defrag(ifp, m);
508         if (m == NULL)
509                 return;
510
511         if (ifp->if_bpf)
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) == 0
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))
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))
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(ifp, lla)
598         struct ifnet *ifp;
599         u_int8_t lla;
600 {
601         ARC_LLADDR(ifp) = lla;
602 }
603
604 /*
605  * Perform common duties while attaching to interface list
606  */
607 void
608 arc_ifattach(ifp, lla)
609         struct ifnet *ifp;
610         u_int8_t lla;
611 {
612         struct ifaddr *ifa;
613         struct sockaddr_dl *sdl;
614         struct arccom *ac;
615
616         ifp->if_input = arc_input;
617         ifp->if_output = arc_output;
618         if_attach(ifp);
619         ifp->if_type = IFT_ARCNET;
620         ifp->if_addrlen = 1;
621         ifp->if_broadcastaddr = arcbroadcastaddr;
622         ifp->if_hdrlen = ARC_HDRLEN;
623         ifp->if_mtu = 1500;
624         ifp->if_resolvemulti = arc_resolvemulti;
625         if (ifp->if_baudrate == 0)
626                 ifp->if_baudrate = 2500000;
627 #if defined(__DragonFly__) || __FreeBSD_version < 500000
628         ifa = ifnet_addrs[ifp->if_index - 1];
629 #else
630         ifa = ifaddr_byindex(ifp->if_index);
631 #endif
632         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
633         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
634         sdl->sdl_type = IFT_ARCNET;
635         sdl->sdl_alen = ifp->if_addrlen;
636
637         if (ifp->if_flags & IFF_BROADCAST)
638                 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
639
640         ac = (struct arccom *)ifp;
641         ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
642         if (lla == 0) {
643                 /* XXX this message isn't entirely clear, to me -- cgd */
644                 log(LOG_ERR,"%s: link address 0 reserved for broadcasts.  Please change it and ifconfig %s down up\n",
645                    ifp->if_xname, ifp->if_xname);
646         }
647         arc_storelladdr(ifp, lla);
648
649         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
650 }
651
652 void
653 arc_ifdetach(ifp)
654         struct ifnet *ifp;
655 {
656         bpfdetach(ifp);
657         if_detach(ifp);
658 }
659
660 int
661 arc_ioctl(ifp, command, data)
662         struct ifnet *ifp;
663         int command;
664         caddr_t data;
665 {
666         struct ifaddr *ifa = (struct ifaddr *) data;
667         struct ifreq *ifr = (struct ifreq *) data;
668         int error = 0;
669
670         switch (command) {
671         case SIOCSIFADDR:
672                 ifp->if_flags |= IFF_UP;
673                 switch (ifa->ifa_addr->sa_family) {
674 #ifdef INET
675                 case AF_INET:
676                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
677                         arp_ifinit(ifp, ifa);
678                         break;
679 #endif
680 #ifdef IPX
681                 /*
682                  * XXX This code is probably wrong
683                  */
684                 case AF_IPX:
685                 {
686                         struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr);
687
688                         if (ipx_nullhost(*ina))
689                                 ina->x_host.c_host[5] = ARC_LLADDR(ifp);
690                         else
691                                 arc_storelladdr(ifp, ina->x_host.c_host[5]);
692
693                         /*
694                          * Set new address
695                          */
696                         ifp->if_init(ifp->if_softc);
697                         break;
698                 }
699 #endif
700                 default:
701                         ifp->if_init(ifp->if_softc);
702                         break;
703                 }
704                 break;
705
706         case SIOCGIFADDR:
707                 {
708                         struct sockaddr *sa;
709
710                         sa = (struct sockaddr *) &ifr->ifr_data;
711                         *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
712                 }
713                 break;
714
715         case SIOCADDMULTI:
716         case SIOCDELMULTI:
717                 if (ifr == NULL)
718                         error = EAFNOSUPPORT;
719                 else {
720                         switch (ifr->ifr_addr.sa_family) {
721                         case AF_INET:
722                         case AF_INET6:
723                                 error = 0;
724                                 break;
725                         default:
726                                 error = EAFNOSUPPORT;
727                                 break;
728                         }
729                 }
730                 break;
731
732         case SIOCSIFMTU:
733                 /*
734                  * Set the interface MTU.
735                  * mtu can't be larger than ARCMTU for RFC1051
736                  * and can't be larger than ARC_PHDS_MTU
737                  */
738                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
739                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
740                         error = EINVAL;
741                 else
742                         ifp->if_mtu = ifr->ifr_mtu;
743                 break;
744         }
745
746         return (error);
747 }
748
749 /* based on ether_resolvemulti() */
750 int
751 arc_resolvemulti(ifp, llsa, sa)
752         struct ifnet *ifp;
753         struct sockaddr **llsa;
754         struct sockaddr *sa;
755 {
756         struct sockaddr_dl *sdl;
757         struct sockaddr_in *sin;
758 #ifdef INET6
759         struct sockaddr_in6 *sin6;
760 #endif
761
762         switch(sa->sa_family) {
763         case AF_LINK:
764                 /*
765                 * No mapping needed. Just check that it's a valid MC address.
766                 */
767                 sdl = (struct sockaddr_dl *)sa;
768                 if (*LLADDR(sdl) != ifp->if_broadcastaddr[0])
769                         return EADDRNOTAVAIL;
770                 *llsa = 0;
771                 return 0;
772 #ifdef INET
773         case AF_INET:
774                 sin = (struct sockaddr_in *)sa;
775                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
776                         return EADDRNOTAVAIL;
777                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
778                        M_WAITOK|M_ZERO);
779                 sdl->sdl_len = sizeof *sdl;
780                 sdl->sdl_family = AF_LINK;
781                 sdl->sdl_index = ifp->if_index;
782                 sdl->sdl_type = IFT_ARCNET;
783                 sdl->sdl_alen = ARC_ADDR_LEN;
784                 *LLADDR(sdl) = 0;
785                 *llsa = (struct sockaddr *)sdl;
786                 return 0;
787 #endif
788 #ifdef INET6
789         case AF_INET6:
790                 sin6 = (struct sockaddr_in6 *)sa;
791                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
792                         /*
793                          * An IP6 address of 0 means listen to all
794                          * of the Ethernet multicast address used for IP6.
795                          * (This is used for multicast routers.)
796                          */
797                         ifp->if_flags |= IFF_ALLMULTI;
798                         *llsa = 0;
799                         return 0;
800                 }
801                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
802                         return EADDRNOTAVAIL;
803                 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
804                        M_WAITOK|M_ZERO);
805                 sdl->sdl_len = sizeof *sdl;
806                 sdl->sdl_family = AF_LINK;
807                 sdl->sdl_index = ifp->if_index;
808                 sdl->sdl_type = IFT_ARCNET;
809                 sdl->sdl_alen = ARC_ADDR_LEN;
810                 *LLADDR(sdl) = 0;
811                 *llsa = (struct sockaddr *)sdl;
812                 return 0;
813 #endif
814
815         default:
816                 /*
817                  * Well, the text isn't quite right, but it's the name
818                  * that counts...
819                  */
820                 return EAFNOSUPPORT;
821         }
822 }