if_arcsubr.c revision 194581
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 194581 2009-06-21 10:29:31Z rdivacky $ */ 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#include <net/if_llatbl.h> 68 69#if defined(INET) || defined(INET6) 70#include <netinet/in.h> 71#include <netinet/in_var.h> 72#include <netinet/if_ether.h> 73#endif 74 75#ifdef INET6 76#include <netinet6/nd6.h> 77#endif 78 79#ifdef IPX 80#include <netipx/ipx.h> 81#include <netipx/ipx_if.h> 82#endif 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(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst, 105 struct route *ro) 106{ 107 struct arc_header *ah; 108 int error; 109 u_int8_t atype, adst; 110 int loop_copy = 0; 111 int isphds; 112#if defined(INET) || defined(INET6) 113 struct llentry *lle; 114#endif 115 116 if (!((ifp->if_flags & IFF_UP) && 117 (ifp->if_drv_flags & IFF_DRV_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, ro ? ro->ro_rt : NULL, 135 m, dst, &adst, &lle); 136 if (error) 137 return (error == EWOULDBLOCK ? 0 : error); 138 } 139 140 atype = (ifp->if_flags & IFF_LINK0) ? 141 ARCTYPE_IP_OLD : ARCTYPE_IP; 142 break; 143 case AF_ARP: 144 { 145 struct arphdr *ah; 146 ah = mtod(m, struct arphdr *); 147 ah->ar_hrd = htons(ARPHRD_ARCNET); 148 149 loop_copy = -1; /* if this is for us, don't do it */ 150 151 switch(ntohs(ah->ar_op)) { 152 case ARPOP_REVREQUEST: 153 case ARPOP_REVREPLY: 154 atype = ARCTYPE_REVARP; 155 break; 156 case ARPOP_REQUEST: 157 case ARPOP_REPLY: 158 default: 159 atype = ARCTYPE_ARP; 160 break; 161 } 162 163 if (m->m_flags & M_BCAST) 164 bcopy(ifp->if_broadcastaddr, &adst, ARC_ADDR_LEN); 165 else 166 bcopy(ar_tha(ah), &adst, ARC_ADDR_LEN); 167 168 } 169 break; 170#endif 171#ifdef INET6 172 case AF_INET6: 173 error = nd6_storelladdr(ifp, m, dst, (u_char *)&adst, &lle); 174 if (error) 175 return (error); 176 atype = ARCTYPE_INET6; 177 break; 178#endif 179#ifdef IPX 180 case AF_IPX: 181 adst = SIPX(dst)->sipx_addr.x_host.c_host[5]; 182 atype = ARCTYPE_IPX; 183 if (adst == 0xff) 184 adst = arcbroadcastaddr; 185 break; 186#endif 187 188 case AF_UNSPEC: 189 loop_copy = -1; 190 ah = (struct arc_header *)dst->sa_data; 191 adst = ah->arc_dhost; 192 atype = ah->arc_type; 193 194 if (atype == ARCTYPE_ARP) { 195 atype = (ifp->if_flags & IFF_LINK0) ? 196 ARCTYPE_ARP_OLD: ARCTYPE_ARP; 197 198#ifdef ARCNET_ALLOW_BROKEN_ARP 199 /* 200 * XXX It's not clear per RFC826 if this is needed, but 201 * "assigned numbers" say this is wrong. 202 * However, e.g., AmiTCP 3.0Beta used it... we make this 203 * switchable for emergency cases. Not perfect, but... 204 */ 205 if (ifp->if_flags & IFF_LINK2) 206 mtod(m, struct arphdr *)->ar_pro = atype - 1; 207#endif 208 } 209 break; 210 211 default: 212 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 213 senderr(EAFNOSUPPORT); 214 } 215 216 isphds = arc_isphds(atype); 217 M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_DONTWAIT); 218 if (m == 0) 219 senderr(ENOBUFS); 220 ah = mtod(m, struct arc_header *); 221 ah->arc_type = atype; 222 ah->arc_dhost = adst; 223 ah->arc_shost = ARC_LLADDR(ifp); 224 if (isphds) { 225 ah->arc_flag = 0; 226 ah->arc_seqid = 0; 227 } 228 229 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 230 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 231 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 232 233 (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); 234 } else if (ah->arc_dhost == ah->arc_shost) { 235 (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); 236 return (0); /* XXX */ 237 } 238 } 239 240 BPF_MTAP(ifp, m); 241 242 error = ifp->if_transmit(ifp, m); 243 244 return (error); 245 246bad: 247 if (m) 248 m_freem(m); 249 return (error); 250} 251 252void 253arc_frag_init(struct ifnet *ifp) 254{ 255 struct arccom *ac; 256 257 ac = (struct arccom *)ifp->if_l2com; 258 ac->curr_frag = 0; 259} 260 261struct mbuf * 262arc_frag_next(struct ifnet *ifp) 263{ 264 struct arccom *ac; 265 struct mbuf *m; 266 struct arc_header *ah; 267 268 ac = (struct arccom *)ifp->if_l2com; 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 + ARC_MAX_DATA - 1) / ARC_MAX_DATA; 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_HDRNEWLEN); 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, ARC_MAX_DATA, 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(struct ifnet *ifp, struct mbuf *m) 358{ 359 struct arc_header *ah, *ah1; 360 struct arccom *ac; 361 struct ac_frag *af; 362 struct mbuf *m1; 363 char *s; 364 int newflen; 365 u_char src,dst,typ; 366 367 ac = (struct arccom *)ifp->if_l2com; 368 369 if (m->m_len < ARC_HDRNEWLEN) { 370 m = m_pullup(m, ARC_HDRNEWLEN); 371 if (m == NULL) { 372 ++ifp->if_ierrors; 373 return NULL; 374 } 375 } 376 377 ah = mtod(m, struct arc_header *); 378 typ = ah->arc_type; 379 380 if (!arc_isphds(typ)) 381 return m; 382 383 src = ah->arc_shost; 384 dst = ah->arc_dhost; 385 386 if (ah->arc_flag == 0xff) { 387 m_adj(m, 4); 388 389 if (m->m_len < ARC_HDRNEWLEN) { 390 m = m_pullup(m, ARC_HDRNEWLEN); 391 if (m == NULL) { 392 ++ifp->if_ierrors; 393 return NULL; 394 } 395 } 396 397 ah = mtod(m, struct arc_header *); 398 } 399 400 af = &ac->ac_fragtab[src]; 401 m1 = af->af_packet; 402 s = "debug code error"; 403 404 if (ah->arc_flag & 1) { 405 /* 406 * first fragment. We always initialize, which is 407 * about the right thing to do, as we only want to 408 * accept one fragmented packet per src at a time. 409 */ 410 if (m1 != NULL) 411 m_freem(m1); 412 413 af->af_packet = m; 414 m1 = m; 415 af->af_maxflag = ah->arc_flag; 416 af->af_lastseen = 0; 417 af->af_seqid = ah->arc_seqid; 418 419 return NULL; 420 /* notreached */ 421 } else { 422 /* check for unfragmented packet */ 423 if (ah->arc_flag == 0) 424 return m; 425 426 /* do we have a first packet from that src? */ 427 if (m1 == NULL) { 428 s = "no first frag"; 429 goto outofseq; 430 } 431 432 ah1 = mtod(m1, struct arc_header *); 433 434 if (ah->arc_seqid != ah1->arc_seqid) { 435 s = "seqid differs"; 436 goto outofseq; 437 } 438 439 if (typ != ah1->arc_type) { 440 s = "type differs"; 441 goto outofseq; 442 } 443 444 if (dst != ah1->arc_dhost) { 445 s = "dest host differs"; 446 goto outofseq; 447 } 448 449 /* typ, seqid and dst are ok here. */ 450 451 if (ah->arc_flag == af->af_lastseen) { 452 m_freem(m); 453 return NULL; 454 } 455 456 if (ah->arc_flag == af->af_lastseen + 2) { 457 /* ok, this is next fragment */ 458 af->af_lastseen = ah->arc_flag; 459 m_adj(m,ARC_HDRNEWLEN); 460 461 /* 462 * m_cat might free the first mbuf (with pkthdr) 463 * in 2nd chain; therefore: 464 */ 465 466 newflen = m->m_pkthdr.len; 467 468 m_cat(m1,m); 469 470 m1->m_pkthdr.len += newflen; 471 472 /* is it the last one? */ 473 if (af->af_lastseen > af->af_maxflag) { 474 af->af_packet = NULL; 475 return(m1); 476 } else 477 return NULL; 478 } 479 s = "other reason"; 480 /* if all else fails, it is out of sequence, too */ 481 } 482outofseq: 483 if (m1) { 484 m_freem(m1); 485 af->af_packet = NULL; 486 } 487 488 if (m) 489 m_freem(m); 490 491 log(LOG_INFO,"%s: got out of seq. packet: %s\n", 492 ifp->if_xname, s); 493 494 return NULL; 495} 496 497/* 498 * return 1 if Packet Header Definition Standard, else 0. 499 * For now: old IP, old ARP aren't obviously. Lacking correct information, 500 * we guess that besides new IP and new ARP also IPX and APPLETALK are PHDS. 501 * (Apple and Novell corporations were involved, among others, in PHDS work). 502 * Easiest is to assume that everybody else uses that, too. 503 */ 504int 505arc_isphds(u_int8_t type) 506{ 507 return (type != ARCTYPE_IP_OLD && 508 type != ARCTYPE_ARP_OLD && 509 type != ARCTYPE_DIAGNOSE); 510} 511 512/* 513 * Process a received Arcnet packet; 514 * the packet is in the mbuf chain m with 515 * the ARCnet header. 516 */ 517void 518arc_input(struct ifnet *ifp, struct mbuf *m) 519{ 520 struct arc_header *ah; 521 int isr; 522 u_int8_t atype; 523 524 if ((ifp->if_flags & IFF_UP) == 0) { 525 m_freem(m); 526 return; 527 } 528 529 /* possibly defragment: */ 530 m = arc_defrag(ifp, m); 531 if (m == NULL) 532 return; 533 534 BPF_MTAP(ifp, m); 535 536 ah = mtod(m, struct arc_header *); 537 /* does this belong to us? */ 538 if ((ifp->if_flags & IFF_PROMISC) == 0 539 && ah->arc_dhost != arcbroadcastaddr 540 && ah->arc_dhost != ARC_LLADDR(ifp)) { 541 m_freem(m); 542 return; 543 } 544 545 ifp->if_ibytes += m->m_pkthdr.len; 546 547 if (ah->arc_dhost == arcbroadcastaddr) { 548 m->m_flags |= M_BCAST|M_MCAST; 549 ifp->if_imcasts++; 550 } 551 552 atype = ah->arc_type; 553 switch (atype) { 554#ifdef INET 555 case ARCTYPE_IP: 556 m_adj(m, ARC_HDRNEWLEN); 557 if ((m = ip_fastforward(m)) == NULL) 558 return; 559 isr = NETISR_IP; 560 break; 561 562 case ARCTYPE_IP_OLD: 563 m_adj(m, ARC_HDRLEN); 564 if ((m = ip_fastforward(m)) == NULL) 565 return; 566 isr = NETISR_IP; 567 break; 568 569 case ARCTYPE_ARP: 570 if (ifp->if_flags & IFF_NOARP) { 571 /* Discard packet if ARP is disabled on interface */ 572 m_freem(m); 573 return; 574 } 575 m_adj(m, ARC_HDRNEWLEN); 576 isr = NETISR_ARP; 577#ifdef ARCNET_ALLOW_BROKEN_ARP 578 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 579#endif 580 break; 581 582 case ARCTYPE_ARP_OLD: 583 if (ifp->if_flags & IFF_NOARP) { 584 /* Discard packet if ARP is disabled on interface */ 585 m_freem(m); 586 return; 587 } 588 m_adj(m, ARC_HDRLEN); 589 isr = NETISR_ARP; 590#ifdef ARCNET_ALLOW_BROKEN_ARP 591 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 592#endif 593 break; 594#endif 595#ifdef INET6 596 case ARCTYPE_INET6: 597 m_adj(m, ARC_HDRNEWLEN); 598 isr = NETISR_IPV6; 599 break; 600#endif 601#ifdef IPX 602 case ARCTYPE_IPX: 603 m_adj(m, ARC_HDRNEWLEN); 604 isr = NETISR_IPX; 605 break; 606#endif 607 default: 608 m_freem(m); 609 return; 610 } 611 netisr_dispatch(isr, m); 612} 613 614/* 615 * Register (new) link level address. 616 */ 617void 618arc_storelladdr(struct ifnet *ifp, u_int8_t lla) 619{ 620 ARC_LLADDR(ifp) = lla; 621} 622 623/* 624 * Perform common duties while attaching to interface list 625 */ 626void 627arc_ifattach(struct ifnet *ifp, 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_addrlen = 1; 635 ifp->if_hdrlen = ARC_HDRLEN; 636 ifp->if_mtu = 1500; 637 ifp->if_resolvemulti = arc_resolvemulti; 638 if (ifp->if_baudrate == 0) 639 ifp->if_baudrate = 2500000; 640#if __FreeBSD_version < 500000 641 ifa = ifnet_addrs[ifp->if_index - 1]; 642#else 643 ifa = ifp->if_addr; 644#endif 645 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 646 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 647 sdl->sdl_type = IFT_ARCNET; 648 sdl->sdl_alen = ifp->if_addrlen; 649 650 if (ifp->if_flags & IFF_BROADCAST) 651 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 652 653 ac = (struct arccom *)ifp->if_l2com; 654 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 655 if (lla == 0) { 656 /* XXX this message isn't entirely clear, to me -- cgd */ 657 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", 658 ifp->if_xname, ifp->if_xname); 659 } 660 arc_storelladdr(ifp, lla); 661 662 ifp->if_broadcastaddr = &arcbroadcastaddr; 663 664 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 665} 666 667void 668arc_ifdetach(struct ifnet *ifp) 669{ 670 bpfdetach(ifp); 671 if_detach(ifp); 672} 673 674int 675arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 676{ 677 struct ifaddr *ifa = (struct ifaddr *) data; 678 struct ifreq *ifr = (struct ifreq *) data; 679 int error = 0; 680 681 switch (command) { 682 case SIOCSIFADDR: 683 ifp->if_flags |= IFF_UP; 684 switch (ifa->ifa_addr->sa_family) { 685#ifdef INET 686 case AF_INET: 687 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 688 arp_ifinit(ifp, ifa); 689 break; 690#endif 691#ifdef IPX 692 /* 693 * XXX This code is probably wrong 694 */ 695 case AF_IPX: 696 { 697 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 698 699 if (ipx_nullhost(*ina)) 700 ina->x_host.c_host[5] = ARC_LLADDR(ifp); 701 else 702 arc_storelladdr(ifp, ina->x_host.c_host[5]); 703 704 /* 705 * Set new address 706 */ 707 ifp->if_init(ifp->if_softc); 708 break; 709 } 710#endif 711 default: 712 ifp->if_init(ifp->if_softc); 713 break; 714 } 715 break; 716 717 case SIOCGIFADDR: 718 { 719 struct sockaddr *sa; 720 721 sa = (struct sockaddr *) &ifr->ifr_data; 722 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 723 } 724 break; 725 726 case SIOCADDMULTI: 727 case SIOCDELMULTI: 728 if (ifr == NULL) 729 error = EAFNOSUPPORT; 730 else { 731 switch (ifr->ifr_addr.sa_family) { 732 case AF_INET: 733 case AF_INET6: 734 error = 0; 735 break; 736 default: 737 error = EAFNOSUPPORT; 738 break; 739 } 740 } 741 break; 742 743 case SIOCSIFMTU: 744 /* 745 * Set the interface MTU. 746 * mtu can't be larger than ARCMTU for RFC1051 747 * and can't be larger than ARC_PHDS_MTU 748 */ 749 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 750 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 751 error = EINVAL; 752 else 753 ifp->if_mtu = ifr->ifr_mtu; 754 break; 755 } 756 757 return (error); 758} 759 760/* based on ether_resolvemulti() */ 761int 762arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 763 struct sockaddr *sa) 764{ 765 struct sockaddr_dl *sdl; 766#ifdef INET 767 struct sockaddr_in *sin; 768#endif 769#ifdef INET6 770 struct sockaddr_in6 *sin6; 771#endif 772 773 switch(sa->sa_family) { 774 case AF_LINK: 775 /* 776 * No mapping needed. Just check that it's a valid MC address. 777 */ 778 sdl = (struct sockaddr_dl *)sa; 779 if (*LLADDR(sdl) != arcbroadcastaddr) 780 return EADDRNOTAVAIL; 781 *llsa = 0; 782 return 0; 783#ifdef INET 784 case AF_INET: 785 sin = (struct sockaddr_in *)sa; 786 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 787 return EADDRNOTAVAIL; 788 sdl = malloc(sizeof *sdl, M_IFMADDR, 789 M_NOWAIT | M_ZERO); 790 if (sdl == NULL) 791 return ENOMEM; 792 sdl->sdl_len = sizeof *sdl; 793 sdl->sdl_family = AF_LINK; 794 sdl->sdl_index = ifp->if_index; 795 sdl->sdl_type = IFT_ARCNET; 796 sdl->sdl_alen = ARC_ADDR_LEN; 797 *LLADDR(sdl) = 0; 798 *llsa = (struct sockaddr *)sdl; 799 return 0; 800#endif 801#ifdef INET6 802 case AF_INET6: 803 sin6 = (struct sockaddr_in6 *)sa; 804 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 805 /* 806 * An IP6 address of 0 means listen to all 807 * of the Ethernet multicast address used for IP6. 808 * (This is used for multicast routers.) 809 */ 810 ifp->if_flags |= IFF_ALLMULTI; 811 *llsa = 0; 812 return 0; 813 } 814 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 815 return EADDRNOTAVAIL; 816 sdl = malloc(sizeof *sdl, M_IFMADDR, 817 M_NOWAIT | M_ZERO); 818 if (sdl == NULL) 819 return ENOMEM; 820 sdl->sdl_len = sizeof *sdl; 821 sdl->sdl_family = AF_LINK; 822 sdl->sdl_index = ifp->if_index; 823 sdl->sdl_type = IFT_ARCNET; 824 sdl->sdl_alen = ARC_ADDR_LEN; 825 *LLADDR(sdl) = 0; 826 *llsa = (struct sockaddr *)sdl; 827 return 0; 828#endif 829 830 default: 831 /* 832 * Well, the text isn't quite right, but it's the name 833 * that counts... 834 */ 835 return EAFNOSUPPORT; 836 } 837} 838 839MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); 840 841static void* 842arc_alloc(u_char type, struct ifnet *ifp) 843{ 844 struct arccom *ac; 845 846 ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); 847 ac->ac_ifp = ifp; 848 849 return (ac); 850} 851 852static void 853arc_free(void *com, u_char type) 854{ 855 856 free(com, M_ARCCOM); 857} 858 859static int 860arc_modevent(module_t mod, int type, void *data) 861{ 862 863 switch (type) { 864 case MOD_LOAD: 865 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); 866 break; 867 case MOD_UNLOAD: 868 if_deregister_com_alloc(IFT_ARCNET); 869 break; 870 default: 871 return EOPNOTSUPP; 872 } 873 874 return (0); 875} 876 877static moduledata_t arc_mod = { 878 "arcnet", 879 arc_modevent, 880 0 881}; 882 883DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 884MODULE_VERSION(arcnet, 1); 885