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