if_iso88025subr.c revision 249925
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: head/sys/net/if_iso88025subr.c 249925 2013-04-26 12:50:32Z glebius $ 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 m->m_pkthdr.header = (void *)th; 480 481 /* 482 * Discard packet if interface is not up. 483 */ 484 if (!((ifp->if_flags & IFF_UP) && 485 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 486 goto dropanyway; 487 488 /* 489 * Give bpf a chance at the packet. 490 */ 491 BPF_MTAP(ifp, m); 492 493 /* 494 * Interface marked for monitoring; discard packet. 495 */ 496 if (ifp->if_flags & IFF_MONITOR) { 497 m_freem(m); 498 return; 499 } 500 501#ifdef MAC 502 mac_ifnet_create_mbuf(ifp, m); 503#endif 504 505 /* 506 * Update interface statistics. 507 */ 508 ifp->if_ibytes += m->m_pkthdr.len; 509 getmicrotime(&ifp->if_lastchange); 510 511 /* 512 * Discard non local unicast packets when interface 513 * is in promiscuous mode. 514 */ 515 if ((ifp->if_flags & IFF_PROMISC) && 516 ((th->iso88025_dhost[0] & 1) == 0) && 517 (bcmp(IF_LLADDR(ifp), (caddr_t) th->iso88025_dhost, 518 ISO88025_ADDR_LEN) != 0)) 519 goto dropanyway; 520 521 /* 522 * Set mbuf flags for bcast/mcast. 523 */ 524 if (th->iso88025_dhost[0] & 1) { 525 if (bcmp(iso88025_broadcastaddr, th->iso88025_dhost, 526 ISO88025_ADDR_LEN) == 0) 527 m->m_flags |= M_BCAST; 528 else 529 m->m_flags |= M_MCAST; 530 ifp->if_imcasts++; 531 } 532 533 mac_hdr_len = ISO88025_HDR_LEN; 534 /* Check for source routing info */ 535 if (th->iso88025_shost[0] & TR_RII) 536 mac_hdr_len += TR_RCF_RIFLEN(th->rcf); 537 538 /* Strip off ISO88025 header. */ 539 m_adj(m, mac_hdr_len); 540 541 m = m_pullup(m, LLC_SNAPFRAMELEN); 542 if (m == 0) { 543 ifp->if_ierrors++; 544 goto dropanyway; 545 } 546 l = mtod(m, struct llc *); 547 548 switch (l->llc_dsap) { 549#ifdef IPX 550 case ETHERTYPE_IPX_8022: /* Thanks a bunch Novell */ 551 if ((l->llc_control != LLC_UI) || 552 (l->llc_ssap != ETHERTYPE_IPX_8022)) { 553 ifp->if_noproto++; 554 goto dropanyway; 555 } 556 557 th->iso88025_shost[0] &= ~(TR_RII); 558 m_adj(m, 3); 559 isr = NETISR_IPX; 560 break; 561#endif /* IPX */ 562 case LLC_SNAP_LSAP: { 563 u_int16_t type; 564 if ((l->llc_control != LLC_UI) || 565 (l->llc_ssap != LLC_SNAP_LSAP)) { 566 ifp->if_noproto++; 567 goto dropanyway; 568 } 569 570 if (l->llc_snap.org_code[0] != 0 || 571 l->llc_snap.org_code[1] != 0 || 572 l->llc_snap.org_code[2] != 0) { 573 ifp->if_noproto++; 574 goto dropanyway; 575 } 576 577 type = ntohs(l->llc_snap.ether_type); 578 m_adj(m, LLC_SNAPFRAMELEN); 579 switch (type) { 580#ifdef INET 581 case ETHERTYPE_IP: 582 th->iso88025_shost[0] &= ~(TR_RII); 583 if ((m = ip_fastforward(m)) == NULL) 584 return; 585 isr = NETISR_IP; 586 break; 587 588 case ETHERTYPE_ARP: 589 if (ifp->if_flags & IFF_NOARP) 590 goto dropanyway; 591 isr = NETISR_ARP; 592 break; 593#endif /* INET */ 594#ifdef IPX_SNAP /* XXX: Not supported! */ 595 case ETHERTYPE_IPX: 596 th->iso88025_shost[0] &= ~(TR_RII); 597 isr = NETISR_IPX; 598 break; 599#endif /* IPX_SNAP */ 600#ifdef INET6 601 case ETHERTYPE_IPV6: 602 th->iso88025_shost[0] &= ~(TR_RII); 603 isr = NETISR_IPV6; 604 break; 605#endif /* INET6 */ 606 default: 607 printf("iso88025_input: unexpected llc_snap ether_type 0x%02x\n", type); 608 ifp->if_noproto++; 609 goto dropanyway; 610 } 611 break; 612 } 613#ifdef ISO 614 case LLC_ISO_LSAP: 615 switch (l->llc_control) { 616 case LLC_UI: 617 ifp->if_noproto++; 618 goto dropanyway; 619 break; 620 case LLC_XID: 621 case LLC_XID_P: 622 if(m->m_len < ISO88025_ADDR_LEN) 623 goto dropanyway; 624 l->llc_window = 0; 625 l->llc_fid = 9; 626 l->llc_class = 1; 627 l->llc_dsap = l->llc_ssap = 0; 628 /* Fall through to */ 629 case LLC_TEST: 630 case LLC_TEST_P: 631 { 632 struct sockaddr sa; 633 struct arpcom *ac; 634 struct iso88025_sockaddr_data *th2; 635 int i; 636 u_char c; 637 638 c = l->llc_dsap; 639 640 if (th->iso88025_shost[0] & TR_RII) { /* XXX */ 641 printf("iso88025_input: dropping source routed LLC_TEST\n"); 642 goto dropanyway; 643 } 644 l->llc_dsap = l->llc_ssap; 645 l->llc_ssap = c; 646 if (m->m_flags & (M_BCAST | M_MCAST)) 647 bcopy((caddr_t)IF_LLADDR(ifp), 648 (caddr_t)th->iso88025_dhost, 649 ISO88025_ADDR_LEN); 650 sa.sa_family = AF_UNSPEC; 651 sa.sa_len = sizeof(sa); 652 th2 = (struct iso88025_sockaddr_data *)sa.sa_data; 653 for (i = 0; i < ISO88025_ADDR_LEN; i++) { 654 th2->ether_shost[i] = c = th->iso88025_dhost[i]; 655 th2->ether_dhost[i] = th->iso88025_dhost[i] = 656 th->iso88025_shost[i]; 657 th->iso88025_shost[i] = c; 658 } 659 th2->ac = TR_AC; 660 th2->fc = TR_LLC_FRAME; 661 ifp->if_output(ifp, m, &sa, NULL); 662 return; 663 } 664 default: 665 printf("iso88025_input: unexpected llc control 0x%02x\n", l->llc_control); 666 ifp->if_noproto++; 667 goto dropanyway; 668 break; 669 } 670 break; 671#endif /* ISO */ 672 default: 673 printf("iso88025_input: unknown dsap 0x%x\n", l->llc_dsap); 674 ifp->if_noproto++; 675 goto dropanyway; 676 break; 677 } 678 679 M_SETFIB(m, ifp->if_fib); 680 netisr_dispatch(isr, m); 681 return; 682 683dropanyway: 684 ifp->if_iqdrops++; 685 if (m) 686 m_freem(m); 687 return; 688} 689 690static int 691iso88025_resolvemulti (ifp, llsa, sa) 692 struct ifnet *ifp; 693 struct sockaddr **llsa; 694 struct sockaddr *sa; 695{ 696 struct sockaddr_dl *sdl; 697#ifdef INET 698 struct sockaddr_in *sin; 699#endif 700#ifdef INET6 701 struct sockaddr_in6 *sin6; 702#endif 703 u_char *e_addr; 704 705 switch(sa->sa_family) { 706 case AF_LINK: 707 /* 708 * No mapping needed. Just check that it's a valid MC address. 709 */ 710 sdl = (struct sockaddr_dl *)sa; 711 e_addr = LLADDR(sdl); 712 if ((e_addr[0] & 1) != 1) { 713 return (EADDRNOTAVAIL); 714 } 715 *llsa = 0; 716 return (0); 717 718#ifdef INET 719 case AF_INET: 720 sin = (struct sockaddr_in *)sa; 721 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) { 722 return (EADDRNOTAVAIL); 723 } 724 sdl = malloc(sizeof *sdl, M_IFMADDR, 725 M_NOWAIT|M_ZERO); 726 if (sdl == NULL) 727 return (ENOMEM); 728 sdl->sdl_len = sizeof *sdl; 729 sdl->sdl_family = AF_LINK; 730 sdl->sdl_index = ifp->if_index; 731 sdl->sdl_type = IFT_ISO88025; 732 sdl->sdl_alen = ISO88025_ADDR_LEN; 733 e_addr = LLADDR(sdl); 734 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 735 *llsa = (struct sockaddr *)sdl; 736 return (0); 737#endif 738#ifdef INET6 739 case AF_INET6: 740 sin6 = (struct sockaddr_in6 *)sa; 741 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 742 /* 743 * An IP6 address of 0 means listen to all 744 * of the Ethernet multicast address used for IP6. 745 * (This is used for multicast routers.) 746 */ 747 ifp->if_flags |= IFF_ALLMULTI; 748 *llsa = 0; 749 return (0); 750 } 751 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 752 return (EADDRNOTAVAIL); 753 } 754 sdl = malloc(sizeof *sdl, M_IFMADDR, 755 M_NOWAIT|M_ZERO); 756 if (sdl == NULL) 757 return (ENOMEM); 758 sdl->sdl_len = sizeof *sdl; 759 sdl->sdl_family = AF_LINK; 760 sdl->sdl_index = ifp->if_index; 761 sdl->sdl_type = IFT_ISO88025; 762 sdl->sdl_alen = ISO88025_ADDR_LEN; 763 e_addr = LLADDR(sdl); 764 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 765 *llsa = (struct sockaddr *)sdl; 766 return (0); 767#endif 768 769 default: 770 /* 771 * Well, the text isn't quite right, but it's the name 772 * that counts... 773 */ 774 return (EAFNOSUPPORT); 775 } 776 777 return (0); 778} 779 780static MALLOC_DEFINE(M_ISO88025, "arpcom", "802.5 interface internals"); 781 782static void* 783iso88025_alloc(u_char type, struct ifnet *ifp) 784{ 785 struct arpcom *ac; 786 787 ac = malloc(sizeof(struct arpcom), M_ISO88025, M_WAITOK | M_ZERO); 788 ac->ac_ifp = ifp; 789 790 return (ac); 791} 792 793static void 794iso88025_free(void *com, u_char type) 795{ 796 797 free(com, M_ISO88025); 798} 799 800static int 801iso88025_modevent(module_t mod, int type, void *data) 802{ 803 804 switch (type) { 805 case MOD_LOAD: 806 if_register_com_alloc(IFT_ISO88025, iso88025_alloc, 807 iso88025_free); 808 break; 809 case MOD_UNLOAD: 810 if_deregister_com_alloc(IFT_ISO88025); 811 break; 812 default: 813 return EOPNOTSUPP; 814 } 815 816 return (0); 817} 818 819static moduledata_t iso88025_mod = { 820 "iso88025", 821 iso88025_modevent, 822 0 823}; 824 825DECLARE_MODULE(iso88025, iso88025_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 826MODULE_VERSION(iso88025, 1); 827