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