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