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 332160 2018-04-07 00:04:28Z brooks $ */ 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 if ((m = ip_fastforward(m)) == NULL) 561 return; 562 isr = NETISR_IP; 563 break; 564 565 case ARCTYPE_IP_OLD: 566 m_adj(m, ARC_HDRLEN); 567 if ((m = ip_fastforward(m)) == NULL) 568 return; 569 isr = NETISR_IP; 570 break; 571 572 case ARCTYPE_ARP: 573 if (ifp->if_flags & IFF_NOARP) { 574 /* Discard packet if ARP is disabled on interface */ 575 m_freem(m); 576 return; 577 } 578 m_adj(m, ARC_HDRNEWLEN); 579 isr = NETISR_ARP; 580#ifdef ARCNET_ALLOW_BROKEN_ARP 581 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 582#endif 583 break; 584 585 case ARCTYPE_ARP_OLD: 586 if (ifp->if_flags & IFF_NOARP) { 587 /* Discard packet if ARP is disabled on interface */ 588 m_freem(m); 589 return; 590 } 591 m_adj(m, ARC_HDRLEN); 592 isr = NETISR_ARP; 593#ifdef ARCNET_ALLOW_BROKEN_ARP 594 mtod(m, struct arphdr *)->ar_pro = htons(ETHERTYPE_IP); 595#endif 596 break; 597#endif 598#ifdef INET6 599 case ARCTYPE_INET6: 600 m_adj(m, ARC_HDRNEWLEN); 601 isr = NETISR_IPV6; 602 break; 603#endif 604#ifdef IPX 605 case ARCTYPE_IPX: 606 m_adj(m, ARC_HDRNEWLEN); 607 isr = NETISR_IPX; 608 break; 609#endif 610 default: 611 m_freem(m); 612 return; 613 } 614 M_SETFIB(m, ifp->if_fib); 615 netisr_dispatch(isr, m); 616} 617 618/* 619 * Register (new) link level address. 620 */ 621void 622arc_storelladdr(struct ifnet *ifp, u_int8_t lla) 623{ 624 ARC_LLADDR(ifp) = lla; 625} 626 627/* 628 * Perform common duties while attaching to interface list 629 */ 630void 631arc_ifattach(struct ifnet *ifp, u_int8_t lla) 632{ 633 struct ifaddr *ifa; 634 struct sockaddr_dl *sdl; 635 struct arccom *ac; 636 637 if_attach(ifp); 638 ifp->if_addrlen = 1; 639 ifp->if_hdrlen = ARC_HDRLEN; 640 ifp->if_mtu = 1500; 641 ifp->if_resolvemulti = arc_resolvemulti; 642 if (ifp->if_baudrate == 0) 643 ifp->if_baudrate = 2500000; 644 ifa = ifp->if_addr; 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 ifr->ifr_addr.sa_data[0] = ARC_LLADDR(ifp); 719 break; 720 721 case SIOCADDMULTI: 722 case SIOCDELMULTI: 723 if (ifr == NULL) 724 error = EAFNOSUPPORT; 725 else { 726 switch (ifr->ifr_addr.sa_family) { 727 case AF_INET: 728 case AF_INET6: 729 error = 0; 730 break; 731 default: 732 error = EAFNOSUPPORT; 733 break; 734 } 735 } 736 break; 737 738 case SIOCSIFMTU: 739 /* 740 * Set the interface MTU. 741 * mtu can't be larger than ARCMTU for RFC1051 742 * and can't be larger than ARC_PHDS_MTU 743 */ 744 if (((ifp->if_flags & IFF_LINK0) && ifr->ifr_mtu > ARCMTU) || 745 ifr->ifr_mtu > ARC_PHDS_MAXMTU) 746 error = EINVAL; 747 else 748 ifp->if_mtu = ifr->ifr_mtu; 749 break; 750 } 751 752 return (error); 753} 754 755/* based on ether_resolvemulti() */ 756int 757arc_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 758 struct sockaddr *sa) 759{ 760 struct sockaddr_dl *sdl; 761#ifdef INET 762 struct sockaddr_in *sin; 763#endif 764#ifdef INET6 765 struct sockaddr_in6 *sin6; 766#endif 767 768 switch(sa->sa_family) { 769 case AF_LINK: 770 /* 771 * No mapping needed. Just check that it's a valid MC address. 772 */ 773 sdl = (struct sockaddr_dl *)sa; 774 if (*LLADDR(sdl) != arcbroadcastaddr) 775 return EADDRNOTAVAIL; 776 *llsa = 0; 777 return 0; 778#ifdef INET 779 case AF_INET: 780 sin = (struct sockaddr_in *)sa; 781 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 782 return EADDRNOTAVAIL; 783 sdl = malloc(sizeof *sdl, M_IFMADDR, 784 M_NOWAIT | M_ZERO); 785 if (sdl == NULL) 786 return ENOMEM; 787 sdl->sdl_len = sizeof *sdl; 788 sdl->sdl_family = AF_LINK; 789 sdl->sdl_index = ifp->if_index; 790 sdl->sdl_type = IFT_ARCNET; 791 sdl->sdl_alen = ARC_ADDR_LEN; 792 *LLADDR(sdl) = 0; 793 *llsa = (struct sockaddr *)sdl; 794 return 0; 795#endif 796#ifdef INET6 797 case AF_INET6: 798 sin6 = (struct sockaddr_in6 *)sa; 799 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 800 /* 801 * An IP6 address of 0 means listen to all 802 * of the Ethernet multicast address used for IP6. 803 * (This is used for multicast routers.) 804 */ 805 ifp->if_flags |= IFF_ALLMULTI; 806 *llsa = 0; 807 return 0; 808 } 809 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 810 return EADDRNOTAVAIL; 811 sdl = malloc(sizeof *sdl, M_IFMADDR, 812 M_NOWAIT | M_ZERO); 813 if (sdl == NULL) 814 return ENOMEM; 815 sdl->sdl_len = sizeof *sdl; 816 sdl->sdl_family = AF_LINK; 817 sdl->sdl_index = ifp->if_index; 818 sdl->sdl_type = IFT_ARCNET; 819 sdl->sdl_alen = ARC_ADDR_LEN; 820 *LLADDR(sdl) = 0; 821 *llsa = (struct sockaddr *)sdl; 822 return 0; 823#endif 824 825 default: 826 /* 827 * Well, the text isn't quite right, but it's the name 828 * that counts... 829 */ 830 return EAFNOSUPPORT; 831 } 832} 833 834static MALLOC_DEFINE(M_ARCCOM, "arccom", "ARCNET interface internals"); 835 836static void* 837arc_alloc(u_char type, struct ifnet *ifp) 838{ 839 struct arccom *ac; 840 841 ac = malloc(sizeof(struct arccom), M_ARCCOM, M_WAITOK | M_ZERO); 842 ac->ac_ifp = ifp; 843 844 return (ac); 845} 846 847static void 848arc_free(void *com, u_char type) 849{ 850 851 free(com, M_ARCCOM); 852} 853 854static int 855arc_modevent(module_t mod, int type, void *data) 856{ 857 858 switch (type) { 859 case MOD_LOAD: 860 if_register_com_alloc(IFT_ARCNET, arc_alloc, arc_free); 861 break; 862 case MOD_UNLOAD: 863 if_deregister_com_alloc(IFT_ARCNET); 864 break; 865 default: 866 return EOPNOTSUPP; 867 } 868 869 return (0); 870} 871 872static moduledata_t arc_mod = { 873 "arcnet", 874 arc_modevent, 875 0 876}; 877 878DECLARE_MODULE(arcnet, arc_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 879MODULE_VERSION(arcnet, 1); 880