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