]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_arcsubr.c
Update hostapd/wpa_supplicant to version 2.5.
[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
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/kernel.h>
47 #include <sys/module.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/if_var.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 #include <net/if_llatbl.h>
68
69 #if defined(INET) || defined(INET6)
70 #include <netinet/in.h>
71 #include <netinet/in_var.h>
72 #include <netinet/if_ether.h>
73 #endif
74
75 #ifdef INET6
76 #include <netinet6/nd6.h>
77 #endif
78
79 #define ARCNET_ALLOW_BROKEN_ARP
80
81 static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
82 static int arc_resolvemulti(struct ifnet *, struct sockaddr **,
83                             struct sockaddr *);
84
85 u_int8_t  arcbroadcastaddr = 0;
86
87 #define ARC_LLADDR(ifp) (*(u_int8_t *)IF_LLADDR(ifp))
88
89 #define senderr(e) { error = (e); goto bad;}
90 #define SIN(s)  ((const struct sockaddr_in *)(s))
91
92 /*
93  * ARCnet output routine.
94  * Encapsulate a packet of type family for the local net.
95  * Assumes that ifp is actually pointer to arccom structure.
96  */
97 int
98 arc_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst,
99     struct route *ro)
100 {
101         struct arc_header       *ah;
102         int                     error;
103         u_int8_t                atype, adst;
104         int                     loop_copy = 0;
105         int                     isphds;
106 #if defined(INET) || defined(INET6)
107         int                     is_gw = 0;
108 #endif
109
110         if (!((ifp->if_flags & IFF_UP) &&
111             (ifp->if_drv_flags & IFF_DRV_RUNNING)))
112                 return(ENETDOWN); /* m, m1 aren't initialized yet */
113
114         error = 0;
115 #if defined(INET) || defined(INET6)
116         if (ro != NULL && ro->ro_rt != NULL &&
117             (ro->ro_rt->rt_flags & RTF_GATEWAY) != 0)
118                 is_gw = 1;
119 #endif
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, is_gw, m, dst, &adst, NULL);
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                 if ((m->m_flags & M_MCAST) != 0)
172                         adst = arcbroadcastaddr; /* ARCnet broadcast address */
173                 else {
174                         error = nd6_resolve(ifp, is_gw, m, dst, &adst, NULL);
175                         if (error != 0)
176                                 return (error == EWOULDBLOCK ? 0 : error);
177                 }
178                 atype = ARCTYPE_INET6;
179                 break;
180 #endif
181         case AF_UNSPEC:
182             {
183                 const struct arc_header *ah;
184
185                 loop_copy = -1;
186                 ah = (const struct arc_header *)dst->sa_data;
187                 adst = ah->arc_dhost;
188                 atype = ah->arc_type;
189
190                 if (atype == ARCTYPE_ARP) {
191                         atype = (ifp->if_flags & IFF_LINK0) ?
192                             ARCTYPE_ARP_OLD: ARCTYPE_ARP;
193
194 #ifdef ARCNET_ALLOW_BROKEN_ARP
195                         /*
196                          * XXX It's not clear per RFC826 if this is needed, but
197                          * "assigned numbers" say this is wrong.
198                          * However, e.g., AmiTCP 3.0Beta used it... we make this
199                          * switchable for emergency cases. Not perfect, but...
200                          */
201                         if (ifp->if_flags & IFF_LINK2)
202                                 mtod(m, struct arphdr *)->ar_pro = atype - 1;
203 #endif
204                 }
205                 break;
206             }
207         default:
208                 if_printf(ifp, "can't handle af%d\n", dst->sa_family);
209                 senderr(EAFNOSUPPORT);
210         }
211
212         isphds = arc_isphds(atype);
213         M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT);
214         if (m == 0)
215                 senderr(ENOBUFS);
216         ah = mtod(m, struct arc_header *);
217         ah->arc_type = atype;
218         ah->arc_dhost = adst;
219         ah->arc_shost = ARC_LLADDR(ifp);
220         if (isphds) {
221                 ah->arc_flag = 0;
222                 ah->arc_seqid = 0;
223         }
224
225         if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) {
226                 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) {
227                         struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
228
229                         (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN);
230                 } else if (ah->arc_dhost == ah->arc_shost) {
231                         (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN);
232                         return (0);     /* XXX */
233                 }
234         }
235
236         BPF_MTAP(ifp, m);
237
238         error = ifp->if_transmit(ifp, m);
239
240         return (error);
241
242 bad:
243         if (m)
244                 m_freem(m);
245         return (error);
246 }
247
248 void
249 arc_frag_init(struct ifnet *ifp)
250 {
251         struct arccom *ac;
252
253         ac = (struct arccom *)ifp->if_l2com;
254         ac->curr_frag = 0;
255 }
256
257 struct mbuf *
258 arc_frag_next(struct ifnet *ifp)
259 {
260         struct arccom *ac;
261         struct mbuf *m;
262         struct arc_header *ah;
263
264         ac = (struct arccom *)ifp->if_l2com;
265         if ((m = ac->curr_frag) == 0) {
266                 int tfrags;
267
268                 /* dequeue new packet */
269                 IF_DEQUEUE(&ifp->if_snd, m);
270                 if (m == 0)
271                         return 0;
272
273                 ah = mtod(m, struct arc_header *);
274                 if (!arc_isphds(ah->arc_type))
275                         return m;
276
277                 ++ac->ac_seqid;         /* make the seqid unique */
278                 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA;
279                 ac->fsflag = 2 * tfrags - 3;
280                 ac->sflag = 0;
281                 ac->rsflag = ac->fsflag;
282                 ac->arc_dhost = ah->arc_dhost;
283                 ac->arc_shost = ah->arc_shost;
284                 ac->arc_type = ah->arc_type;
285
286                 m_adj(m, ARC_HDRNEWLEN);
287                 ac->curr_frag = m;
288         }
289
290         /* split out next fragment and return it */
291         if (ac->sflag < ac->fsflag) {
292                 /* we CAN'T have short packets here */
293                 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT);
294                 if (ac->curr_frag == 0) {
295                         m_freem(m);
296                         return 0;
297                 }
298
299                 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
300                 if (m == 0) {
301                         m_freem(ac->curr_frag);
302                         ac->curr_frag = 0;
303                         return 0;
304                 }
305
306                 ah = mtod(m, struct arc_header *);
307                 ah->arc_flag = ac->rsflag;
308                 ah->arc_seqid = ac->ac_seqid;
309
310                 ac->sflag += 2;
311                 ac->rsflag = ac->sflag;
312         } else if ((m->m_pkthdr.len >=
313             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
314             (m->m_pkthdr.len <=
315             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
316                 ac->curr_frag = 0;
317
318                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT);
319                 if (m == 0)
320                         return 0;
321
322                 ah = mtod(m, struct arc_header *);
323                 ah->arc_flag = 0xFF;
324                 ah->arc_seqid = 0xFFFF;
325                 ah->arc_type2 = ac->arc_type;
326                 ah->arc_flag2 = ac->sflag;
327                 ah->arc_seqid2 = ac->ac_seqid;
328         } else {
329                 ac->curr_frag = 0;
330
331                 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT);
332                 if (m == 0)
333                         return 0;
334
335                 ah = mtod(m, struct arc_header *);
336                 ah->arc_flag = ac->sflag;
337                 ah->arc_seqid = ac->ac_seqid;
338         }
339
340         ah->arc_dhost = ac->arc_dhost;
341         ah->arc_shost = ac->arc_shost;
342         ah->arc_type = ac->arc_type;
343
344         return m;
345 }
346
347 /*
348  * Defragmenter. Returns mbuf if last packet found, else
349  * NULL. frees imcoming mbuf as necessary.
350  */
351
352 static __inline struct mbuf *
353 arc_defrag(struct ifnet *ifp, struct mbuf *m)
354 {
355         struct arc_header *ah, *ah1;
356         struct arccom *ac;
357         struct ac_frag *af;
358         struct mbuf *m1;
359         char *s;
360         int newflen;
361         u_char src,dst,typ;
362
363         ac = (struct arccom *)ifp->if_l2com;
364
365         if (m->m_len < ARC_HDRNEWLEN) {
366                 m = m_pullup(m, ARC_HDRNEWLEN);
367                 if (m == NULL) {
368                         if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
369                         return NULL;
370                 }
371         }
372
373         ah = mtod(m, struct arc_header *);
374         typ = ah->arc_type;
375
376         if (!arc_isphds(typ))
377                 return m;
378
379         src = ah->arc_shost;
380         dst = ah->arc_dhost;
381
382         if (ah->arc_flag == 0xff) {
383                 m_adj(m, 4);
384
385                 if (m->m_len < ARC_HDRNEWLEN) {
386                         m = m_pullup(m, ARC_HDRNEWLEN);
387                         if (m == NULL) {
388                                 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1);
389                                 return NULL;
390                         }
391                 }
392
393                 ah = mtod(m, struct arc_header *);
394         }
395
396         af = &ac->ac_fragtab[src];
397         m1 = af->af_packet;
398         s = "debug code error";
399
400         if (ah->arc_flag & 1) {
401                 /*
402                  * first fragment. We always initialize, which is
403                  * about the right thing to do, as we only want to
404                  * accept one fragmented packet per src at a time.
405                  */
406                 if (m1 != NULL)
407                         m_freem(m1);
408
409                 af->af_packet = m;
410                 m1 = m;
411                 af->af_maxflag = ah->arc_flag;
412                 af->af_lastseen = 0;
413                 af->af_seqid = ah->arc_seqid;
414
415                 return NULL;
416                 /* notreached */
417         } else {
418                 /* check for unfragmented packet */
419                 if (ah->arc_flag == 0)
420                         return m;
421
422                 /* do we have a first packet from that src? */
423                 if (m1 == NULL) {
424                         s = "no first frag";
425                         goto outofseq;
426                 }
427
428                 ah1 = mtod(m1, struct arc_header *);
429
430                 if (ah->arc_seqid != ah1->arc_seqid) {
431                         s = "seqid differs";
432                         goto outofseq;
433                 }
434
435                 if (typ != ah1->arc_type) {
436                         s = "type differs";
437                         goto outofseq;
438                 }
439
440                 if (dst != ah1->arc_dhost) {
441                         s = "dest host differs";
442                         goto outofseq;
443                 }
444
445                 /* typ, seqid and dst are ok here. */
446
447                 if (ah->arc_flag == af->af_lastseen) {
448                         m_freem(m);
449                         return NULL;
450                 }
451
452                 if (ah->arc_flag == af->af_lastseen + 2) {
453                         /* ok, this is next fragment */
454                         af->af_lastseen = ah->arc_flag;
455                         m_adj(m,ARC_HDRNEWLEN);
456
457                         /*
458                          * m_cat might free the first mbuf (with pkthdr)
459                          * in 2nd chain; therefore:
460                          */
461
462                         newflen = m->m_pkthdr.len;
463
464                         m_cat(m1,m);
465
466                         m1->m_pkthdr.len += newflen;
467
468                         /* is it the last one? */
469                         if (af->af_lastseen > af->af_maxflag) {
470                                 af->af_packet = NULL;
471                                 return(m1);
472                         } else
473                                 return NULL;
474                 }
475                 s = "other reason";
476                 /* if all else fails, it is out of sequence, too */
477         }
478 outofseq:
479         if (m1) {
480                 m_freem(m1);
481                 af->af_packet = NULL;
482         }
483
484         if (m)
485                 m_freem(m);
486
487         log(LOG_INFO,"%s: got out of seq. packet: %s\n",
488             ifp->if_xname, s);
489
490         return NULL;
491 }
492
493 /*
494  * return 1 if Packet Header Definition Standard, else 0.
495  * For now: old IP, old ARP aren't obviously. Lacking correct information,
496  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
497  * (Apple and Novell corporations were involved, among others, in PHDS work).
498  * Easiest is to assume that everybody else uses that, too.
499  */
500 int
501 arc_isphds(u_int8_t type)
502 {
503         return (type != ARCTYPE_IP_OLD &&
504                 type != ARCTYPE_ARP_OLD &&
505                 type != ARCTYPE_DIAGNOSE);
506 }
507
508 /*
509  * Process a received Arcnet packet;
510  * the packet is in the mbuf chain m with
511  * the ARCnet header.
512  */
513 void
514 arc_input(struct ifnet *ifp, struct mbuf *m)
515 {
516         struct arc_header *ah;
517         int isr;
518         u_int8_t atype;
519
520         if ((ifp->if_flags & IFF_UP) == 0) {
521                 m_freem(m);
522                 return;
523         }
524
525         /* possibly defragment: */
526         m = arc_defrag(ifp, m);
527         if (m == NULL)
528                 return;
529
530         BPF_MTAP(ifp, m);
531
532         ah = mtod(m, struct arc_header *);
533         /* does this belong to us? */
534         if ((ifp->if_flags & IFF_PROMISC) == 0
535             && ah->arc_dhost != arcbroadcastaddr
536             && ah->arc_dhost != ARC_LLADDR(ifp)) {
537                 m_freem(m);
538                 return;
539         }
540
541         if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len);
542
543         if (ah->arc_dhost == arcbroadcastaddr) {
544                 m->m_flags |= M_BCAST|M_MCAST;
545                 if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1);
546         }
547
548         atype = ah->arc_type;
549         switch (atype) {
550 #ifdef INET
551         case ARCTYPE_IP:
552                 m_adj(m, ARC_HDRNEWLEN);
553                 if ((m = ip_fastforward(m)) == NULL)
554                         return;
555                 isr = NETISR_IP;
556                 break;
557
558         case ARCTYPE_IP_OLD:
559                 m_adj(m, ARC_HDRLEN);
560                 if ((m = ip_fastforward(m)) == NULL)
561                         return;
562                 isr = NETISR_IP;
563                 break;
564
565         case ARCTYPE_ARP:
566                 if (ifp->if_flags & IFF_NOARP) {
567                         /* Discard packet if ARP is disabled on interface */
568                         m_freem(m);
569                         return;
570                 }
571                 m_adj(m, ARC_HDRNEWLEN);
572                 isr = NETISR_ARP;
573 #ifdef ARCNET_ALLOW_BROKEN_ARP
574                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
575 #endif
576                 break;
577
578         case ARCTYPE_ARP_OLD:
579                 if (ifp->if_flags & IFF_NOARP) {
580                         /* Discard packet if ARP is disabled on interface */
581                         m_freem(m);
582                         return;
583                 }
584                 m_adj(m, ARC_HDRLEN);
585                 isr = NETISR_ARP;
586 #ifdef ARCNET_ALLOW_BROKEN_ARP
587                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
588 #endif
589                 break;
590 #endif
591 #ifdef INET6
592         case ARCTYPE_INET6:
593                 m_adj(m, ARC_HDRNEWLEN);
594                 isr = NETISR_IPV6;
595                 break;
596 #endif
597         default:
598                 m_freem(m);
599                 return;
600         }
601         M_SETFIB(m, ifp->if_fib);
602         netisr_dispatch(isr, m);
603 }
604
605 /*
606  * Register (new) link level address.
607  */
608 void
609 arc_storelladdr(struct ifnet *ifp, 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(struct ifnet *ifp, u_int8_t lla)
619 {
620         struct ifaddr *ifa;
621         struct sockaddr_dl *sdl;
622         struct arccom *ac;
623
624         if_attach(ifp);
625         ifp->if_addrlen = 1;
626         ifp->if_hdrlen = ARC_HDRLEN;
627         ifp->if_mtu = 1500;
628         ifp->if_resolvemulti = arc_resolvemulti;
629         if (ifp->if_baudrate == 0)
630                 ifp->if_baudrate = 2500000;
631         ifa = ifp->if_addr;
632         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
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->if_l2com;
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         ifp->if_broadcastaddr = &arcbroadcastaddr;
650
651         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
652 }
653
654 void
655 arc_ifdetach(struct ifnet *ifp)
656 {
657         bpfdetach(ifp);
658         if_detach(ifp);
659 }
660
661 int
662 arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
663 {
664         struct ifaddr *ifa = (struct ifaddr *) data;
665         struct ifreq *ifr = (struct ifreq *) data;
666         int error = 0;
667
668         switch (command) {
669         case SIOCSIFADDR:
670                 ifp->if_flags |= IFF_UP;
671                 switch (ifa->ifa_addr->sa_family) {
672 #ifdef INET
673                 case AF_INET:
674                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
675                         arp_ifinit(ifp, ifa);
676                         break;
677 #endif
678                 default:
679                         ifp->if_init(ifp->if_softc);
680                         break;
681                 }
682                 break;
683
684         case SIOCGIFADDR:
685                 {
686                         struct sockaddr *sa;
687
688                         sa = (struct sockaddr *) &ifr->ifr_data;
689                         *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp);
690                 }
691                 break;
692
693         case SIOCADDMULTI:
694         case SIOCDELMULTI:
695                 if (ifr == NULL)
696                         error = EAFNOSUPPORT;
697                 else {
698                         switch (ifr->ifr_addr.sa_family) {
699                         case AF_INET:
700                         case AF_INET6:
701                                 error = 0;
702                                 break;
703                         default:
704                                 error = EAFNOSUPPORT;
705                                 break;
706                         }
707                 }
708                 break;
709
710         case SIOCSIFMTU:
711                 /*
712                  * Set the interface MTU.
713                  * mtu can't be larger than ARCMTU for RFC1051
714                  * and can't be larger than ARC_PHDS_MTU
715                  */
716                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
717                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
718                         error = EINVAL;
719                 else
720                         ifp->if_mtu = ifr->ifr_mtu;
721                 break;
722         }
723
724         return (error);
725 }
726
727 /* based on ether_resolvemulti() */
728 int
729 arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
730     struct sockaddr *sa)
731 {
732         struct sockaddr_dl *sdl;
733 #ifdef INET
734         struct sockaddr_in *sin;
735 #endif
736 #ifdef INET6
737         struct sockaddr_in6 *sin6;
738 #endif
739
740         switch(sa->sa_family) {
741         case AF_LINK:
742                 /*
743                 * No mapping needed. Just check that it's a valid MC address.
744                 */
745                 sdl = (struct sockaddr_dl *)sa;
746                 if (*LLADDR(sdl) != arcbroadcastaddr)
747                         return EADDRNOTAVAIL;
748                 *llsa = 0;
749                 return 0;
750 #ifdef INET
751         case AF_INET:
752                 sin = (struct sockaddr_in *)sa;
753                 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
754                         return EADDRNOTAVAIL;
755                 sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
756                 sdl->sdl_alen = ARC_ADDR_LEN;
757                 *LLADDR(sdl) = 0;
758                 *llsa = (struct sockaddr *)sdl;
759                 return 0;
760 #endif
761 #ifdef INET6
762         case AF_INET6:
763                 sin6 = (struct sockaddr_in6 *)sa;
764                 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
765                         /*
766                          * An IP6 address of 0 means listen to all
767                          * of the Ethernet multicast address used for IP6.
768                          * (This is used for multicast routers.)
769                          */
770                         ifp->if_flags |= IFF_ALLMULTI;
771                         *llsa = 0;
772                         return 0;
773                 }
774                 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
775                         return EADDRNOTAVAIL;
776                 sdl = link_init_sdl(ifp, *llsa, IFT_ETHER);
777                 sdl->sdl_alen = ARC_ADDR_LEN;
778                 *LLADDR(sdl) = 0;
779                 *llsa = (struct sockaddr *)sdl;
780                 return 0;
781 #endif
782
783         default:
784                 /*
785                  * Well, the text isn't quite right, but it's the name
786                  * that counts...
787                  */
788                 return EAFNOSUPPORT;
789         }
790 }
791
792 static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals");
793
794 static void*
795 arc_alloc(u_char type, struct ifnet *ifp)
796 {
797         struct arccom   *ac;
798         
799         ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO);
800         ac->ac_ifp = ifp;
801
802         return (ac);
803 }
804
805 static void
806 arc_free(void *com, u_char type)
807 {
808
809         free(com, M_ARCCOM);
810 }
811
812 static int
813 arc_modevent(module_t mod, int type, void *data)
814 {
815
816         switch (type) {
817         case MOD_LOAD:
818                 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free);
819                 break;
820         case MOD_UNLOAD:
821                 if_deregister_com_alloc(IFT_ARCNET);
822                 break;
823         default:
824                 return EOPNOTSUPP;
825         }
826
827         return (0);
828 }
829
830 static moduledata_t arc_mod = {
831         "arcnet",
832         arc_modevent,
833         0
834 };
835
836 DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY);
837 MODULE_VERSION(arcnet, 1);