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