if_fddisubr.c revision 185164
1/*- 2 * Copyright (c) 1995, 1996 3 * Matt Thomas <matt@3am-software.com>. All rights reserved. 4 * Copyright (c) 1982, 1989, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by the University of 18 * California, Berkeley and its contributors. 19 * 4. Neither the name of the University nor the names of its contributors 20 * may be used to endorse or promote products derived from this software 21 * without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33 * SUCH DAMAGE. 34 * 35 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp 36 * $FreeBSD: head/sys/net/if_fddisubr.c 185164 2008-11-22 07:35:45Z kmacy $ 37 */ 38 39#include "opt_atalk.h" 40#include "opt_inet.h" 41#include "opt_inet6.h" 42#include "opt_ipx.h" 43#include "opt_mac.h" 44 45#include <sys/param.h> 46#include <sys/systm.h> 47#include <sys/kernel.h> 48#include <sys/malloc.h> 49#include <sys/mbuf.h> 50#include <sys/module.h> 51#include <sys/socket.h> 52#include <sys/sockio.h> 53 54#include <net/if.h> 55#include <net/if_dl.h> 56#include <net/if_llc.h> 57#include <net/if_types.h> 58 59#include <net/ethernet.h> 60#include <net/netisr.h> 61#include <net/route.h> 62#include <net/bpf.h> 63#include <net/fddi.h> 64 65#if defined(INET) || defined(INET6) 66#include <netinet/in.h> 67#include <netinet/in_var.h> 68#include <netinet/if_ether.h> 69#endif 70#ifdef INET6 71#include <netinet6/nd6.h> 72#endif 73 74#ifdef IPX 75#include <netipx/ipx.h> 76#include <netipx/ipx_if.h> 77#endif 78 79#ifdef DECNET 80#include <netdnet/dn.h> 81#endif 82 83#ifdef NETATALK 84#include <netatalk/at.h> 85#include <netatalk/at_var.h> 86#include <netatalk/at_extern.h> 87 88extern u_char at_org_code[ 3 ]; 89extern u_char aarp_org_code[ 3 ]; 90#endif /* NETATALK */ 91 92#include <security/mac/mac_framework.h> 93 94static const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 95 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 96 97static int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 98 struct sockaddr *); 99static int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *, 100 struct rtentry *); 101static void fddi_input(struct ifnet *ifp, struct mbuf *m); 102 103#define senderr(e) do { error = (e); goto bad; } while (0) 104 105/* 106 * FDDI output routine. 107 * Encapsulate a packet of type family for the local net. 108 * Use trailer local net encapsulation if enough data in first 109 * packet leaves a multiple of 512 bytes of data in remainder. 110 * Assumes that ifp is actually pointer to arpcom structure. 111 */ 112static int 113fddi_output(ifp, m, dst, rt0) 114 struct ifnet *ifp; 115 struct mbuf *m; 116 struct sockaddr *dst; 117 struct rtentry *rt0; 118{ 119 u_int16_t type; 120 int loop_copy = 0, error = 0, hdrcmplt = 0; 121 u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 122 struct fddi_header *fh; 123 124#ifdef MAC 125 error = mac_ifnet_check_transmit(ifp, m); 126 if (error) 127 senderr(error); 128#endif 129 130 if (ifp->if_flags & IFF_MONITOR) 131 senderr(ENETDOWN); 132 if (!((ifp->if_flags & IFF_UP) && 133 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 134 senderr(ENETDOWN); 135 getmicrotime(&ifp->if_lastchange); 136 137 switch (dst->sa_family) { 138#ifdef INET 139 case AF_INET: { 140 error = arpresolve(ifp, rt0, m, dst, edst); 141 if (error) 142 return (error == EWOULDBLOCK ? 0 : error); 143 type = htons(ETHERTYPE_IP); 144 break; 145 } 146 case AF_ARP: 147 { 148 struct arphdr *ah; 149 ah = mtod(m, struct arphdr *); 150 ah->ar_hrd = htons(ARPHRD_ETHER); 151 152 loop_copy = -1; /* if this is for us, don't do it */ 153 154 switch (ntohs(ah->ar_op)) { 155 case ARPOP_REVREQUEST: 156 case ARPOP_REVREPLY: 157 type = htons(ETHERTYPE_REVARP); 158 break; 159 case ARPOP_REQUEST: 160 case ARPOP_REPLY: 161 default: 162 type = htons(ETHERTYPE_ARP); 163 break; 164 } 165 166 if (m->m_flags & M_BCAST) 167 bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); 168 else 169 bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); 170 171 } 172 break; 173#endif /* INET */ 174#ifdef INET6 175 case AF_INET6: 176 error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); 177 if (error) 178 return (error); /* Something bad happened */ 179 type = htons(ETHERTYPE_IPV6); 180 break; 181#endif /* INET6 */ 182#ifdef IPX 183 case AF_IPX: 184 type = htons(ETHERTYPE_IPX); 185 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 186 (caddr_t)edst, FDDI_ADDR_LEN); 187 break; 188#endif /* IPX */ 189#ifdef NETATALK 190 case AF_APPLETALK: { 191 struct at_ifaddr *aa; 192 if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst)) 193 return (0); 194 /* 195 * ifaddr is the first thing in at_ifaddr 196 */ 197 if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 198 goto bad; 199 200 /* 201 * In the phase 2 case, we need to prepend an mbuf for the llc header. 202 * Since we must preserve the value of m, which is passed to us by 203 * value, we m_copy() the first mbuf, and use it for our llc header. 204 */ 205 if (aa->aa_flags & AFA_PHASE2) { 206 struct llc llc; 207 208 M_PREPEND(m, LLC_SNAPFRAMELEN, M_WAIT); 209 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 210 llc.llc_control = LLC_UI; 211 bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 212 llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 213 bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 214 type = 0; 215 } else { 216 type = htons(ETHERTYPE_AT); 217 } 218 break; 219 } 220#endif /* NETATALK */ 221 222 case pseudo_AF_HDRCMPLT: 223 { 224 struct ether_header *eh; 225 hdrcmplt = 1; 226 eh = (struct ether_header *)dst->sa_data; 227 bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 228 /* FALLTHROUGH */ 229 } 230 231 case AF_UNSPEC: 232 { 233 struct ether_header *eh; 234 loop_copy = -1; 235 eh = (struct ether_header *)dst->sa_data; 236 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 237 if (*edst & 1) 238 m->m_flags |= (M_BCAST|M_MCAST); 239 type = eh->ether_type; 240 break; 241 } 242 243 case AF_IMPLINK: 244 { 245 fh = mtod(m, struct fddi_header *); 246 error = EPROTONOSUPPORT; 247 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 248 case FDDIFC_LLC_ASYNC: { 249 /* legal priorities are 0 through 7 */ 250 if ((fh->fddi_fc & FDDIFC_Z) > 7) 251 goto bad; 252 break; 253 } 254 case FDDIFC_LLC_SYNC: { 255 /* FDDIFC_Z bits reserved, must be zero */ 256 if (fh->fddi_fc & FDDIFC_Z) 257 goto bad; 258 break; 259 } 260 case FDDIFC_SMT: { 261 /* FDDIFC_Z bits must be non zero */ 262 if ((fh->fddi_fc & FDDIFC_Z) == 0) 263 goto bad; 264 break; 265 } 266 default: { 267 /* anything else is too dangerous */ 268 goto bad; 269 } 270 } 271 error = 0; 272 if (fh->fddi_dhost[0] & 1) 273 m->m_flags |= (M_BCAST|M_MCAST); 274 goto queue_it; 275 } 276 default: 277 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 278 senderr(EAFNOSUPPORT); 279 } 280 281 /* 282 * Add LLC header. 283 */ 284 if (type != 0) { 285 struct llc *l; 286 M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 287 if (m == 0) 288 senderr(ENOBUFS); 289 l = mtod(m, struct llc *); 290 l->llc_control = LLC_UI; 291 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 292 l->llc_snap.org_code[0] = 293 l->llc_snap.org_code[1] = 294 l->llc_snap.org_code[2] = 0; 295 l->llc_snap.ether_type = htons(type); 296 } 297 298 /* 299 * Add local net header. If no space in first mbuf, 300 * allocate another. 301 */ 302 M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 303 if (m == 0) 304 senderr(ENOBUFS); 305 fh = mtod(m, struct fddi_header *); 306 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 307 bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 308 queue_it: 309 if (hdrcmplt) 310 bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 311 else 312 bcopy(IF_LLADDR(ifp), (caddr_t)fh->fddi_shost, 313 FDDI_ADDR_LEN); 314 315 /* 316 * If a simplex interface, and the packet is being sent to our 317 * Ethernet address or a broadcast address, loopback a copy. 318 * XXX To make a simplex device behave exactly like a duplex 319 * device, we should copy in the case of sending to our own 320 * ethernet address (thus letting the original actually appear 321 * on the wire). However, we don't do that here for security 322 * reasons and compatibility with the original behavior. 323 */ 324 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 325 if ((m->m_flags & M_BCAST) || (loop_copy > 0)) { 326 struct mbuf *n; 327 n = m_copy(m, 0, (int)M_COPYALL); 328 (void) if_simloop(ifp, n, dst->sa_family, 329 FDDI_HDR_LEN); 330 } else if (bcmp(fh->fddi_dhost, fh->fddi_shost, 331 FDDI_ADDR_LEN) == 0) { 332 (void) if_simloop(ifp, m, dst->sa_family, 333 FDDI_HDR_LEN); 334 return (0); /* XXX */ 335 } 336 } 337 338 error = (ifp->if_transmit)(ifp, m); 339 if (error) 340 ifp->if_oerrors++; 341 342 return (error); 343 344bad: 345 ifp->if_oerrors++; 346 if (m) 347 m_freem(m); 348 return (error); 349} 350 351/* 352 * Process a received FDDI packet. 353 */ 354static void 355fddi_input(ifp, m) 356 struct ifnet *ifp; 357 struct mbuf *m; 358{ 359 int isr; 360 struct llc *l; 361 struct fddi_header *fh; 362 363 /* 364 * Do consistency checks to verify assumptions 365 * made by code past this point. 366 */ 367 if ((m->m_flags & M_PKTHDR) == 0) { 368 if_printf(ifp, "discard frame w/o packet header\n"); 369 ifp->if_ierrors++; 370 m_freem(m); 371 return; 372 } 373 if (m->m_pkthdr.rcvif == NULL) { 374 if_printf(ifp, "discard frame w/o interface pointer\n"); 375 ifp->if_ierrors++; 376 m_freem(m); 377 return; 378 } 379 380 m = m_pullup(m, FDDI_HDR_LEN); 381 if (m == NULL) { 382 ifp->if_ierrors++; 383 goto dropanyway; 384 } 385 fh = mtod(m, struct fddi_header *); 386 m->m_pkthdr.header = (void *)fh; 387 388 /* 389 * Discard packet if interface is not up. 390 */ 391 if (!((ifp->if_flags & IFF_UP) && 392 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 393 goto dropanyway; 394 395 /* 396 * Give bpf a chance at the packet. 397 */ 398 BPF_MTAP(ifp, m); 399 400 /* 401 * Interface marked for monitoring; discard packet. 402 */ 403 if (ifp->if_flags & IFF_MONITOR) { 404 m_freem(m); 405 return; 406 } 407 408#ifdef MAC 409 mac_ifnet_create_mbuf(ifp, m); 410#endif 411 412 /* 413 * Update interface statistics. 414 */ 415 ifp->if_ibytes += m->m_pkthdr.len; 416 getmicrotime(&ifp->if_lastchange); 417 418 /* 419 * Discard non local unicast packets when interface 420 * is in promiscuous mode. 421 */ 422 if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 423 (bcmp(IF_LLADDR(ifp), (caddr_t)fh->fddi_dhost, 424 FDDI_ADDR_LEN) != 0)) 425 goto dropanyway; 426 427 /* 428 * Set mbuf flags for bcast/mcast. 429 */ 430 if (fh->fddi_dhost[0] & 1) { 431 if (bcmp(ifp->if_broadcastaddr, fh->fddi_dhost, 432 FDDI_ADDR_LEN) == 0) 433 m->m_flags |= M_BCAST; 434 else 435 m->m_flags |= M_MCAST; 436 ifp->if_imcasts++; 437 } 438 439#ifdef M_LINK0 440 /* 441 * If this has a LLC priority of 0, then mark it so upper 442 * layers have a hint that it really came via a FDDI/Ethernet 443 * bridge. 444 */ 445 if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 446 m->m_flags |= M_LINK0; 447#endif 448 449 /* Strip off FDDI header. */ 450 m_adj(m, FDDI_HDR_LEN); 451 452 m = m_pullup(m, LLC_SNAPFRAMELEN); 453 if (m == 0) { 454 ifp->if_ierrors++; 455 goto dropanyway; 456 } 457 l = mtod(m, struct llc *); 458 459 switch (l->llc_dsap) { 460 case LLC_SNAP_LSAP: 461 { 462 u_int16_t type; 463 if ((l->llc_control != LLC_UI) || 464 (l->llc_ssap != LLC_SNAP_LSAP)) { 465 ifp->if_noproto++; 466 goto dropanyway; 467 } 468#ifdef NETATALK 469 if (bcmp(&(l->llc_snap.org_code)[0], at_org_code, 470 sizeof(at_org_code)) == 0 && 471 ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 472 isr = NETISR_ATALK2; 473 m_adj(m, LLC_SNAPFRAMELEN); 474 break; 475 } 476 477 if (bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 478 sizeof(aarp_org_code)) == 0 && 479 ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 480 m_adj(m, LLC_SNAPFRAMELEN); 481 isr = NETISR_AARP; 482 break; 483 } 484#endif /* NETATALK */ 485 if (l->llc_snap.org_code[0] != 0 || 486 l->llc_snap.org_code[1] != 0 || 487 l->llc_snap.org_code[2] != 0) { 488 ifp->if_noproto++; 489 goto dropanyway; 490 } 491 492 type = ntohs(l->llc_snap.ether_type); 493 m_adj(m, LLC_SNAPFRAMELEN); 494 495 switch (type) { 496#ifdef INET 497 case ETHERTYPE_IP: 498 if ((m = ip_fastforward(m)) == NULL) 499 return; 500 isr = NETISR_IP; 501 break; 502 503 case ETHERTYPE_ARP: 504 if (ifp->if_flags & IFF_NOARP) 505 goto dropanyway; 506 isr = NETISR_ARP; 507 break; 508#endif 509#ifdef INET6 510 case ETHERTYPE_IPV6: 511 isr = NETISR_IPV6; 512 break; 513#endif 514#ifdef IPX 515 case ETHERTYPE_IPX: 516 isr = NETISR_IPX; 517 break; 518#endif 519#ifdef DECNET 520 case ETHERTYPE_DECNET: 521 isr = NETISR_DECNET; 522 break; 523#endif 524#ifdef NETATALK 525 case ETHERTYPE_AT: 526 isr = NETISR_ATALK1; 527 break; 528 case ETHERTYPE_AARP: 529 isr = NETISR_AARP; 530 break; 531#endif /* NETATALK */ 532 default: 533 /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 534 ifp->if_noproto++; 535 goto dropanyway; 536 } 537 break; 538 } 539 540 default: 541 /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 542 ifp->if_noproto++; 543 goto dropanyway; 544 } 545 netisr_dispatch(isr, m); 546 return; 547 548dropanyway: 549 ifp->if_iqdrops++; 550 if (m) 551 m_freem(m); 552 return; 553} 554 555/* 556 * Perform common duties while attaching to interface list 557 */ 558void 559fddi_ifattach(ifp, lla, bpf) 560 struct ifnet *ifp; 561 const u_int8_t *lla; 562 int bpf; 563{ 564 struct ifaddr *ifa; 565 struct sockaddr_dl *sdl; 566 567 ifp->if_type = IFT_FDDI; 568 ifp->if_addrlen = FDDI_ADDR_LEN; 569 ifp->if_hdrlen = 21; 570 571 if_attach(ifp); /* Must be called before additional assignments */ 572 573 ifp->if_mtu = FDDIMTU; 574 ifp->if_output = fddi_output; 575 ifp->if_input = fddi_input; 576 ifp->if_resolvemulti = fddi_resolvemulti; 577 ifp->if_broadcastaddr = fddibroadcastaddr; 578 ifp->if_baudrate = 100000000; 579#ifdef IFF_NOTRAILERS 580 ifp->if_flags |= IFF_NOTRAILERS; 581#endif 582 ifa = ifp->if_addr; 583 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 584 585 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 586 sdl->sdl_type = IFT_FDDI; 587 sdl->sdl_alen = ifp->if_addrlen; 588 bcopy(lla, LLADDR(sdl), ifp->if_addrlen); 589 590 if (bpf) 591 bpfattach(ifp, DLT_FDDI, FDDI_HDR_LEN); 592 593 return; 594} 595 596void 597fddi_ifdetach(ifp, bpf) 598 struct ifnet *ifp; 599 int bpf; 600{ 601 602 if (bpf) 603 bpfdetach(ifp); 604 605 if_detach(ifp); 606 607 return; 608} 609 610int 611fddi_ioctl (ifp, command, data) 612 struct ifnet *ifp; 613 int command; 614 caddr_t data; 615{ 616 struct ifaddr *ifa; 617 struct ifreq *ifr; 618 int error; 619 620 ifa = (struct ifaddr *) data; 621 ifr = (struct ifreq *) data; 622 error = 0; 623 624 switch (command) { 625 case SIOCSIFADDR: 626 ifp->if_flags |= IFF_UP; 627 628 switch (ifa->ifa_addr->sa_family) { 629#ifdef INET 630 case AF_INET: /* before arpwhohas */ 631 ifp->if_init(ifp->if_softc); 632 arp_ifinit(ifp, ifa); 633 break; 634#endif 635#ifdef IPX 636 /* 637 * XXX - This code is probably wrong 638 */ 639 case AF_IPX: { 640 struct ipx_addr *ina; 641 642 ina = &(IA_SIPX(ifa)->sipx_addr); 643 644 if (ipx_nullhost(*ina)) { 645 ina->x_host = *(union ipx_host *) 646 IF_LLADDR(ifp); 647 } else { 648 bcopy((caddr_t) ina->x_host.c_host, 649 (caddr_t) IF_LLADDR(ifp), 650 ETHER_ADDR_LEN); 651 } 652 653 /* 654 * Set new address 655 */ 656 ifp->if_init(ifp->if_softc); 657 } 658 break; 659#endif 660 default: 661 ifp->if_init(ifp->if_softc); 662 break; 663 } 664 break; 665 case SIOCGIFADDR: { 666 struct sockaddr *sa; 667 668 sa = (struct sockaddr *) & ifr->ifr_data; 669 bcopy(IF_LLADDR(ifp), 670 (caddr_t) sa->sa_data, FDDI_ADDR_LEN); 671 672 } 673 break; 674 case SIOCSIFMTU: 675 /* 676 * Set the interface MTU. 677 */ 678 if (ifr->ifr_mtu > FDDIMTU) { 679 error = EINVAL; 680 } else { 681 ifp->if_mtu = ifr->ifr_mtu; 682 } 683 break; 684 default: 685 error = EINVAL; 686 break; 687 } 688 689 return (error); 690} 691 692static int 693fddi_resolvemulti(ifp, llsa, sa) 694 struct ifnet *ifp; 695 struct sockaddr **llsa; 696 struct sockaddr *sa; 697{ 698 struct sockaddr_dl *sdl; 699#ifdef INET 700 struct sockaddr_in *sin; 701#endif 702#ifdef INET6 703 struct sockaddr_in6 *sin6; 704#endif 705 u_char *e_addr; 706 707 switch(sa->sa_family) { 708 case AF_LINK: 709 /* 710 * No mapping needed. Just check that it's a valid MC address. 711 */ 712 sdl = (struct sockaddr_dl *)sa; 713 e_addr = LLADDR(sdl); 714 if ((e_addr[0] & 1) != 1) 715 return (EADDRNOTAVAIL); 716 *llsa = 0; 717 return (0); 718 719#ifdef INET 720 case AF_INET: 721 sin = (struct sockaddr_in *)sa; 722 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 723 return (EADDRNOTAVAIL); 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_FDDI; 732 sdl->sdl_nlen = 0; 733 sdl->sdl_alen = FDDI_ADDR_LEN; 734 sdl->sdl_slen = 0; 735 e_addr = LLADDR(sdl); 736 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 737 *llsa = (struct sockaddr *)sdl; 738 return (0); 739#endif 740#ifdef INET6 741 case AF_INET6: 742 sin6 = (struct sockaddr_in6 *)sa; 743 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 744 /* 745 * An IP6 address of 0 means listen to all 746 * of the Ethernet multicast address used for IP6. 747 * (This is used for multicast routers.) 748 */ 749 ifp->if_flags |= IFF_ALLMULTI; 750 *llsa = 0; 751 return (0); 752 } 753 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 754 return (EADDRNOTAVAIL); 755 sdl = malloc(sizeof *sdl, M_IFMADDR, 756 M_NOWAIT | M_ZERO); 757 if (sdl == NULL) 758 return (ENOMEM); 759 sdl->sdl_len = sizeof *sdl; 760 sdl->sdl_family = AF_LINK; 761 sdl->sdl_index = ifp->if_index; 762 sdl->sdl_type = IFT_FDDI; 763 sdl->sdl_nlen = 0; 764 sdl->sdl_alen = FDDI_ADDR_LEN; 765 sdl->sdl_slen = 0; 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 783static moduledata_t fddi_mod = { 784 "fddi", /* module name */ 785 NULL, /* event handler */ 786 0 /* extra data */ 787}; 788 789DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 790MODULE_VERSION(fddi, 1); 791