1/*- 2 * Copyright (c) 1998, Larry Lile 3 * All rights reserved. 4 * 5 * For latest sources and information on this driver, please 6 * go to http://anarchy.stdio.com. 7 * 8 * Questions, comments or suggestions should be directed to 9 * Larry Lile <lile@stdio.com>. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice unmodified, this list of conditions, and the following 16 * disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 * 33 * $FreeBSD: stable/10/sys/net/if_iso88025subr.c 332160 2018-04-07 00:04:28Z brooks $ 34 * 35 */ 36 37/* 38 * 39 * General ISO 802.5 (Token Ring) support routines 40 * 41 */ 42 43#include "opt_inet.h" 44#include "opt_inet6.h" 45#include "opt_ipx.h" 46 47#include <sys/param.h> 48#include <sys/systm.h> 49#include <sys/kernel.h> 50#include <sys/malloc.h> 51#include <sys/mbuf.h> 52#include <sys/module.h> 53#include <sys/socket.h> 54#include <sys/sockio.h> 55 56#include <net/if.h> 57#include <net/if_arp.h> 58#include <net/if_dl.h> 59#include <net/if_llc.h> 60#include <net/if_types.h> 61#include <net/if_llatbl.h> 62 63#include <net/ethernet.h> 64#include <net/netisr.h> 65#include <net/route.h> 66#include <net/bpf.h> 67#include <net/iso88025.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#ifdef INET6 75#include <netinet6/nd6.h> 76#endif 77 78#ifdef IPX 79#include <netipx/ipx.h> 80#include <netipx/ipx_if.h> 81#endif 82 83#include <security/mac/mac_framework.h> 84 85static const u_char iso88025_broadcastaddr[ISO88025_ADDR_LEN] = 86 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 87 88static int iso88025_resolvemulti (struct ifnet *, struct sockaddr **, 89 struct sockaddr *); 90 91#define senderr(e) do { error = (e); goto bad; } while (0) 92 93/* 94 * Perform common duties while attaching to interface list 95 */ 96void 97iso88025_ifattach(struct ifnet *ifp, const u_int8_t *lla, int bpf) 98{ 99 struct ifaddr *ifa; 100 struct sockaddr_dl *sdl; 101 102 ifa = NULL; 103 104 ifp->if_type = IFT_ISO88025; 105 ifp->if_addrlen = ISO88025_ADDR_LEN; 106 ifp->if_hdrlen = ISO88025_HDR_LEN; 107 108 if_attach(ifp); /* Must be called before additional assignments */ 109 110 ifp->if_output = iso88025_output; 111 ifp->if_input = iso88025_input; 112 ifp->if_resolvemulti = iso88025_resolvemulti; 113 ifp->if_broadcastaddr = iso88025_broadcastaddr; 114 115 if (ifp->if_baudrate == 0) 116 ifp->if_baudrate = TR_16MBPS; /* 16Mbit should be a safe default */ 117 if (ifp->if_mtu == 0) 118 ifp->if_mtu = ISO88025_DEFAULT_MTU; 119 120 ifa = ifp->if_addr; 121 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 122 123 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 124 sdl->sdl_type = IFT_ISO88025; 125 sdl->sdl_alen = ifp->if_addrlen; 126 bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 127 128 if (bpf) 129 bpfattach(ifp, DLT_IEEE802, ISO88025_HDR_LEN); 130 131 return; 132} 133 134/* 135 * Perform common duties while detaching a Token Ring interface 136 */ 137void 138iso88025_ifdetach(ifp, bpf) 139 struct ifnet *ifp; 140 int bpf; 141{ 142 143 if (bpf) 144 bpfdetach(ifp); 145 146 if_detach(ifp); 147 148 return; 149} 150 151int 152iso88025_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 153{ 154 struct ifaddr *ifa; 155 struct ifreq *ifr; 156 int error; 157 158 ifa = (struct ifaddr *) data; 159 ifr = (struct ifreq *) data; 160 error = 0; 161 162 switch (command) { 163 case SIOCSIFADDR: 164 ifp->if_flags |= IFF_UP; 165 166 switch (ifa->ifa_addr->sa_family) { 167#ifdef INET 168 case AF_INET: 169 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 170 arp_ifinit(ifp, ifa); 171 break; 172#endif /* INET */ 173#ifdef IPX 174 /* 175 * XXX - This code is probably wrong 176 */ 177 case AF_IPX: { 178 struct ipx_addr *ina; 179 180 ina = &(IA_SIPX(ifa)->sipx_addr); 181 182 if (ipx_nullhost(*ina)) 183 ina->x_host = *(union ipx_host *) 184 IF_LLADDR(ifp); 185 else 186 bcopy((caddr_t) ina->x_host.c_host, 187 (caddr_t) IF_LLADDR(ifp), 188 ISO88025_ADDR_LEN); 189 190 /* 191 * Set new address 192 */ 193 ifp->if_init(ifp->if_softc); 194 } 195 break; 196#endif /* IPX */ 197 default: 198 ifp->if_init(ifp->if_softc); 199 break; 200 } 201 break; 202 203 case SIOCGIFADDR: 204 bcopy(IF_LLADDR(ifp), &ifr->ifr_addr.sa_data[0], 205 ISO88025_ADDR_LEN); 206 break; 207 208 case SIOCSIFMTU: 209 /* 210 * Set the interface MTU. 211 */ 212 if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 213 error = EINVAL; 214 } else { 215 ifp->if_mtu = ifr->ifr_mtu; 216 } 217 break; 218 default: 219 error = EINVAL; /* XXX netbsd has ENOTTY??? */ 220 break; 221 } 222 223 return (error); 224} 225 226/* 227 * ISO88025 encapsulation 228 */ 229int 230iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 231 struct route *ro) 232{ 233 u_int16_t snap_type = 0; 234 int loop_copy = 0, error = 0, rif_len = 0; 235 u_char edst[ISO88025_ADDR_LEN]; 236 struct iso88025_header *th; 237 struct iso88025_header gen_th; 238 struct sockaddr_dl *sdl = NULL; 239 struct rtentry *rt0 = NULL; 240#if defined(INET) || defined(INET6) 241 struct llentry *lle; 242#endif 243 244 if (ro != NULL) 245 rt0 = ro->ro_rt; 246 247#ifdef MAC 248 error = mac_ifnet_check_transmit(ifp, m); 249 if (error) 250 senderr(error); 251#endif 252 253 if (ifp->if_flags & IFF_MONITOR) 254 senderr(ENETDOWN); 255 if (!((ifp->if_flags & IFF_UP) && 256 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 257 senderr(ENETDOWN); 258 getmicrotime(&ifp->if_lastchange); 259 260 /* Calculate routing info length based on arp table entry */ 261 /* XXX any better way to do this ? */ 262 263 if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway)) 264 if (SDL_ISO88025(sdl)->trld_rcf != 0) 265 rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 266 267 /* Generate a generic 802.5 header for the packet */ 268 gen_th.ac = TR_AC; 269 gen_th.fc = TR_LLC_FRAME; 270 (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp), 271 ISO88025_ADDR_LEN); 272 if (rif_len) { 273 gen_th.iso88025_shost[0] |= TR_RII; 274 if (rif_len > 2) { 275 gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 276 (void)memcpy((caddr_t)gen_th.rd, 277 (caddr_t)SDL_ISO88025(sdl)->trld_route, 278 rif_len - 2); 279 } 280 } 281 282 switch (dst->sa_family) { 283#ifdef INET 284 case AF_INET: 285 error = arpresolve(ifp, rt0, m, dst, edst, &lle); 286 if (error) 287 return (error == EWOULDBLOCK ? 0 : error); 288 snap_type = ETHERTYPE_IP; 289 break; 290 case AF_ARP: 291 { 292 struct arphdr *ah; 293 ah = mtod(m, struct arphdr *); 294 ah->ar_hrd = htons(ARPHRD_IEEE802); 295 296 loop_copy = -1; /* if this is for us, don't do it */ 297 298 switch(ntohs(ah->ar_op)) { 299 case ARPOP_REVREQUEST: 300 case ARPOP_REVREPLY: 301 snap_type = ETHERTYPE_REVARP; 302 break; 303 case ARPOP_REQUEST: 304 case ARPOP_REPLY: 305 default: 306 snap_type = ETHERTYPE_ARP; 307 break; 308 } 309 310 if (m->m_flags & M_BCAST) 311 bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN); 312 else 313 bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN); 314 315 } 316 break; 317#endif /* INET */ 318#ifdef INET6 319 case AF_INET6: 320 error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 321 if (error) 322 return (error); 323 snap_type = ETHERTYPE_IPV6; 324 break; 325#endif /* INET6 */ 326#ifdef IPX 327 case AF_IPX: 328 { 329 u_int8_t *cp; 330 331 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 332 ISO88025_ADDR_LEN); 333 334 M_PREPEND(m, 3, M_WAITOK); 335 m = m_pullup(m, 3); 336 if (m == 0) 337 senderr(ENOBUFS); 338 cp = mtod(m, u_int8_t *); 339 *cp++ = ETHERTYPE_IPX_8022; 340 *cp++ = ETHERTYPE_IPX_8022; 341 *cp++ = LLC_UI; 342 } 343 break; 344#endif /* IPX */ 345 case AF_UNSPEC: 346 { 347 const struct iso88025_sockaddr_data *sd; 348 /* 349 * For AF_UNSPEC sockaddr.sa_data must contain all of the 350 * mac information needed to send the packet. This allows 351 * full mac, llc, and source routing function to be controlled. 352 * llc and source routing information must already be in the 353 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 354 * should be an iso88025_sockaddr_data structure see iso88025.h 355 */ 356 loop_copy = -1; 357 sd = (const struct iso88025_sockaddr_data *)dst->sa_data; 358 gen_th.ac = sd->ac; 359 gen_th.fc = sd->fc; 360 (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN); 361 (void)memcpy(gen_th.iso88025_shost, sd->ether_shost, 362 ISO88025_ADDR_LEN); 363 rif_len = 0; 364 break; 365 } 366 default: 367 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 368 senderr(EAFNOSUPPORT); 369 break; 370 } 371 372 /* 373 * Add LLC header. 374 */ 375 if (snap_type != 0) { 376 struct llc *l; 377 M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); 378 if (m == 0) 379 senderr(ENOBUFS); 380 l = mtod(m, struct llc *); 381 l->llc_control = LLC_UI; 382 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 383 l->llc_snap.org_code[0] = 384 l->llc_snap.org_code[1] = 385 l->llc_snap.org_code[2] = 0; 386 l->llc_snap.ether_type = htons(snap_type); 387 } 388 389 /* 390 * Add local net header. If no space in first mbuf, 391 * allocate another. 392 */ 393 M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT); 394 if (m == 0) 395 senderr(ENOBUFS); 396 th = mtod(m, struct iso88025_header *); 397 bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 398 399 /* Copy as much of the generic header as is needed into the mbuf */ 400 memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 401 402 /* 403 * If a simplex interface, and the packet is being sent to our 404 * Ethernet address or a broadcast address, loopback a copy. 405 * XXX To make a simplex device behave exactly like a duplex 406 * device, we should copy in the case of sending to our own 407 * ethernet address (thus letting the original actually appear 408 * on the wire). However, we don't do that here for security 409 * reasons and compatibility with the original behavior. 410 */ 411 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 412 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 413 struct mbuf *n; 414 n = m_copy(m, 0, (int)M_COPYALL); 415 (void) if_simloop(ifp, n, dst->sa_family, 416 ISO88025_HDR_LEN); 417 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 418 ETHER_ADDR_LEN) == 0) { 419 (void) if_simloop(ifp, m, dst->sa_family, 420 ISO88025_HDR_LEN); 421 return(0); /* XXX */ 422 } 423 } 424 425 IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error); 426 if (error) { 427 printf("iso88025_output: packet dropped QFULL.\n"); 428 ifp->if_oerrors++; 429 } 430 return (error); 431 432bad: 433 ifp->if_oerrors++; 434 if (m) 435 m_freem(m); 436 return (error); 437} 438 439/* 440 * ISO 88025 de-encapsulation 441 */ 442void 443iso88025_input(ifp, m) 444 struct ifnet *ifp; 445 struct mbuf *m; 446{ 447 struct iso88025_header *th; 448 struct llc *l; 449 int isr; 450 int mac_hdr_len; 451 452 /* 453 * Do consistency checks to verify assumptions 454 * made by code past this point. 455 */ 456 if ((m->m_flags & M_PKTHDR) == 0) { 457 if_printf(ifp, "discard frame w/o packet header\n"); 458 ifp->if_ierrors++; 459 m_freem(m); 460 return; 461 } 462 if (m->m_pkthdr.rcvif == NULL) { 463 if_printf(ifp, "discard frame w/o interface pointer\n"); 464 ifp->if_ierrors++; 465 m_freem(m); 466 return; 467 } 468 469 m = m_pullup(m, ISO88025_HDR_LEN); 470 if (m == NULL) { 471 ifp->if_ierrors++; 472 goto dropanyway; 473 } 474 th = mtod(m, struct iso88025_header *); 475 476 /* 477 * Discard packet if interface is not up. 478 */ 479 if (!((ifp->if_flags & IFF_UP) && 480 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 481 goto dropanyway; 482 483 /* 484 * Give bpf a chance at the packet. 485 */ 486 BPF_MTAP(ifp, m); 487 488 /* 489 * Interface marked for monitoring; discard packet. 490 */ 491 if (ifp->if_flags & IFF_MONITOR) { 492 m_freem(m); 493 return; 494 } 495 496#ifdef MAC 497 mac_ifnet_create_mbuf(ifp, m); 498#endif 499 500 /* 501 * Update interface statistics. 502 */ 503 ifp->if_ibytes += m->m_pkthdr.len; 504 getmicrotime(&ifp->if_lastchange); 505 506 /* 507 * Discard non local unicast packets when interface 508 * is in promiscuous mode. 509 */ 510 if ((ifp->if_flags & IFF_PROMISC) && 511 ((th->iso88025_dhost[0] & 1) == 0) && 512 (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost, 513 ISO88025_ADDR_LEN) != 0)) 514 goto dropanyway; 515 516 /* 517 * Set mbuf flags for bcast/mcast. 518 */ 519 if (th->iso88025_dhost[0] & 1) { 520 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost, 521 ISO88025_ADDR_LEN) == 0) 522 m->m_flags |= M_BCAST; 523 else 524 m->m_flags |= M_MCAST; 525 ifp->if_imcasts++; 526 } 527 528 mac_hdr_len = ISO88025_HDR_LEN; 529 /* Check for source routing info */ 530 if (th->iso88025_shost[0] & TR_RII) 531 mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 532 533 /* Strip off ISO88025 header. */ 534 m_adj(m, mac_hdr_len); 535 536 m = m_pullup(m, LLC_SNAPFRAMELEN); 537 if (m == 0) { 538 ifp->if_ierrors++; 539 goto dropanyway; 540 } 541 l = mtod(m, struct llc *); 542 543 switch (l->llc_dsap) { 544#ifdef IPX 545 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 546 if ((l->llc_control != LLC_UI) || 547 (l->llc_ssap != ETHERTYPE_IPX_8022)) { 548 ifp->if_noproto++; 549 goto dropanyway; 550 } 551 552 th->iso88025_shost[0] &= ~(TR_RII); 553 m_adj(m, 3); 554 isr = NETISR_IPX; 555 break; 556#endif /* IPX */ 557 case LLC_SNAP_LSAP: { 558 u_int16_t type; 559 if ((l->llc_control != LLC_UI) || 560 (l->llc_ssap != LLC_SNAP_LSAP)) { 561 ifp->if_noproto++; 562 goto dropanyway; 563 } 564 565 if (l->llc_snap.org_code[0] != 0 || 566 l->llc_snap.org_code[1] != 0 || 567 l->llc_snap.org_code[2] != 0) { 568 ifp->if_noproto++; 569 goto dropanyway; 570 } 571 572 type = ntohs(l->llc_snap.ether_type); 573 m_adj(m, LLC_SNAPFRAMELEN); 574 switch (type) { 575#ifdef INET 576 case ETHERTYPE_IP: 577 th->iso88025_shost[0] &= ~(TR_RII); 578 if ((m = ip_fastforward(m)) == NULL) 579 return; 580 isr = NETISR_IP; 581 break; 582 583 case ETHERTYPE_ARP: 584 if (ifp->if_flags & IFF_NOARP) 585 goto dropanyway; 586 isr = NETISR_ARP; 587 break; 588#endif /* INET */ 589#ifdef IPX_SNAP /* XXX: Not supported! */ 590 case ETHERTYPE_IPX: 591 th->iso88025_shost[0] &= ~(TR_RII); 592 isr = NETISR_IPX; 593 break; 594#endif /* IPX_SNAP */ 595#ifdef INET6 596 case ETHERTYPE_IPV6: 597 th->iso88025_shost[0] &= ~(TR_RII); 598 isr = NETISR_IPV6; 599 break; 600#endif /* INET6 */ 601 default: 602 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 603 ifp->if_noproto++; 604 goto dropanyway; 605 } 606 break; 607 } 608#ifdef ISO 609 case LLC_ISO_LSAP: 610 switch (l->llc_control) { 611 case LLC_UI: 612 ifp->if_noproto++; 613 goto dropanyway; 614 break; 615 case LLC_XID: 616 case LLC_XID_P: 617 if(m->m_len < ISO88025_ADDR_LEN) 618 goto dropanyway; 619 l->llc_window = 0; 620 l->llc_fid = 9; 621 l->llc_class = 1; 622 l->llc_dsap = l->llc_ssap = 0; 623 /* Fall through to */ 624 case LLC_TEST: 625 case LLC_TEST_P: 626 { 627 struct sockaddr sa; 628 struct arpcom *ac; 629 struct iso88025_sockaddr_data *th2; 630 int i; 631 u_char c; 632 633 c = l->llc_dsap; 634 635 if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 636 printf("iso88025_input: dropping source routed LLC_TEST\n"); 637 goto dropanyway; 638 } 639 l->llc_dsap = l->llc_ssap; 640 l->llc_ssap = c; 641 if (m->m_flags & (M_BCAST | M_MCAST)) 642 bcopy((caddr_t)IF_LLADDR(ifp), 643 (caddr_t)th->iso88025_dhost, 644 ISO88025_ADDR_LEN); 645 sa.sa_family = AF_UNSPEC; 646 sa.sa_len = sizeof(sa); 647 th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 648 for (i = 0; i < ISO88025_ADDR_LEN; i++) { 649 th2->ether_shost[i] = c = th->iso88025_dhost[i]; 650 th2->ether_dhost[i] = th->iso88025_dhost[i] = 651 th->iso88025_shost[i]; 652 th->iso88025_shost[i] = c; 653 } 654 th2->ac = TR_AC; 655 th2->fc = TR_LLC_FRAME; 656 ifp->if_output(ifp, m, &sa, NULL); 657 return; 658 } 659 default: 660 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 661 ifp->if_noproto++; 662 goto dropanyway; 663 break; 664 } 665 break; 666#endif /* ISO */ 667 default: 668 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 669 ifp->if_noproto++; 670 goto dropanyway; 671 break; 672 } 673 674 M_SETFIB(m, ifp->if_fib); 675 netisr_dispatch(isr, m); 676 return; 677 678dropanyway: 679 ifp->if_iqdrops++; 680 if (m) 681 m_freem(m); 682 return; 683} 684 685static int 686iso88025_resolvemulti (ifp, llsa, sa) 687 struct ifnet *ifp; 688 struct sockaddr **llsa; 689 struct sockaddr *sa; 690{ 691 struct sockaddr_dl *sdl; 692#ifdef INET 693 struct sockaddr_in *sin; 694#endif 695#ifdef INET6 696 struct sockaddr_in6 *sin6; 697#endif 698 u_char *e_addr; 699 700 switch(sa->sa_family) { 701 case AF_LINK: 702 /* 703 * No mapping needed. Just check that it's a valid MC address. 704 */ 705 sdl = (struct sockaddr_dl *)sa; 706 e_addr = LLADDR(sdl); 707 if ((e_addr[0] & 1) != 1) { 708 return (EADDRNOTAVAIL); 709 } 710 *llsa = 0; 711 return (0); 712 713#ifdef INET 714 case AF_INET: 715 sin = (struct sockaddr_in *)sa; 716 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 717 return (EADDRNOTAVAIL); 718 } 719 sdl = malloc(sizeof *sdl, M_IFMADDR, 720 M_NOWAIT|M_ZERO); 721 if (sdl == NULL) 722 return (ENOMEM); 723 sdl->sdl_len = sizeof *sdl; 724 sdl->sdl_family = AF_LINK; 725 sdl->sdl_index = ifp->if_index; 726 sdl->sdl_type = IFT_ISO88025; 727 sdl->sdl_alen = ISO88025_ADDR_LEN; 728 e_addr = LLADDR(sdl); 729 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 730 *llsa = (struct sockaddr *)sdl; 731 return (0); 732#endif 733#ifdef INET6 734 case AF_INET6: 735 sin6 = (struct sockaddr_in6 *)sa; 736 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 737 /* 738 * An IP6 address of 0 means listen to all 739 * of the Ethernet multicast address used for IP6. 740 * (This is used for multicast routers.) 741 */ 742 ifp->if_flags |= IFF_ALLMULTI; 743 *llsa = 0; 744 return (0); 745 } 746 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 747 return (EADDRNOTAVAIL); 748 } 749 sdl = malloc(sizeof *sdl, M_IFMADDR, 750 M_NOWAIT|M_ZERO); 751 if (sdl == NULL) 752 return (ENOMEM); 753 sdl->sdl_len = sizeof *sdl; 754 sdl->sdl_family = AF_LINK; 755 sdl->sdl_index = ifp->if_index; 756 sdl->sdl_type = IFT_ISO88025; 757 sdl->sdl_alen = ISO88025_ADDR_LEN; 758 e_addr = LLADDR(sdl); 759 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 760 *llsa = (struct sockaddr *)sdl; 761 return (0); 762#endif 763 764 default: 765 /* 766 * Well, the text isn't quite right, but it's the name 767 * that counts... 768 */ 769 return (EAFNOSUPPORT); 770 } 771 772 return (0); 773} 774 775static MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals"); 776 777static void* 778iso88025_alloc(u_char type, struct ifnet *ifp) 779{ 780 struct arpcom *ac; 781 782 ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO); 783 ac->ac_ifp = ifp; 784 785 return (ac); 786} 787 788static void 789iso88025_free(void *com, u_char type) 790{ 791 792 free(com, M_ISO88025); 793} 794 795static int 796iso88025_modevent(module_t mod, int type, void *data) 797{ 798 799 switch (type) { 800 case MOD_LOAD: 801 if_register_com_alloc(IFT_ISO88025, iso88025_alloc, 802 iso88025_free); 803 break; 804 case MOD_UNLOAD: 805 if_deregister_com_alloc(IFT_ISO88025); 806 break; 807 default: 808 return EOPNOTSUPP; 809 } 810 811 return (0); 812} 813 814static moduledata_t iso88025_mod = { 815 "iso88025", 816 iso88025_modevent, 817 0 818}; 819 820DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 821MODULE_VERSION(iso88025, 1); 822