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