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