Deleted Added
full compact
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */
2/* $FreeBSD: head/sys/net/if_arcsubr.c 94660 2002-04-14 16:40:11Z fjoe $ */
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
76MODULE_VERSION(arcnet, 1);
77
78#define ARCNET_ALLOW_BROKEN_ARP
79
80static struct mbuf *arc_defrag(struct ifnet *, struct mbuf *);
81
82u_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 */
92int
93arc_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
244bad:
245 if (m)
246 m_freem(m);
247 return (error);
248}
249
250void
251arc_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
260struct mbuf *
261arc_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_freem(m);
300 return 0;
301 }
302
303 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
304 if (m == 0) {
305 m_freem(ac->curr_frag);
306 ac->curr_frag = 0;
307 return 0;
308 }
309
310 ah = mtod(m, struct arc_header *);
311 ah->arc_flag = ac->rsflag;
312 ah->arc_seqid = ac->ac_seqid;
313
314 ac->sflag += 2;
315 ac->rsflag = ac->sflag;
316 } else if ((m->m_pkthdr.len >=
317 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) &&
318 (m->m_pkthdr.len <=
319 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) {
320 ac->curr_frag = 0;
321
322 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_DONTWAIT);
323 if (m == 0)
324 return 0;
325
326 ah = mtod(m, struct arc_header *);
327 ah->arc_flag = 0xFF;
328 ah->arc_seqid = 0xFFFF;
329 ah->arc_type2 = ac->arc_type;
330 ah->arc_flag2 = ac->sflag;
331 ah->arc_seqid2 = ac->ac_seqid;
332 } else {
333 ac->curr_frag = 0;
334
335 M_PREPEND(m, ARC_HDRNEWLEN, M_DONTWAIT);
336 if (m == 0)
337 return 0;
338
339 ah = mtod(m, struct arc_header *);
340 ah->arc_flag = ac->sflag;
341 ah->arc_seqid = ac->ac_seqid;
342 }
343
344 ah->arc_dhost = ac->arc_dhost;
345 ah->arc_shost = ac->arc_shost;
346 ah->arc_type = ac->arc_type;
347
348 return m;
349}
350
351/*
352 * Defragmenter. Returns mbuf if last packet found, else
353 * NULL. frees imcoming mbuf as necessary.
354 */
355
356__inline struct mbuf *
357arc_defrag(ifp, m)
358 struct ifnet *ifp;
359 struct mbuf *m;
360{
361 struct arc_header *ah, *ah1;
362 struct arccom *ac;
363 struct ac_frag *af;
364 struct mbuf *m1;
365 char *s;
366 int newflen;
367 u_char src,dst,typ;
368
369 ac = (struct arccom *)ifp;
370
371 if (m->m_len < ARC_HDRNEWLEN) {
372 m = m_pullup(m, ARC_HDRNEWLEN);
373 if (m == NULL) {
374 ++ifp->if_ierrors;
375 return NULL;
376 }
377 }
378
379 ah = mtod(m, struct arc_header *);
380 typ = ah->arc_type;
381
382 if (!arc_isphds(typ))
383 return m;
384
385 src = ah->arc_shost;
386 dst = ah->arc_dhost;
387
388 if (ah->arc_flag == 0xff) {
389 m_adj(m, 4);
390
391 if (m->m_len < ARC_HDRNEWLEN) {
392 m = m_pullup(m, ARC_HDRNEWLEN);
393 if (m == NULL) {
394 ++ifp->if_ierrors;
395 return NULL;
396 }
397 }
398
399 ah = mtod(m, struct arc_header *);
400 }
401
402 af = &ac->ac_fragtab[src];
403 m1 = af->af_packet;
404 s = "debug code error";
405
406 if (ah->arc_flag & 1) {
407 /*
408 * first fragment. We always initialize, which is
409 * about the right thing to do, as we only want to
410 * accept one fragmented packet per src at a time.
411 */
412 if (m1 != NULL)
413 m_freem(m1);
414
415 af->af_packet = m;
416 m1 = m;
417 af->af_maxflag = ah->arc_flag;
418 af->af_lastseen = 0;
419 af->af_seqid = ah->arc_seqid;
420
421 return NULL;
422 /* notreached */
423 } else {
424 /* check for unfragmented packet */
425 if (ah->arc_flag == 0)
426 return m;
427
428 /* do we have a first packet from that src? */
429 if (m1 == NULL) {
430 s = "no first frag";
431 goto outofseq;
432 }
433
434 ah1 = mtod(m1, struct arc_header *);
435
436 if (ah->arc_seqid != ah1->arc_seqid) {
437 s = "seqid differs";
438 goto outofseq;
439 }
440
441 if (typ != ah1->arc_type) {
442 s = "type differs";
443 goto outofseq;
444 }
445
446 if (dst != ah1->arc_dhost) {
447 s = "dest host differs";
448 goto outofseq;
449 }
450
451 /* typ, seqid and dst are ok here. */
452
453 if (ah->arc_flag == af->af_lastseen) {
454 m_freem(m);
455 return NULL;
456 }
457
458 if (ah->arc_flag == af->af_lastseen + 2) {
459 /* ok, this is next fragment */
460 af->af_lastseen = ah->arc_flag;
461 m_adj(m,ARC_HDRNEWLEN);
462
463 /*
464 * m_cat might free the first mbuf (with pkthdr)
465 * in 2nd chain; therefore:
466 */
467
468 newflen = m->m_pkthdr.len;
469
470 m_cat(m1,m);
471
472 m1->m_pkthdr.len += newflen;
473
474 /* is it the last one? */
475 if (af->af_lastseen > af->af_maxflag) {
476 af->af_packet = NULL;
477 return(m1);
478 } else
479 return NULL;
480 }
481 s = "other reason";
482 /* if all else fails, it is out of sequence, too */
483 }
484outofseq:
485 if (m1) {
486 m_freem(m1);
487 af->af_packet = NULL;
488 }
489
490 if (m)
491 m_freem(m);
492
493 log(LOG_INFO,"%s%d: got out of seq. packet: %s\n",
494 ifp->if_name, ifp->if_unit, s);
495
496 return NULL;
497}
498
499/*
500 * return 1 if Packet Header Definition Standard, else 0.
501 * For now: old IP, old ARP aren't obviously. Lacking correct information,
502 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS.
503 * (Apple and Novell corporations were involved, among others, in PHDS work).
504 * Easiest is to assume that everybody else uses that, too.
505 */
506int
507arc_isphds(type)
508 u_int8_t type;
509{
510 return (type != ARCTYPE_IP_OLD &&
511 type != ARCTYPE_ARP_OLD &&
512 type != ARCTYPE_DIAGNOSE);
513}
514
515/*
516 * Process a received Arcnet packet;
517 * the packet is in the mbuf chain m with
518 * the ARCnet header.
519 */
520void
521arc_input(ifp, m)
522 struct ifnet *ifp;
523 struct mbuf *m;
524{
525 struct arc_header *ah;
526 struct ifqueue *inq;
527 u_int8_t atype;
528#ifdef INET
529 struct arphdr *arph;
530#endif
531#if __FreeBSD_version < 500000
532 int s;
533#endif
534
535 if ((ifp->if_flags & IFF_UP) == 0) {
536 m_freem(m);
537 return;
538 }
539
540 /* possibly defragment: */
541 m = arc_defrag(ifp, m);
542 if (m == NULL)
543 return;
544
545 if (ifp->if_bpf)
546 bpf_mtap(ifp, m);
547
548 ah = mtod(m, struct arc_header *);
549
550 ifp->if_ibytes += m->m_pkthdr.len;
551
552 if (arcbroadcastaddr == ah->arc_dhost) {
553 m->m_flags |= M_BCAST|M_MCAST;
554 ifp->if_imcasts++;
555 }
556
557 atype = ah->arc_type;
558 switch (atype) {
559#ifdef INET
560 case ARCTYPE_IP:
561 m_adj(m, ARC_HDRNEWLEN);
562 schednetisr(NETISR_IP);
563 inq = &ipintrq;
564 break;
565
566 case ARCTYPE_IP_OLD:
567 m_adj(m, ARC_HDRLEN);
568 schednetisr(NETISR_IP);
569 inq = &ipintrq;
570 break;
571
572 case ARCTYPE_ARP:
573 if (ifp->if_flags & IFF_NOARP) {
574 /* Discard packet if ARP is disabled on interface */
575 m_freem(m);
576 return;
577 }
578 m_adj(m, ARC_HDRNEWLEN);
579 schednetisr(NETISR_ARP);
580 inq = &arpintrq;
581#ifdef ARCNET_ALLOW_BROKEN_ARP
582 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
583#endif
584 break;
585
586 case ARCTYPE_ARP_OLD:
587 if (ifp->if_flags & IFF_NOARP) {
588 /* Discard packet if ARP is disabled on interface */
589 m_freem(m);
590 return;
591 }
592 m_adj(m, ARC_HDRLEN);
593 schednetisr(NETISR_ARP);
594 inq = &arpintrq;
595 arph = mtod(m, struct arphdr *);
596#ifdef ARCNET_ALLOW_BROKEN_ARP
597 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP);
598#endif
599 break;
600#endif
601#ifdef INET6
602 case ARCTYPE_INET6:
603 m_adj(m, ARC_HDRNEWLEN);
604 schednetisr(NETISR_IPV6);
605 inq = &ip6intrq;
606 break;
607#endif
608 default:
609 m_freem(m);
610 return;
611 }
612
613#if __FreeBSD_version < 500000
614 s = splimp();
615 if (IF_QFULL(inq)) {
616 IF_DROP(inq);
617 m_freem(m);
618 } else
619 IF_ENQUEUE(inq, m);
620 splx(s);
621#else
622 IF_HANDOFF(inq, m, NULL);
623#endif
624}
625
626/*
627 * Convert Arcnet address to printable (loggable) representation.
628 */
629static char digits[] = "0123456789abcdef";
630char *
631arc_sprintf(ap)
632 u_int8_t *ap;
633{
634 static char arcbuf[3];
635 char *cp = arcbuf;
636
637 *cp++ = digits[*ap >> 4];
638 *cp++ = digits[*ap++ & 0xf];
639 *cp = 0;
640 return (arcbuf);
641}
642
643/*
644 * Register (new) link level address.
645 */
646void
647arc_storelladdr(ifp, lla)
648 struct ifnet *ifp;
649 u_int8_t lla;
650{
651 *IF_LLADDR(ifp) = lla;
652}
653
654/*
655 * Perform common duties while attaching to interface list
656 */
657void
658arc_ifattach(ifp, lla)
659 struct ifnet *ifp;
660 u_int8_t lla;
661{
662 struct ifaddr *ifa;
663 struct sockaddr_dl *sdl;
664 struct arccom *ac;
665
666 if_attach(ifp);
667 ifp->if_type = IFT_ARCNET;
668 ifp->if_addrlen = 1;
669 ifp->if_hdrlen = ARC_HDRLEN;
670 ifp->if_mtu = 1500;
671 if (ifp->if_baudrate == 0)
672 ifp->if_baudrate = 2500000;
673#if __FreeBSD_version < 500000
674 ifa = ifnet_addrs[ifp->if_index - 1];
675#else
676 ifa = ifaddr_byindex(ifp->if_index);
677#endif
678 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __FUNCTION__));
679 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
680 sdl->sdl_type = IFT_ARCNET;
681 sdl->sdl_alen = ifp->if_addrlen;
682
683 if (ifp->if_flags & IFF_BROADCAST)
684 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI;
685
686 ac = (struct arccom *)ifp;
687 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */
688 if (lla == 0) {
689 /* XXX this message isn't entirely clear, to me -- cgd */
690 log(LOG_ERR,"%s%d: link address 0 reserved for broadcasts. Please change it and ifconfig %s%d down up\n",
691 ifp->if_name, ifp->if_unit, ifp->if_name, ifp->if_unit);
692 }
693 arc_storelladdr(ifp, lla);
694
695 ifp->if_broadcastaddr = &arcbroadcastaddr;
696
697 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN);
698}
699
700void
701arc_ifdetach(ifp)
702 struct ifnet *ifp;
703{
704 bpfdetach(ifp);
705 if_detach(ifp);
706}
707
708int
709arc_ioctl(ifp, command, data)
710 struct ifnet *ifp;
711 int command;
712 caddr_t data;
713{
714 struct ifaddr *ifa = (struct ifaddr *) data;
715 struct ifreq *ifr = (struct ifreq *) data;
716 int error = 0;
717
718 switch (command) {
719 case SIOCSIFADDR:
720 ifp->if_flags |= IFF_UP;
721 switch (ifa->ifa_addr->sa_family) {
722#ifdef INET
723 case AF_INET:
724 ifp->if_init(ifp->if_softc); /* before arpwhohas */
725 arp_ifinit(ifp, ifa);
726 break;
727#endif
728 default:
729 ifp->if_init(ifp->if_softc);
730 break;
731 }
732 break;
733
734 case SIOCADDMULTI:
735 case SIOCDELMULTI:
736 if (ifr == NULL)
737 error = EAFNOSUPPORT;
738 else {
739 switch (ifr->ifr_addr.sa_family) {
740 case AF_INET:
741 case AF_INET6:
742 error = 0;
743 break;
744 default:
745 error = EAFNOSUPPORT;
746 break;
747 }
748 }
749 break;
750
751 case SIOCSIFMTU:
752 /*
753 * Set the interface MTU.
754 * mtu can't be larger than ARCMTU for RFC1051
755 * and can't be larger than ARC_PHDS_MTU
756 */
757 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) ||
758 ifr->ifr_mtu > ARC_PHDS_MAXMTU)
759 error = EINVAL;
760 else
761 ifp->if_mtu = ifr->ifr_mtu;
762 break;
763
764#if 0
765 case SIOCGIFADDR:
766 {
767 struct sockaddr *sa;
768
769 sa = (struct sockaddr *) & ifr->ifr_data;
770 bcopy(IFP2AC(ifp)->ac_enaddr,
771 (caddr_t) sa->sa_data, ETHER_ADDR_LEN);
772 }
773 break;
774#endif
775 }
776
777 return (error);
778}