if_arcsubr.c revision 295285
1/* $NetBSD: if_arcsubr.c,v 1.36 2001/06/14 05:44:23 itojun Exp $ */ 2/* $FreeBSD: stable/10/sys/net/if_arcsubr.c 295285 2016-02-04 22:53:12Z gnn $ */ 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) ((const struct sockaddr_in *)(s)) 96#define SIPX(s) ((const 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, const 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 { 190 const struct arc_header *ah; 191 192 loop_copy = -1; 193 ah = (const struct arc_header *)dst->sa_data; 194 adst = ah->arc_dhost; 195 atype = ah->arc_type; 196 197 if (atype == ARCTYPE_ARP) { 198 atype = (ifp->if_flags & IFF_LINK0) ? 199 ARCTYPE_ARP_OLD: ARCTYPE_ARP; 200 201#ifdef ARCNET_ALLOW_BROKEN_ARP 202 /* 203 * XXX It's not clear per RFC826 if this is needed, but 204 * "assigned numbers" say this is wrong. 205 * However, e.g., AmiTCP 3.0Beta used it... we make this 206 * switchable for emergency cases. Not perfect, but... 207 */ 208 if (ifp->if_flags & IFF_LINK2) 209 mtod(m, struct arphdr *)->ar_pro = atype - 1; 210#endif 211 } 212 break; 213 } 214 default: 215 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 216 senderr(EAFNOSUPPORT); 217 } 218 219 isphds = arc_isphds(atype); 220 M_PREPEND(m, isphds ? ARC_HDRNEWLEN : ARC_HDRLEN, M_NOWAIT); 221 if (m == 0) 222 senderr(ENOBUFS); 223 ah = mtod(m, struct arc_header *); 224 ah->arc_type = atype; 225 ah->arc_dhost = adst; 226 ah->arc_shost = ARC_LLADDR(ifp); 227 if (isphds) { 228 ah->arc_flag = 0; 229 ah->arc_seqid = 0; 230 } 231 232 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 233 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 234 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 235 236 (void) if_simloop(ifp, n, dst->sa_family, ARC_HDRLEN); 237 } else if (ah->arc_dhost == ah->arc_shost) { 238 (void) if_simloop(ifp, m, dst->sa_family, ARC_HDRLEN); 239 return (0); /* XXX */ 240 } 241 } 242 243 BPF_MTAP(ifp, m); 244 245 error = ifp->if_transmit(ifp, m); 246 247 return (error); 248 249bad: 250 if (m) 251 m_freem(m); 252 return (error); 253} 254 255void 256arc_frag_init(struct ifnet *ifp) 257{ 258 struct arccom *ac; 259 260 ac = (struct arccom *)ifp->if_l2com; 261 ac->curr_frag = 0; 262} 263 264struct mbuf * 265arc_frag_next(struct ifnet *ifp) 266{ 267 struct arccom *ac; 268 struct mbuf *m; 269 struct arc_header *ah; 270 271 ac = (struct arccom *)ifp->if_l2com; 272 if ((m = ac->curr_frag) == 0) { 273 int tfrags; 274 275 /* dequeue new packet */ 276 IF_DEQUEUE(&ifp->if_snd, m); 277 if (m == 0) 278 return 0; 279 280 ah = mtod(m, struct arc_header *); 281 if (!arc_isphds(ah->arc_type)) 282 return m; 283 284 ++ac->ac_seqid; /* make the seqid unique */ 285 tfrags = (m->m_pkthdr.len + ARC_MAX_DATA - 1) / ARC_MAX_DATA; 286 ac->fsflag = 2 * tfrags - 3; 287 ac->sflag = 0; 288 ac->rsflag = ac->fsflag; 289 ac->arc_dhost = ah->arc_dhost; 290 ac->arc_shost = ah->arc_shost; 291 ac->arc_type = ah->arc_type; 292 293 m_adj(m, ARC_HDRNEWLEN); 294 ac->curr_frag = m; 295 } 296 297 /* split out next fragment and return it */ 298 if (ac->sflag < ac->fsflag) { 299 /* we CAN'T have short packets here */ 300 ac->curr_frag = m_split(m, ARC_MAX_DATA, M_NOWAIT); 301 if (ac->curr_frag == 0) { 302 m_freem(m); 303 return 0; 304 } 305 306 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); 307 if (m == 0) { 308 m_freem(ac->curr_frag); 309 ac->curr_frag = 0; 310 return 0; 311 } 312 313 ah = mtod(m, struct arc_header *); 314 ah->arc_flag = ac->rsflag; 315 ah->arc_seqid = ac->ac_seqid; 316 317 ac->sflag += 2; 318 ac->rsflag = ac->sflag; 319 } else if ((m->m_pkthdr.len >= 320 ARC_MIN_FORBID_LEN - ARC_HDRNEWLEN + 2) && 321 (m->m_pkthdr.len <= 322 ARC_MAX_FORBID_LEN - ARC_HDRNEWLEN + 2)) { 323 ac->curr_frag = 0; 324 325 M_PREPEND(m, ARC_HDRNEWLEN_EXC, M_NOWAIT); 326 if (m == 0) 327 return 0; 328 329 ah = mtod(m, struct arc_header *); 330 ah->arc_flag = 0xFF; 331 ah->arc_seqid = 0xFFFF; 332 ah->arc_type2 = ac->arc_type; 333 ah->arc_flag2 = ac->sflag; 334 ah->arc_seqid2 = ac->ac_seqid; 335 } else { 336 ac->curr_frag = 0; 337 338 M_PREPEND(m, ARC_HDRNEWLEN, M_NOWAIT); 339 if (m == 0) 340 return 0; 341 342 ah = mtod(m, struct arc_header *); 343 ah->arc_flag = ac->sflag; 344 ah->arc_seqid = ac->ac_seqid; 345 } 346 347 ah->arc_dhost = ac->arc_dhost; 348 ah->arc_shost = ac->arc_shost; 349 ah->arc_type = ac->arc_type; 350 351 return m; 352} 353 354/* 355 * Defragmenter. Returns mbuf if last packet found, else 356 * NULL. frees imcoming mbuf as necessary. 357 */ 358 359static __inline struct mbuf * 360arc_defrag(struct ifnet *ifp, 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->if_l2com; 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(u_int8_t type) 509{ 510 return (type != ARCTYPE_IP_OLD && 511 type != ARCTYPE_ARP_OLD && 512 type != ARCTYPE_DIAGNOSE); 513} 514 515/* 516 * Process a received Arcnet packet; 517 * the packet is in the mbuf chain m with 518 * the ARCnet header. 519 */ 520void 521arc_input(struct ifnet *ifp, struct mbuf *m) 522{ 523 struct arc_header *ah; 524 int isr; 525 u_int8_t atype; 526 527 if ((ifp->if_flags & IFF_UP) == 0) { 528 m_freem(m); 529 return; 530 } 531 532 /* possibly defragment: */ 533 m = arc_defrag(ifp, m); 534 if (m == NULL) 535 return; 536 537 BPF_MTAP(ifp, m); 538 539 ah = mtod(m, struct arc_header *); 540 /* does this belong to us? */ 541 if ((ifp->if_flags & IFF_PROMISC) == 0 542 && ah->arc_dhost != arcbroadcastaddr 543 && ah->arc_dhost != ARC_LLADDR(ifp)) { 544 m_freem(m); 545 return; 546 } 547 548 ifp->if_ibytes += m->m_pkthdr.len; 549 550 if (ah->arc_dhost == arcbroadcastaddr) { 551 m->m_flags |= M_BCAST|M_MCAST; 552 ifp->if_imcasts++; 553 } 554 555 atype = ah->arc_type; 556 switch (atype) { 557#ifdef INET 558 case ARCTYPE_IP: 559 m_adj(m, ARC_HDRNEWLEN); 560 isr = NETISR_IP; 561 break; 562 563 case ARCTYPE_IP_OLD: 564 m_adj(m, ARC_HDRLEN); 565 isr = NETISR_IP; 566 break; 567 568 case ARCTYPE_ARP: 569 if (ifp->if_flags & IFF_NOARP) { 570 /* Discard packet if ARP is disabled on interface */ 571 m_freem(m); 572 return; 573 } 574 m_adj(m, ARC_HDRNEWLEN); 575 isr = NETISR_ARP; 576#ifdef ARCNET_ALLOW_BROKEN_ARP 577 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 578#endif 579 break; 580 581 case ARCTYPE_ARP_OLD: 582 if (ifp->if_flags & IFF_NOARP) { 583 /* Discard packet if ARP is disabled on interface */ 584 m_freem(m); 585 return; 586 } 587 m_adj(m, ARC_HDRLEN); 588 isr = NETISR_ARP; 589#ifdef ARCNET_ALLOW_BROKEN_ARP 590 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 591#endif 592 break; 593#endif 594#ifdef INET6 595 case ARCTYPE_INET6: 596 m_adj(m, ARC_HDRNEWLEN); 597 isr = NETISR_IPV6; 598 break; 599#endif 600#ifdef IPX 601 case ARCTYPE_IPX: 602 m_adj(m, ARC_HDRNEWLEN); 603 isr = NETISR_IPX; 604 break; 605#endif 606 default: 607 m_freem(m); 608 return; 609 } 610 M_SETFIB(m, ifp->if_fib); 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 ifa = ifp->if_addr; 641 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 642 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 643 sdl->sdl_type = IFT_ARCNET; 644 sdl->sdl_alen = ifp->if_addrlen; 645 646 if (ifp->if_flags & IFF_BROADCAST) 647 ifp->if_flags |= IFF_MULTICAST|IFF_ALLMULTI; 648 649 ac = (struct arccom *)ifp->if_l2com; 650 ac->ac_seqid = (time_second) & 0xFFFF; /* try to make seqid unique */ 651 if (lla == 0) { 652 /* XXX this message isn't entirely clear, to me -- cgd */ 653 log(LOG_ERR,"%s: link address 0 reserved for broadcasts. Please change it and ifconfig %s down up\n", 654 ifp->if_xname, ifp->if_xname); 655 } 656 arc_storelladdr(ifp, lla); 657 658 ifp->if_broadcastaddr = &arcbroadcastaddr; 659 660 bpfattach(ifp, DLT_ARCNET, ARC_HDRLEN); 661} 662 663void 664arc_ifdetach(struct ifnet *ifp) 665{ 666 bpfdetach(ifp); 667 if_detach(ifp); 668} 669 670int 671arc_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 672{ 673 struct ifaddr *ifa = (struct ifaddr *) data; 674 struct ifreq *ifr = (struct ifreq *) data; 675 int error = 0; 676 677 switch (command) { 678 case SIOCSIFADDR: 679 ifp->if_flags |= IFF_UP; 680 switch (ifa->ifa_addr->sa_family) { 681#ifdef INET 682 case AF_INET: 683 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 684 arp_ifinit(ifp, ifa); 685 break; 686#endif 687#ifdef IPX 688 /* 689 * XXX This code is probably wrong 690 */ 691 case AF_IPX: 692 { 693 struct ipx_addr *ina = &(IA_SIPX(ifa)->sipx_addr); 694 695 if (ipx_nullhost(*ina)) 696 ina->x_host.c_host[5] = ARC_LLADDR(ifp); 697 else 698 arc_storelladdr(ifp, ina->x_host.c_host[5]); 699 700 /* 701 * Set new address 702 */ 703 ifp->if_init(ifp->if_softc); 704 break; 705 } 706#endif 707 default: 708 ifp->if_init(ifp->if_softc); 709 break; 710 } 711 break; 712 713 case SIOCGIFADDR: 714 { 715 struct sockaddr *sa; 716 717 sa = (struct sockaddr *) &ifr->ifr_data; 718 *(u_int8_t *)sa->sa_data = ARC_LLADDR(ifp); 719 } 720 break; 721 722 case SIOCADDMULTI: 723 case SIOCDELMULTI: 724 if (ifr == NULL) 725 error = EAFNOSUPPORT; 726 else { 727 switch (ifr->ifr_addr.sa_family) { 728 case AF_INET: 729 case AF_INET6: 730 error = 0; 731 break; 732 default: 733 error = EAFNOSUPPORT; 734 break; 735 } 736 } 737 break; 738 739 case SIOCSIFMTU: 740 /* 741 * Set the interface MTU. 742 * mtu can't be larger than ARCMTU for RFC1051 743 * and can't be larger than ARC_PHDS_MTU 744 */ 745 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 746 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 747 error = EINVAL; 748 else 749 ifp->if_mtu = ifr->ifr_mtu; 750 break; 751 } 752 753 return (error); 754} 755 756/* based on ether_resolvemulti() */ 757int 758arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 759 struct sockaddr *sa) 760{ 761 struct sockaddr_dl *sdl; 762#ifdef INET 763 struct sockaddr_in *sin; 764#endif 765#ifdef INET6 766 struct sockaddr_in6 *sin6; 767#endif 768 769 switch(sa->sa_family) { 770 case AF_LINK: 771 /* 772 * No mapping needed. Just check that it's a valid MC address. 773 */ 774 sdl = (struct sockaddr_dl *)sa; 775 if (*LLADDR(sdl) != arcbroadcastaddr) 776 return EADDRNOTAVAIL; 777 *llsa = 0; 778 return 0; 779#ifdef INET 780 case AF_INET: 781 sin = (struct sockaddr_in *)sa; 782 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 783 return EADDRNOTAVAIL; 784 sdl = malloc(sizeof *sdl, M_IFMADDR, 785 M_NOWAIT | M_ZERO); 786 if (sdl == NULL) 787 return ENOMEM; 788 sdl->sdl_len = sizeof *sdl; 789 sdl->sdl_family = AF_LINK; 790 sdl->sdl_index = ifp->if_index; 791 sdl->sdl_type = IFT_ARCNET; 792 sdl->sdl_alen = ARC_ADDR_LEN; 793 *LLADDR(sdl) = 0; 794 *llsa = (struct sockaddr *)sdl; 795 return 0; 796#endif 797#ifdef INET6 798 case AF_INET6: 799 sin6 = (struct sockaddr_in6 *)sa; 800 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 801 /* 802 * An IP6 address of 0 means listen to all 803 * of the Ethernet multicast address used for IP6. 804 * (This is used for multicast routers.) 805 */ 806 ifp->if_flags |= IFF_ALLMULTI; 807 *llsa = 0; 808 return 0; 809 } 810 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 811 return EADDRNOTAVAIL; 812 sdl = malloc(sizeof *sdl, M_IFMADDR, 813 M_NOWAIT | M_ZERO); 814 if (sdl == NULL) 815 return ENOMEM; 816 sdl->sdl_len = sizeof *sdl; 817 sdl->sdl_family = AF_LINK; 818 sdl->sdl_index = ifp->if_index; 819 sdl->sdl_type = IFT_ARCNET; 820 sdl->sdl_alen = ARC_ADDR_LEN; 821 *LLADDR(sdl) = 0; 822 *llsa = (struct sockaddr *)sdl; 823 return 0; 824#endif 825 826 default: 827 /* 828 * Well, the text isn't quite right, but it's the name 829 * that counts... 830 */ 831 return EAFNOSUPPORT; 832 } 833} 834 835static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); 836 837static void* 838arc_alloc(u_char type, struct ifnet *ifp) 839{ 840 struct arccom *ac; 841 842 ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); 843 ac->ac_ifp = ifp; 844 845 return (ac); 846} 847 848static void 849arc_free(void *com, u_char type) 850{ 851 852 free(com, M_ARCCOM); 853} 854 855static int 856arc_modevent(module_t mod, int type, void *data) 857{ 858 859 switch (type) { 860 case MOD_LOAD: 861 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); 862 break; 863 case MOD_UNLOAD: 864 if_deregister_com_alloc(IFT_ARCNET); 865 break; 866 default: 867 return EOPNOTSUPP; 868 } 869 870 return (0); 871} 872 873static moduledata_t arc_mod = { 874 "arcnet", 875 arc_modevent, 876 0 877}; 878 879DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 880MODULE_VERSION(arcnet, 1); 881