if_arcsubr.c revision 89099
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 89099 2002-01-08 20:03:13Z 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 __P((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_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 * 359arc_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 } 486outofseq: 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 */ 508int 509arc_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 */ 522void 523arc_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 */ 631static char digits[] = "0123456789abcdef"; 632char * 633arc_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 */ 648void 649arc_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 */ 659void 660arc_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 702void 703arc_ifdetach(ifp) 704 struct ifnet *ifp; 705{ 706 bpfdetach(ifp); 707 if_detach(ifp); 708} 709 710int 711arc_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} 781