]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/net/if_arcsubr.c
This commit was generated by cvs2svn to compensate for changes in r91116,
[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/malloc.h>
48 #include <sys/mbuf.h>
49 #include <sys/protosw.h>
50 #include <sys/socket.h>
51 #include <sys/sockio.h>
52 #include <sys/errno.h>
53 #include <sys/syslog.h>
54
55 #include <machine/cpu.h>
56
57 #include <net/if.h>
58 #include <net/netisr.h>
59 #include <net/route.h>
60 #include <net/if_dl.h>
61 #include <net/if_types.h>
62 #include <net/if_arc.h>
63 #include <net/if_arp.h>
64 #include <net/bpf.h>
65
66 #if defined(INET) || defined(INET6)
67 #include <netinet/in.h>
68 #include <netinet/in_var.h>
69 #include <netinet/if_ether.h>
70 #endif
71
72 #ifdef INET6
73 #include <netinet6/nd6.h>
74 #endif
75
76 MODULE_VERSION(arcnet, 1);
77
78 #define ARCNET_ALLOW_BROKEN_ARP
79
80 static struct mbuf *arc_defrag __P((struct ifnet *, struct mbuf *));
81
82 u_int8_t  arcbroadcastaddr = 0;
83
84 #define senderr(e) { error = (e); goto bad;}
85 #define SIN(s) ((struct sockaddr_in *)s)
86
87 /*
88  * ARCnet output routine.
89  * Encapsulate a packet of type family for the local net.
90  * Assumes that ifp is actually pointer to arccom structure.
91  */
92 int
93 arc_output(ifp, m, dst, rt0)
94         struct ifnet *ifp;
95         struct mbuf *m;
96         struct sockaddr *dst;
97         struct rtentry *rt0;
98 {
99         struct mbuf             *mcopy;
100         struct rtentry          *rt;
101         struct arccom           *ac;
102         struct arc_header       *ah;
103         struct arphdr           *arph;
104         int                     error;
105         u_int8_t                atype, adst;
106 #if __FreeBSD_version < 500000
107         int                     s;
108 #endif
109
110         if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
111                 return(ENETDOWN); /* m, m1 aren't initialized yet */
112
113         error = 0;
114         ac = (struct arccom *)ifp;
115         mcopy = NULL;
116
117         if ((rt = rt0)) {
118                 if ((rt->rt_flags & RTF_UP) == 0) {
119                         if ((rt0 = rt = rtalloc1(dst, 1, 0UL)))
120                                 rt->rt_refcnt--;
121                         else
122                                 senderr(EHOSTUNREACH);
123                 }
124                 if (rt->rt_flags & RTF_GATEWAY) {
125                         if (rt->rt_gwroute == 0)
126                                 goto lookup;
127                         if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
128                                 rtfree(rt); rt = rt0;
129                         lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL);
130                                 if ((rt = rt->rt_gwroute) == 0)
131                                         senderr(EHOSTUNREACH);
132                         }
133                 }
134                 if (rt->rt_flags & RTF_REJECT)
135                         if (rt->rt_rmx.rmx_expire == 0 ||
136                             time_second < rt->rt_rmx.rmx_expire)
137                                 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
138         }
139
140         switch (dst->sa_family) {
141 #ifdef INET
142         case AF_INET:
143
144                 /*
145                  * For now, use the simple IP addr -> ARCnet addr mapping
146                  */
147                 if (m->m_flags & (M_BCAST|M_MCAST))
148                         adst = arcbroadcastaddr; /* ARCnet broadcast address */
149                 else if (ifp->if_flags & IFF_NOARP)
150                         adst = ntohl(SIN(dst)->sin_addr.s_addr) & 0xFF;
151                 else if (!arpresolve(ifp, rt, m, dst, &adst, rt0))
152                         return 0;       /* not resolved yet */
153
154                 /* If broadcasting on a simplex interface, loopback a copy */
155                 if ((m->m_flags & (M_BCAST|M_MCAST)) &&
156                     (ifp->if_flags & IFF_SIMPLEX))
157                         mcopy = m_copy(m, 0, (int)M_COPYALL);
158                 atype = (ifp->if_flags & IFF_LINK0) ?
159                         ARCTYPE_IP_OLD : ARCTYPE_IP;
160                 break;
161 #endif
162 #ifdef INET6
163         case AF_INET6:
164 #ifdef OLDIP6OUTPUT
165                 if (!nd6_resolve(ifp, rt, m, dst, (u_char *)&adst))
166                         return(0);      /* if not yet resolves */
167 #else
168                 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&adst))
169                         return(0); /* it must be impossible, but... */
170 #endif /* OLDIP6OUTPUT */
171                 atype = ARCTYPE_INET6;
172                 break;
173 #endif
174
175         case AF_UNSPEC:
176                 ah = (struct arc_header *)dst->sa_data;
177                 adst = ah->arc_dhost;
178                 atype = ah->arc_type;
179
180                 if (atype == ARCTYPE_ARP) {
181                         atype = (ifp->if_flags & IFF_LINK0) ?
182                             ARCTYPE_ARP_OLD: ARCTYPE_ARP;
183
184 #ifdef ARCNET_ALLOW_BROKEN_ARP
185                         /*
186                          * XXX It's not clear per RFC826 if this is needed, but
187                          * "assigned numbers" say this is wrong.
188                          * However, e.g., AmiTCP 3.0Beta used it... we make this
189                          * switchable for emergency cases. Not perfect, but...
190                          */
191                         arph = mtod(m, struct arphdr *);
192                         if (ifp->if_flags & IFF_LINK2)
193                                 arph->ar_pro = atype - 1;
194 #endif
195                 }
196                 break;
197
198         default:
199                 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
200                     dst->sa_family);
201                 senderr(EAFNOSUPPORT);
202         }
203
204         if (mcopy)
205                 (void) if_simloop(ifp, mcopy, dst->sa_family, 0);
206
207         M_PREPEND(m, ARC_HDRLEN, M_DONTWAIT);
208         if (m == 0)
209                 senderr(ENOBUFS);
210         ah = mtod(m, struct arc_header *);
211         ah->arc_type = atype;
212         ah->arc_dhost = adst;
213         ah->arc_shost = *IF_LLADDR(ifp);
214
215         if (ifp->if_bpf)
216                 bpf_mtap(ifp, m);
217
218 #if __FreeBSD_version < 500000
219         s = splimp();
220
221         /*
222          * Queue message on interface, and start output if interface
223          * not yet active.
224          */
225         if (IF_QFULL(&ifp->if_snd)) {
226                 IF_DROP(&ifp->if_snd);
227                 splx(s);
228                 senderr(ENOBUFS);
229         }
230         ifp->if_obytes += m->m_pkthdr.len;
231         IF_ENQUEUE(&ifp->if_snd, m);
232         if ((ifp->if_flags & IFF_OACTIVE) == 0)
233                 (*ifp->if_start)(ifp);
234         splx(s);
235 #else
236         if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
237                 m = 0;
238                 senderr(ENOBUFS);
239         }
240 #endif
241
242         return (error);
243
244 bad:
245         if (m)
246                 m_freem(m);
247         return (error);
248 }
249
250 void
251 arc_frag_init(ifp)
252         struct ifnet *ifp;
253 {
254         struct arccom *ac;
255
256         ac = (struct arccom *)ifp;
257         ac->curr_frag = 0;
258 }
259
260 struct mbuf *
261 arc_frag_next(ifp)
262         struct ifnet *ifp;
263 {
264         struct arccom *ac;
265         struct mbuf *m;
266         struct arc_header *ah;
267
268         ac = (struct arccom *)ifp;
269         if ((m = ac->curr_frag) == 0) {
270                 int tfrags;
271
272                 /* dequeue new packet */
273                 IF_DEQUEUE(&ifp->if_snd, m);
274                 if (m == 0)
275                         return 0;
276
277                 ah = mtod(m, struct arc_header *);
278                 if (!arc_isphds(ah->arc_type))
279                         return m;
280
281                 ++ac->ac_seqid;         /* make the seqid unique */
282                 tfrags = (m->m_pkthdr.len + 503) / 504;
283                 ac->fsflag = 2 * tfrags - 3;
284                 ac->sflag = 0;
285                 ac->rsflag = ac->fsflag;
286                 ac->arc_dhost = ah->arc_dhost;
287                 ac->arc_shost = ah->arc_shost;
288                 ac->arc_type = ah->arc_type;
289
290                 m_adj(m, ARC_HDRLEN);
291                 ac->curr_frag = m;
292         }
293
294         /* split out next fragment and return it */
295         if (ac->sflag < ac->fsflag) {
296                 /* we CAN'T have short packets here */
297                 ac->curr_frag = m_split(m, 504, M_DONTWAIT);
298                 if (ac->curr_frag == 0) {
299                         m_free(m);
300                         return 0;
301                 }
302
303                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
304                 if (m == 0) {
305                         m_free(ac->curr_frag);
306                         ac->curr_frag = 0;
307
308                         m_free(m);
309                         return 0;
310                 }
311
312                 ah = mtod(m, struct arc_header *);
313                 ah->arc_flag = ac->rsflag;
314                 ah->arc_seqid = ac->ac_seqid;
315
316                 ac->sflag += 2;
317                 ac->rsflag = ac->sflag;
318         } else if ((m->m_pkthdr.len >=
319             ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
320             (m->m_pkthdr.len <=
321             ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
322                 ac->curr_frag = 0;
323
324                 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
325                 if (m == 0)
326                         return 0;
327
328                 ah = mtod(m, struct arc_header *);
329                 ah->arc_flag = 0xFF;
330                 ah->arc_seqid = 0xFFFF;
331                 ah->arc_type2 = ac->arc_type;
332                 ah->arc_flag2 = ac->sflag;
333                 ah->arc_seqid2 = ac->ac_seqid;
334         } else {
335                 ac->curr_frag = 0;
336
337                 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
338                 if (m == 0)
339                         return 0;
340
341                 ah = mtod(m, struct arc_header *);
342                 ah->arc_flag = ac->sflag;
343                 ah->arc_seqid = ac->ac_seqid;
344         }
345
346         ah->arc_dhost = ac->arc_dhost;
347         ah->arc_shost = ac->arc_shost;
348         ah->arc_type = ac->arc_type;
349
350         return m;
351 }
352
353 /*
354  * Defragmenter. Returns mbuf if last packet found, else
355  * NULL. frees imcoming mbuf as necessary.
356  */
357
358 __inline struct mbuf *
359 arc_defrag(ifp, m)
360         struct ifnet *ifp;
361         struct mbuf *m;
362 {
363         struct arc_header *ah, *ah1;
364         struct arccom *ac;
365         struct ac_frag *af;
366         struct mbuf *m1;
367         char *s;
368         int newflen;
369         u_char src,dst,typ;
370
371         ac = (struct arccom *)ifp;
372
373         if (m->m_len < ARC_HDRNEWLEN) {
374                 m = m_pullup(m, ARC_HDRNEWLEN);
375                 if (m == NULL) {
376                         ++ifp->if_ierrors;
377                         return NULL;
378                 }
379         }
380
381         ah = mtod(m, struct arc_header *);
382         typ = ah->arc_type;
383
384         if (!arc_isphds(typ))
385                 return m;
386
387         src = ah->arc_shost;
388         dst = ah->arc_dhost;
389
390         if (ah->arc_flag == 0xff) {
391                 m_adj(m, 4);
392
393                 if (m->m_len < ARC_HDRNEWLEN) {
394                         m = m_pullup(m, ARC_HDRNEWLEN);
395                         if (m == NULL) {
396                                 ++ifp->if_ierrors;
397                                 return NULL;
398                         }
399                 }
400
401                 ah = mtod(m, struct arc_header *);
402         }
403
404         af = &ac->ac_fragtab[src];
405         m1 = af->af_packet;
406         s = "debug code error";
407
408         if (ah->arc_flag & 1) {
409                 /*
410                  * first fragment. We always initialize, which is
411                  * about the right thing to do, as we only want to
412                  * accept one fragmented packet per src at a time.
413                  */
414                 if (m1 != NULL)
415                         m_freem(m1);
416
417                 af->af_packet = m;
418                 m1 = m;
419                 af->af_maxflag = ah->arc_flag;
420                 af->af_lastseen = 0;
421                 af->af_seqid = ah->arc_seqid;
422
423                 return NULL;
424                 /* notreached */
425         } else {
426                 /* check for unfragmented packet */
427                 if (ah->arc_flag == 0)
428                         return m;
429
430                 /* do we have a first packet from that src? */
431                 if (m1 == NULL) {
432                         s = "no first frag";
433                         goto outofseq;
434                 }
435
436                 ah1 = mtod(m1, struct arc_header *);
437
438                 if (ah->arc_seqid != ah1->arc_seqid) {
439                         s = "seqid differs";
440                         goto outofseq;
441                 }
442
443                 if (typ != ah1->arc_type) {
444                         s = "type differs";
445                         goto outofseq;
446                 }
447
448                 if (dst != ah1->arc_dhost) {
449                         s = "dest host differs";
450                         goto outofseq;
451                 }
452
453                 /* typ, seqid and dst are ok here. */
454
455                 if (ah->arc_flag == af->af_lastseen) {
456                         m_freem(m);
457                         return NULL;
458                 }
459
460                 if (ah->arc_flag == af->af_lastseen + 2) {
461                         /* ok, this is next fragment */
462                         af->af_lastseen = ah->arc_flag;
463                         m_adj(m,ARC_HDRNEWLEN);
464
465                         /*
466                          * m_cat might free the first mbuf (with pkthdr)
467                          * in 2nd chain; therefore:
468                          */
469
470                         newflen = m->m_pkthdr.len;
471
472                         m_cat(m1,m);
473
474                         m1->m_pkthdr.len += newflen;
475
476                         /* is it the last one? */
477                         if (af->af_lastseen > af->af_maxflag) {
478                                 af->af_packet = NULL;
479                                 return(m1);
480                         } else
481                                 return NULL;
482                 }
483                 s = "other reason";
484                 /* if all else fails, it is out of sequence, too */
485         }
486 outofseq:
487         if (m1) {
488                 m_freem(m1);
489                 af->af_packet = NULL;
490         }
491
492         if (m)
493                 m_freem(m);
494
495         log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
496             ifp->if_name, ifp->if_unit, s);
497
498         return NULL;
499 }
500
501 /*
502  * return 1 if Packet Header Definition Standard, else 0.
503  * For now: old IP, old ARP aren't obviously. Lacking correct information,
504  * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
505  * (Apple and Novell corporations were involved, among others, in PHDS work).
506  * Easiest is to assume that everybody else uses that, too.
507  */
508 int
509 arc_isphds(type)
510         u_int8_t type;
511 {
512         return (type != ARCTYPE_IP_OLD &&
513                 type != ARCTYPE_ARP_OLD &&
514                 type != ARCTYPE_DIAGNOSE);
515 }
516
517 /*
518  * Process a received Arcnet packet;
519  * the packet is in the mbuf chain m with
520  * the ARCnet header.
521  */
522 void
523 arc_input(ifp, m)
524         struct ifnet *ifp;
525         struct mbuf *m;
526 {
527         struct arc_header *ah;
528         struct ifqueue *inq;
529         u_int8_t atype;
530 #ifdef INET
531         struct arphdr *arph;
532 #endif
533 #if __FreeBSD_version < 500000
534         int s;
535 #endif
536
537         if ((ifp->if_flags & IFF_UP) == 0) {
538                 m_freem(m);
539                 return;
540         }
541
542         /* possibly defragment: */
543         m = arc_defrag(ifp, m);
544         if (m == NULL)
545                 return;
546
547         if (ifp->if_bpf)
548                 bpf_mtap(ifp, m);
549
550         ah = mtod(m, struct arc_header *);
551
552         ifp->if_ibytes += m->m_pkthdr.len;
553
554         if (arcbroadcastaddr == ah->arc_dhost) {
555                 m->m_flags |= M_BCAST|M_MCAST;
556                 ifp->if_imcasts++;
557         }
558
559         atype = ah->arc_type;
560         switch (atype) {
561 #ifdef INET
562         case ARCTYPE_IP:
563                 m_adj(m, ARC_HDRNEWLEN);
564                 schednetisr(NETISR_IP);
565                 inq = &ipintrq;
566                 break;
567
568         case ARCTYPE_IP_OLD:
569                 m_adj(m, ARC_HDRLEN);
570                 schednetisr(NETISR_IP);
571                 inq = &ipintrq;
572                 break;
573
574         case ARCTYPE_ARP:
575                 if (ifp->if_flags & IFF_NOARP) {
576                         /* Discard packet if ARP is disabled on interface */
577                         m_freem(m);
578                         return;
579                 }
580                 m_adj(m, ARC_HDRNEWLEN);
581                 schednetisr(NETISR_ARP);
582                 inq = &arpintrq;
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                 schednetisr(NETISR_ARP);
596                 inq = &arpintrq;
597                 arph = mtod(m, struct arphdr *);
598 #ifdef ARCNET_ALLOW_BROKEN_ARP
599                 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
600 #endif
601                 break;
602 #endif
603 #ifdef INET6
604         case ARCTYPE_INET6:
605                 m_adj(m, ARC_HDRNEWLEN);
606                 schednetisr(NETISR_IPV6);
607                 inq = &ip6intrq;
608                 break;
609 #endif
610         default:
611                 m_freem(m);
612                 return;
613         }
614
615 #if __FreeBSD_version < 500000
616         s = splimp();
617         if (IF_QFULL(inq)) {
618                 IF_DROP(inq);
619                 m_freem(m);
620         } else
621                 IF_ENQUEUE(inq, m);
622         splx(s);
623 #else
624         IF_HANDOFF(inq, m, NULL);
625 #endif
626 }
627
628 /*
629  * Convert Arcnet address to printable (loggable) representation.
630  */
631 static char digits[] = "0123456789abcdef";
632 char *
633 arc_sprintf(ap)
634         u_int8_t *ap;
635 {
636         static char arcbuf[3];
637         char *cp = arcbuf;
638
639         *cp++ = digits[*ap >> 4];
640         *cp++ = digits[*ap++ & 0xf];
641         *cp   = 0;
642         return (arcbuf);
643 }
644
645 /*
646  * Register (new) link level address.
647  */
648 void
649 arc_storelladdr(ifp, lla)
650         struct ifnet *ifp;
651         u_int8_t lla;
652 {
653         *IF_LLADDR(ifp) = lla;
654 }
655
656 /*
657  * Perform common duties while attaching to interface list
658  */
659 void
660 arc_ifattach(ifp, lla)
661         struct ifnet *ifp;
662         u_int8_t lla;
663 {
664         struct ifaddr *ifa;
665         struct sockaddr_dl *sdl;
666         struct arccom *ac;
667
668         if_attach(ifp);
669         ifp->if_type = IFT_ARCNET;
670         ifp->if_addrlen = 1;
671         ifp->if_hdrlen = ARC_HDRLEN;
672         ifp->if_mtu = 1500;
673         if (ifp->if_baudrate == 0)
674                 ifp->if_baudrate = 2500000;
675 #if __FreeBSD_version < 500000
676         ifa = ifnet_addrs[ifp->if_index - 1];
677 #else
678         ifa = ifaddr_byindex(ifp->if_index);
679 #endif
680         KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
681         sdl = (struct sockaddr_dl *)ifa->ifa_addr;
682         sdl->sdl_type = IFT_ARCNET;
683         sdl->sdl_alen = ifp->if_addrlen;
684
685         if (ifp->if_flags & IFF_BROADCAST)
686                 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
687
688         ac = (struct arccom *)ifp;
689         ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
690         if (lla == 0) {
691                 /* XXX this message isn't entirely clear, to me -- cgd */
692                 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts.  Please change it and ifconfig %s%d down up\n",
693                    ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
694         }
695         arc_storelladdr(ifp, lla);
696
697         ifp->if_broadcastaddr = &arcbroadcastaddr;
698
699         bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
700 }
701
702 void
703 arc_ifdetach(ifp)
704         struct ifnet *ifp;
705 {
706         bpfdetach(ifp);
707         if_detach(ifp);
708 }
709
710 int
711 arc_ioctl(ifp, command, data)
712         struct ifnet *ifp;
713         int command;
714         caddr_t data;
715 {
716         struct ifaddr *ifa = (struct ifaddr *) data;
717         struct ifreq *ifr = (struct ifreq *) data;
718         int error = 0;
719
720         switch (command) {
721         case SIOCSIFADDR:
722                 ifp->if_flags |= IFF_UP;
723                 switch (ifa->ifa_addr->sa_family) {
724 #ifdef INET
725                 case AF_INET:
726                         ifp->if_init(ifp->if_softc);    /* before arpwhohas */
727                         arp_ifinit(ifp, ifa);
728                         break;
729 #endif
730                 default:
731                         ifp->if_init(ifp->if_softc);
732                         break;
733                 }
734                 break;
735
736         case SIOCADDMULTI:
737         case SIOCDELMULTI:
738                 if (ifr == NULL)
739                         error = EAFNOSUPPORT;
740                 else {
741                         switch (ifr->ifr_addr.sa_family) {
742                         case AF_INET:
743                         case AF_INET6:
744                                 error = 0;
745                                 break;
746                         default:
747                                 error = EAFNOSUPPORT;
748                                 break;
749                         }
750                 }
751                 break;
752
753         case SIOCSIFMTU:
754                 /*
755                  * Set the interface MTU.
756                  * mtu can't be larger than ARCMTU for RFC1051
757                  * and can't be larger than ARC_PHDS_MTU
758                  */
759                 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
760                     ifr->ifr_mtu > ARC_PHDS_MAXMTU)
761                         error = EINVAL;
762                 else
763                         ifp->if_mtu = ifr->ifr_mtu;
764                 break;
765
766 #if 0
767         case SIOCGIFADDR:
768                 {
769                         struct sockaddr *sa;
770
771                         sa = (struct sockaddr *) & ifr->ifr_data;
772                         bcopy(IFP2AC(ifp)->ac_enaddr,
773                               (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
774                 }
775                 break;
776 #endif
777         }
778
779         return (error);
780 }