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