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$ 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 struct sockaddr *sa; 205 206 sa = (struct sockaddr *) & ifr->ifr_data; 207 bcopy(IF_LLADDR(ifp), 208 (caddr_t) sa->sa_data, ISO88025_ADDR_LEN); 209 } 210 break; 211 212 case SIOCSIFMTU: 213 /* 214 * Set the interface MTU. 215 */ 216 if (ifr->ifr_mtu > ISO88025_MAX_MTU) { 217 error = EINVAL; 218 } else { 219 ifp->if_mtu = ifr->ifr_mtu; 220 } 221 break; 222 default: 223 error = EINVAL; /* XXX netbsd has ENOTTY??? */ 224 break; 225 } 226 227 return (error); 228} 229 230/* 231 * ISO88025 encapsulation 232 */ 233int 234iso88025_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 235 struct route *ro) 236{ 237 u_int16_t snap_type = 0; 238 int loop_copy = 0, error = 0, rif_len = 0; 239 u_char edst[ISO88025_ADDR_LEN]; 240 struct iso88025_header *th; 241 struct iso88025_header gen_th; 242 struct sockaddr_dl *sdl = NULL; 243 struct rtentry *rt0 = NULL; 244#if defined(INET) || defined(INET6) 245 struct llentry *lle; 246#endif 247 248 if (ro != NULL) 249 rt0 = ro->ro_rt; 250 251#ifdef MAC 252 error = mac_ifnet_check_transmit(ifp, m); 253 if (error) 254 senderr(error); 255#endif 256 257 if (ifp->if_flags & IFF_MONITOR) 258 senderr(ENETDOWN); 259 if (!((ifp->if_flags & IFF_UP) && 260 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 261 senderr(ENETDOWN); 262 getmicrotime(&ifp->if_lastchange); 263 264 /* Calculate routing info length based on arp table entry */ 265 /* XXX any better way to do this ? */ 266 267 if (rt0 && (sdl = (struct sockaddr_dl *)rt0->rt_gateway)) 268 if (SDL_ISO88025(sdl)->trld_rcf != 0) 269 rif_len = TR_RCF_RIFLEN(SDL_ISO88025(sdl)->trld_rcf); 270 271 /* Generate a generic 802.5 header for the packet */ 272 gen_th.ac = TR_AC; 273 gen_th.fc = TR_LLC_FRAME; 274 (void)memcpy((caddr_t)gen_th.iso88025_shost, IF_LLADDR(ifp), 275 ISO88025_ADDR_LEN); 276 if (rif_len) { 277 gen_th.iso88025_shost[0] |= TR_RII; 278 if (rif_len > 2) { 279 gen_th.rcf = SDL_ISO88025(sdl)->trld_rcf; 280 (void)memcpy((caddr_t)gen_th.rd, 281 (caddr_t)SDL_ISO88025(sdl)->trld_route, 282 rif_len - 2); 283 } 284 } 285 286 switch (dst->sa_family) { 287#ifdef INET 288 case AF_INET: 289 error = arpresolve(ifp, rt0, m, dst, edst, &lle); 290 if (error) 291 return (error == EWOULDBLOCK ? 0 : error); 292 snap_type = ETHERTYPE_IP; 293 break; 294 case AF_ARP: 295 { 296 struct arphdr *ah; 297 ah = mtod(m, struct arphdr *); 298 ah->ar_hrd = htons(ARPHRD_IEEE802); 299 300 loop_copy = -1; /* if this is for us, don't do it */ 301 302 switch(ntohs(ah->ar_op)) { 303 case ARPOP_REVREQUEST: 304 case ARPOP_REVREPLY: 305 snap_type = ETHERTYPE_REVARP; 306 break; 307 case ARPOP_REQUEST: 308 case ARPOP_REPLY: 309 default: 310 snap_type = ETHERTYPE_ARP; 311 break; 312 } 313 314 if (m->m_flags & M_BCAST) 315 bcopy(ifp->if_broadcastaddr, edst, ISO88025_ADDR_LEN); 316 else 317 bcopy(ar_tha(ah), edst, ISO88025_ADDR_LEN); 318 319 } 320 break; 321#endif /* INET */ 322#ifdef INET6 323 case AF_INET6: 324 error = nd6_storelladdr(ifp, m, dst, (u_char *)edst, &lle); 325 if (error) 326 return (error); 327 snap_type = ETHERTYPE_IPV6; 328 break; 329#endif /* INET6 */ 330#ifdef IPX 331 case AF_IPX: 332 { 333 u_int8_t *cp; 334 335 bcopy((caddr_t)&(satoipx_addr(dst).x_host), (caddr_t)edst, 336 ISO88025_ADDR_LEN); 337 338 M_PREPEND(m, 3, M_WAITOK); 339 m = m_pullup(m, 3); 340 if (m == 0) 341 senderr(ENOBUFS); 342 cp = mtod(m, u_int8_t *); 343 *cp++ = ETHERTYPE_IPX_8022; 344 *cp++ = ETHERTYPE_IPX_8022; 345 *cp++ = LLC_UI; 346 } 347 break; 348#endif /* IPX */ 349 case AF_UNSPEC: 350 { 351 const struct iso88025_sockaddr_data *sd; 352 /* 353 * For AF_UNSPEC sockaddr.sa_data must contain all of the 354 * mac information needed to send the packet. This allows 355 * full mac, llc, and source routing function to be controlled. 356 * llc and source routing information must already be in the 357 * mbuf provided, ac/fc are set in sa_data. sockaddr.sa_data 358 * should be an iso88025_sockaddr_data structure see iso88025.h 359 */ 360 loop_copy = -1; 361 sd = (const struct iso88025_sockaddr_data *)dst->sa_data; 362 gen_th.ac = sd->ac; 363 gen_th.fc = sd->fc; 364 (void)memcpy(edst, sd->ether_dhost, ISO88025_ADDR_LEN); 365 (void)memcpy(gen_th.iso88025_shost, sd->ether_shost, 366 ISO88025_ADDR_LEN); 367 rif_len = 0; 368 break; 369 } 370 default: 371 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 372 senderr(EAFNOSUPPORT); 373 break; 374 } 375 376 /* 377 * Add LLC header. 378 */ 379 if (snap_type != 0) { 380 struct llc *l; 381 M_PREPEND(m, LLC_SNAPFRAMELEN, M_NOWAIT); 382 if (m == 0) 383 senderr(ENOBUFS); 384 l = mtod(m, struct llc *); 385 l->llc_control = LLC_UI; 386 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 387 l->llc_snap.org_code[0] = 388 l->llc_snap.org_code[1] = 389 l->llc_snap.org_code[2] = 0; 390 l->llc_snap.ether_type = htons(snap_type); 391 } 392 393 /* 394 * Add local net header. If no space in first mbuf, 395 * allocate another. 396 */ 397 M_PREPEND(m, ISO88025_HDR_LEN + rif_len, M_NOWAIT); 398 if (m == 0) 399 senderr(ENOBUFS); 400 th = mtod(m, struct iso88025_header *); 401 bcopy((caddr_t)edst, (caddr_t)&gen_th.iso88025_dhost, ISO88025_ADDR_LEN); 402 403 /* Copy as much of the generic header as is needed into the mbuf */ 404 memcpy(th, &gen_th, ISO88025_HDR_LEN + rif_len); 405 406 /* 407 * If a simplex interface, and the packet is being sent to our 408 * Ethernet address or a broadcast address, loopback a copy. 409 * XXX To make a simplex device behave exactly like a duplex 410 * device, we should copy in the case of sending to our own 411 * ethernet address (thus letting the original actually appear 412 * on the wire). However, we don't do that here for security 413 * reasons and compatibility with the original behavior. 414 */ 415 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 416 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 417 struct mbuf *n; 418 n = m_copy(m, 0, (int)M_COPYALL); 419 (void) if_simloop(ifp, n, dst->sa_family, 420 ISO88025_HDR_LEN); 421 } else if (bcmp(th->iso88025_dhost, th->iso88025_shost, 422 ETHER_ADDR_LEN) == 0) { 423 (void) if_simloop(ifp, m, dst->sa_family, 424 ISO88025_HDR_LEN); 425 return(0); /* XXX */ 426 } 427 } 428 429 IFQ_HANDOFF_ADJ(ifp, m, ISO88025_HDR_LEN + LLC_SNAPFRAMELEN, error); 430 if (error) { 431 printf("iso88025_output: packet dropped QFULL.\n"); 432 ifp->if_oerrors++; 433 } 434 return (error); 435 436bad: 437 ifp->if_oerrors++; 438 if (m) 439 m_freem(m); 440 return (error); 441} 442 443/* 444 * ISO 88025 de-encapsulation 445 */ 446void 447iso88025_input(ifp, m) 448 struct ifnet *ifp; 449 struct mbuf *m; 450{ 451 struct iso88025_header *th; 452 struct llc *l; 453 int isr; 454 int mac_hdr_len; 455 456 /* 457 * Do consistency checks to verify assumptions 458 * made by code past this point. 459 */ 460 if ((m->m_flags & M_PKTHDR) == 0) { 461 if_printf(ifp, "discard frame w/o packet header\n"); 462 ifp->if_ierrors++; 463 m_freem(m); 464 return; 465 } 466 if (m->m_pkthdr.rcvif == NULL) { 467 if_printf(ifp, "discard frame w/o interface pointer\n"); 468 ifp->if_ierrors++; 469 m_freem(m); 470 return; 471 } 472 473 m = m_pullup(m, ISO88025_HDR_LEN); 474 if (m == NULL) { 475 ifp->if_ierrors++; 476 goto dropanyway; 477 } 478 th = mtod(m, struct iso88025_header *); 479 480 /* 481 * Discard packet if interface is not up. 482 */ 483 if (!((ifp->if_flags & IFF_UP) && 484 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 485 goto dropanyway; 486 487 /* 488 * Give bpf a chance at the packet. 489 */ 490 BPF_MTAP(ifp, m); 491 492 /* 493 * Interface marked for monitoring; discard packet. 494 */ 495 if (ifp->if_flags & IFF_MONITOR) { 496 m_freem(m); 497 return; 498 } 499 500#ifdef MAC 501 mac_ifnet_create_mbuf(ifp, m); 502#endif 503 504 /* 505 * Update interface statistics. 506 */ 507 ifp->if_ibytes += m->m_pkthdr.len; 508 getmicrotime(&ifp->if_lastchange); 509 510 /* 511 * Discard non local unicast packets when interface 512 * is in promiscuous mode. 513 */ 514 if ((ifp->if_flags & IFF_PROMISC) && 515 ((th->iso88025_dhost[0] & 1) == 0) && 516 (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost, 517 ISO88025_ADDR_LEN) != 0)) 518 goto dropanyway; 519 520 /* 521 * Set mbuf flags for bcast/mcast. 522 */ 523 if (th->iso88025_dhost[0] & 1) { 524 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost, 525 ISO88025_ADDR_LEN) == 0) 526 m->m_flags |= M_BCAST; 527 else 528 m->m_flags |= M_MCAST; 529 ifp->if_imcasts++; 530 } 531 532 mac_hdr_len = ISO88025_HDR_LEN; 533 /* Check for source routing info */ 534 if (th->iso88025_shost[0] & TR_RII) 535 mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 536 537 /* Strip off ISO88025 header. */ 538 m_adj(m, mac_hdr_len); 539 540 m = m_pullup(m, LLC_SNAPFRAMELEN); 541 if (m == 0) { 542 ifp->if_ierrors++; 543 goto dropanyway; 544 } 545 l = mtod(m, struct llc *); 546 547 switch (l->llc_dsap) { 548#ifdef IPX 549 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 550 if ((l->llc_control != LLC_UI) || 551 (l->llc_ssap != ETHERTYPE_IPX_8022)) { 552 ifp->if_noproto++; 553 goto dropanyway; 554 } 555 556 th->iso88025_shost[0] &= ~(TR_RII); 557 m_adj(m, 3); 558 isr = NETISR_IPX; 559 break; 560#endif /* IPX */ 561 case LLC_SNAP_LSAP: { 562 u_int16_t type; 563 if ((l->llc_control != LLC_UI) || 564 (l->llc_ssap != LLC_SNAP_LSAP)) { 565 ifp->if_noproto++; 566 goto dropanyway; 567 } 568 569 if (l->llc_snap.org_code[0] != 0 || 570 l->llc_snap.org_code[1] != 0 || 571 l->llc_snap.org_code[2] != 0) { 572 ifp->if_noproto++; 573 goto dropanyway; 574 } 575 576 type = ntohs(l->llc_snap.ether_type); 577 m_adj(m, LLC_SNAPFRAMELEN); 578 switch (type) { 579#ifdef INET 580 case ETHERTYPE_IP: 581 th->iso88025_shost[0] &= ~(TR_RII); 582 if ((m = ip_fastforward(m)) == NULL) 583 return; 584 isr = NETISR_IP; 585 break; 586 587 case ETHERTYPE_ARP: 588 if (ifp->if_flags & IFF_NOARP) 589 goto dropanyway; 590 isr = NETISR_ARP; 591 break; 592#endif /* INET */ 593#ifdef IPX_SNAP /* XXX: Not supported! */ 594 case ETHERTYPE_IPX: 595 th->iso88025_shost[0] &= ~(TR_RII); 596 isr = NETISR_IPX; 597 break; 598#endif /* IPX_SNAP */ 599#ifdef INET6 600 case ETHERTYPE_IPV6: 601 th->iso88025_shost[0] &= ~(TR_RII); 602 isr = NETISR_IPV6; 603 break; 604#endif /* INET6 */ 605 default: 606 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 607 ifp->if_noproto++; 608 goto dropanyway; 609 } 610 break; 611 } 612#ifdef ISO 613 case LLC_ISO_LSAP: 614 switch (l->llc_control) { 615 case LLC_UI: 616 ifp->if_noproto++; 617 goto dropanyway; 618 break; 619 case LLC_XID: 620 case LLC_XID_P: 621 if(m->m_len < ISO88025_ADDR_LEN) 622 goto dropanyway; 623 l->llc_window = 0; 624 l->llc_fid = 9; 625 l->llc_class = 1; 626 l->llc_dsap = l->llc_ssap = 0; 627 /* Fall through to */ 628 case LLC_TEST: 629 case LLC_TEST_P: 630 { 631 struct sockaddr sa; 632 struct arpcom *ac; 633 struct iso88025_sockaddr_data *th2; 634 int i; 635 u_char c; 636 637 c = l->llc_dsap; 638 639 if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 640 printf("iso88025_input: dropping source routed LLC_TEST\n"); 641 goto dropanyway; 642 } 643 l->llc_dsap = l->llc_ssap; 644 l->llc_ssap = c; 645 if (m->m_flags & (M_BCAST | M_MCAST)) 646 bcopy((caddr_t)IF_LLADDR(ifp), 647 (caddr_t)th->iso88025_dhost, 648 ISO88025_ADDR_LEN); 649 sa.sa_family = AF_UNSPEC; 650 sa.sa_len = sizeof(sa); 651 th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 652 for (i = 0; i < ISO88025_ADDR_LEN; i++) { 653 th2->ether_shost[i] = c = th->iso88025_dhost[i]; 654 th2->ether_dhost[i] = th->iso88025_dhost[i] = 655 th->iso88025_shost[i]; 656 th->iso88025_shost[i] = c; 657 } 658 th2->ac = TR_AC; 659 th2->fc = TR_LLC_FRAME; 660 ifp->if_output(ifp, m, &sa, NULL); 661 return; 662 } 663 default: 664 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 665 ifp->if_noproto++; 666 goto dropanyway; 667 break; 668 } 669 break; 670#endif /* ISO */ 671 default: 672 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 673 ifp->if_noproto++; 674 goto dropanyway; 675 break; 676 } 677 678 M_SETFIB(m, ifp->if_fib); 679 netisr_dispatch(isr, m); 680 return; 681 682dropanyway: 683 ifp->if_iqdrops++; 684 if (m) 685 m_freem(m); 686 return; 687} 688 689static int 690iso88025_resolvemulti (ifp, llsa, sa) 691 struct ifnet *ifp; 692 struct sockaddr **llsa; 693 struct sockaddr *sa; 694{ 695 struct sockaddr_dl *sdl; 696#ifdef INET 697 struct sockaddr_in *sin; 698#endif 699#ifdef INET6 700 struct sockaddr_in6 *sin6; 701#endif 702 u_char *e_addr; 703 704 switch(sa->sa_family) { 705 case AF_LINK: 706 /* 707 * No mapping needed. Just check that it's a valid MC address. 708 */ 709 sdl = (struct sockaddr_dl *)sa; 710 e_addr = LLADDR(sdl); 711 if ((e_addr[0] & 1) != 1) { 712 return (EADDRNOTAVAIL); 713 } 714 *llsa = 0; 715 return (0); 716 717#ifdef INET 718 case AF_INET: 719 sin = (struct sockaddr_in *)sa; 720 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 721 return (EADDRNOTAVAIL); 722 } 723 sdl = malloc(sizeof *sdl, M_IFMADDR, 724 M_NOWAIT|M_ZERO); 725 if (sdl == NULL) 726 return (ENOMEM); 727 sdl->sdl_len = sizeof *sdl; 728 sdl->sdl_family = AF_LINK; 729 sdl->sdl_index = ifp->if_index; 730 sdl->sdl_type = IFT_ISO88025; 731 sdl->sdl_alen = ISO88025_ADDR_LEN; 732 e_addr = LLADDR(sdl); 733 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 734 *llsa = (struct sockaddr *)sdl; 735 return (0); 736#endif 737#ifdef INET6 738 case AF_INET6: 739 sin6 = (struct sockaddr_in6 *)sa; 740 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 741 /* 742 * An IP6 address of 0 means listen to all 743 * of the Ethernet multicast address used for IP6. 744 * (This is used for multicast routers.) 745 */ 746 ifp->if_flags |= IFF_ALLMULTI; 747 *llsa = 0; 748 return (0); 749 } 750 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 751 return (EADDRNOTAVAIL); 752 } 753 sdl = malloc(sizeof *sdl, M_IFMADDR, 754 M_NOWAIT|M_ZERO); 755 if (sdl == NULL) 756 return (ENOMEM); 757 sdl->sdl_len = sizeof *sdl; 758 sdl->sdl_family = AF_LINK; 759 sdl->sdl_index = ifp->if_index; 760 sdl->sdl_type = IFT_ISO88025; 761 sdl->sdl_alen = ISO88025_ADDR_LEN; 762 e_addr = LLADDR(sdl); 763 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 764 *llsa = (struct sockaddr *)sdl; 765 return (0); 766#endif 767 768 default: 769 /* 770 * Well, the text isn't quite right, but it's the name 771 * that counts... 772 */ 773 return (EAFNOSUPPORT); 774 } 775 776 return (0); 777} 778 779static MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals"); 780 781static void* 782iso88025_alloc(u_char type, struct ifnet *ifp) 783{ 784 struct arpcom *ac; 785 786 ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO); 787 ac->ac_ifp = ifp; 788 789 return (ac); 790} 791 792static void 793iso88025_free(void *com, u_char type) 794{ 795 796 free(com, M_ISO88025); 797} 798 799static int 800iso88025_modevent(module_t mod, int type, void *data) 801{ 802 803 switch (type) { 804 case MOD_LOAD: 805 if_register_com_alloc(IFT_ISO88025, iso88025_alloc, 806 iso88025_free); 807 break; 808 case MOD_UNLOAD: 809 if_deregister_com_alloc(IFT_ISO88025); 810 break; 811 default: 812 return EOPNOTSUPP; 813 } 814 815 return (0); 816} 817 818static moduledata_t iso88025_mod = { 819 "iso88025", 820 iso88025_modevent, 821 0 822}; 823 824DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 825MODULE_VERSION(iso88025, 1); 826