if_arcsubr.c revision 248621
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: head/sys/net/if_arcsubr.c 248621 2013-03-22 20:44:16Z glebius $ */ 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_NOWAIT); 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_NOWAIT); 298 if (ac->curr_frag == 0) { 299 m_freem(m); 300 return 0; 301 } 302 303 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); 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_NOWAIT); 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_NOWAIT); 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 M_SETFIB(m, ifp->if_fib); 612 netisr_dispatch(isr, m); 613} 614 615/* 616 * Register (new) link level address. 617 */ 618void 619arc_storelladdr(struct ifnet *ifp, u_int8_t lla) 620{ 621 ARC_LLADDR(ifp) = lla; 622} 623 624/* 625 * Perform common duties while attaching to interface list 626 */ 627void 628arc_ifattach(struct ifnet *ifp, u_int8_t lla) 629{ 630 struct ifaddr *ifa; 631 struct sockaddr_dl *sdl; 632 struct arccom *ac; 633 634 if_attach(ifp); 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 ifa = ifp->if_addr; 642 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 643 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 644 sdl->sdl_type = IFT_ARCNET; 645 sdl->sdl_alen = ifp->if_addrlen; 646 647 if (ifp->if_flags & IFF_BROADCAST) 648 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 649 650 ac = (struct arccom *)ifp->if_l2com; 651 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 652 if (lla == 0) { 653 /* XXX this message isn't entirely clear, to me -- cgd */ 654 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", 655 ifp->if_xname, ifp->if_xname); 656 } 657 arc_storelladdr(ifp, lla); 658 659 ifp->if_broadcastaddr = &arcbroadcastaddr; 660 661 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 662} 663 664void 665arc_ifdetach(struct ifnet *ifp) 666{ 667 bpfdetach(ifp); 668 if_detach(ifp); 669} 670 671int 672arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 673{ 674 struct ifaddr *ifa = (struct ifaddr *) data; 675 struct ifreq *ifr = (struct ifreq *) data; 676 int error = 0; 677 678 switch (command) { 679 case SIOCSIFADDR: 680 ifp->if_flags |= IFF_UP; 681 switch (ifa->ifa_addr->sa_family) { 682#ifdef INET 683 case AF_INET: 684 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 685 arp_ifinit(ifp, ifa); 686 break; 687#endif 688#ifdef IPX 689 /* 690 * XXX This code is probably wrong 691 */ 692 case AF_IPX: 693 { 694 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 695 696 if (ipx_nullhost(*ina)) 697 ina->x_host.c_host[5] = ARC_LLADDR(ifp); 698 else 699 arc_storelladdr(ifp, ina->x_host.c_host[5]); 700 701 /* 702 * Set new address 703 */ 704 ifp->if_init(ifp->if_softc); 705 break; 706 } 707#endif 708 default: 709 ifp->if_init(ifp->if_softc); 710 break; 711 } 712 break; 713 714 case SIOCGIFADDR: 715 { 716 struct sockaddr *sa; 717 718 sa = (struct sockaddr *) &ifr->ifr_data; 719 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 720 } 721 break; 722 723 case SIOCADDMULTI: 724 case SIOCDELMULTI: 725 if (ifr == NULL) 726 error = EAFNOSUPPORT; 727 else { 728 switch (ifr->ifr_addr.sa_family) { 729 case AF_INET: 730 case AF_INET6: 731 error = 0; 732 break; 733 default: 734 error = EAFNOSUPPORT; 735 break; 736 } 737 } 738 break; 739 740 case SIOCSIFMTU: 741 /* 742 * Set the interface MTU. 743 * mtu can't be larger than ARCMTU for RFC1051 744 * and can't be larger than ARC_PHDS_MTU 745 */ 746 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 747 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 748 error = EINVAL; 749 else 750 ifp->if_mtu = ifr->ifr_mtu; 751 break; 752 } 753 754 return (error); 755} 756 757/* based on ether_resolvemulti() */ 758int 759arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 760 struct sockaddr *sa) 761{ 762 struct sockaddr_dl *sdl; 763#ifdef INET 764 struct sockaddr_in *sin; 765#endif 766#ifdef INET6 767 struct sockaddr_in6 *sin6; 768#endif 769 770 switch(sa->sa_family) { 771 case AF_LINK: 772 /* 773 * No mapping needed. Just check that it's a valid MC address. 774 */ 775 sdl = (struct sockaddr_dl *)sa; 776 if (*LLADDR(sdl) != arcbroadcastaddr) 777 return EADDRNOTAVAIL; 778 *llsa = 0; 779 return 0; 780#ifdef INET 781 case AF_INET: 782 sin = (struct sockaddr_in *)sa; 783 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 784 return EADDRNOTAVAIL; 785 sdl = malloc(sizeof *sdl, M_IFMADDR, 786 M_NOWAIT | M_ZERO); 787 if (sdl == NULL) 788 return ENOMEM; 789 sdl->sdl_len = sizeof *sdl; 790 sdl->sdl_family = AF_LINK; 791 sdl->sdl_index = ifp->if_index; 792 sdl->sdl_type = IFT_ARCNET; 793 sdl->sdl_alen = ARC_ADDR_LEN; 794 *LLADDR(sdl) = 0; 795 *llsa = (struct sockaddr *)sdl; 796 return 0; 797#endif 798#ifdef INET6 799 case AF_INET6: 800 sin6 = (struct sockaddr_in6 *)sa; 801 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 802 /* 803 * An IP6 address of 0 means listen to all 804 * of the Ethernet multicast address used for IP6. 805 * (This is used for multicast routers.) 806 */ 807 ifp->if_flags |= IFF_ALLMULTI; 808 *llsa = 0; 809 return 0; 810 } 811 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 812 return EADDRNOTAVAIL; 813 sdl = malloc(sizeof *sdl, M_IFMADDR, 814 M_NOWAIT | M_ZERO); 815 if (sdl == NULL) 816 return ENOMEM; 817 sdl->sdl_len = sizeof *sdl; 818 sdl->sdl_family = AF_LINK; 819 sdl->sdl_index = ifp->if_index; 820 sdl->sdl_type = IFT_ARCNET; 821 sdl->sdl_alen = ARC_ADDR_LEN; 822 *LLADDR(sdl) = 0; 823 *llsa = (struct sockaddr *)sdl; 824 return 0; 825#endif 826 827 default: 828 /* 829 * Well, the text isn't quite right, but it's the name 830 * that counts... 831 */ 832 return EAFNOSUPPORT; 833 } 834} 835 836static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); 837 838static void* 839arc_alloc(u_char type, struct ifnet *ifp) 840{ 841 struct arccom *ac; 842 843 ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); 844 ac->ac_ifp = ifp; 845 846 return (ac); 847} 848 849static void 850arc_free(void *com, u_char type) 851{ 852 853 free(com, M_ARCCOM); 854} 855 856static int 857arc_modevent(module_t mod, int type, void *data) 858{ 859 860 switch (type) { 861 case MOD_LOAD: 862 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); 863 break; 864 case MOD_UNLOAD: 865 if_deregister_com_alloc(IFT_ARCNET); 866 break; 867 default: 868 return EOPNOTSUPP; 869 } 870 871 return (0); 872} 873 874static moduledata_t arc_mod = { 875 "arcnet", 876 arc_modevent, 877 0 878}; 879 880DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 881MODULE_VERSION(arcnet, 1); 882