if_arcsubr.c revision 105228
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 105228 2002-10-16 10:45:53Z phk $ */ 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 356static __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} 779