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