if_fddisubr.c revision 148887
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 148887 2005-08-09 10:20:02Z rwatson $ 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/mac.h> 49#include <sys/malloc.h> 50#include <sys/mbuf.h> 51#include <sys/module.h> 52#include <sys/socket.h> 53#include <sys/sockio.h> 54 55#include <net/if.h> 56#include <net/if_dl.h> 57#include <net/if_llc.h> 58#include <net/if_types.h> 59 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 92static const u_char fddibroadcastaddr[FDDI_ADDR_LEN] = 93 { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; 94 95static int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 96 struct sockaddr *); 97static int fddi_output(struct ifnet *, struct mbuf *, struct sockaddr *, 98 struct rtentry *); 99static void fddi_input(struct ifnet *ifp, struct mbuf *m); 100 101#define senderr(e) do { error = (e); goto bad; } while (0) 102 103/* 104 * FDDI output routine. 105 * Encapsulate a packet of type family for the local net. 106 * Use trailer local net encapsulation if enough data in first 107 * packet leaves a multiple of 512 bytes of data in remainder. 108 * Assumes that ifp is actually pointer to arpcom structure. 109 */ 110static int 111fddi_output(ifp, m, dst, rt0) 112 struct ifnet *ifp; 113 struct mbuf *m; 114 struct sockaddr *dst; 115 struct rtentry *rt0; 116{ 117 u_int16_t type; 118 int loop_copy = 0, error = 0, hdrcmplt = 0; 119 u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 120 struct fddi_header *fh; 121 122#ifdef MAC 123 error = mac_check_ifnet_transmit(ifp, m); 124 if (error) 125 senderr(error); 126#endif 127 128 if (ifp->if_flags & IFF_MONITOR) 129 senderr(ENETDOWN); 130 if (!((ifp->if_flags & IFF_UP) && 131 (ifp->if_drv_flags & IFF_DRV_RUNNING))) 132 senderr(ENETDOWN); 133 getmicrotime(&ifp->if_lastchange); 134 135 switch (dst->sa_family) { 136#ifdef INET 137 case AF_INET: { 138 error = arpresolve(ifp, rt0, m, dst, edst); 139 if (error) 140 return (error == EWOULDBLOCK ? 0 : error); 141 type = htons(ETHERTYPE_IP); 142 break; 143 } 144 case AF_ARP: 145 { 146 struct arphdr *ah; 147 ah = mtod(m, struct arphdr *); 148 ah->ar_hrd = htons(ARPHRD_ETHER); 149 150 loop_copy = -1; /* if this is for us, don't do it */ 151 152 switch (ntohs(ah->ar_op)) { 153 case ARPOP_REVREQUEST: 154 case ARPOP_REVREPLY: 155 type = htons(ETHERTYPE_REVARP); 156 break; 157 case ARPOP_REQUEST: 158 case ARPOP_REPLY: 159 default: 160 type = htons(ETHERTYPE_ARP); 161 break; 162 } 163 164 if (m->m_flags & M_BCAST) 165 bcopy(ifp->if_broadcastaddr, edst, FDDI_ADDR_LEN); 166 else 167 bcopy(ar_tha(ah), edst, FDDI_ADDR_LEN); 168 169 } 170 break; 171#endif /* INET */ 172#ifdef INET6 173 case AF_INET6: 174 error = nd6_storelladdr(ifp, rt0, m, dst, (u_char *)edst); 175 if (error) 176 return (error); /* Something bad happened */ 177 type = htons(ETHERTYPE_IPV6); 178 break; 179#endif /* INET6 */ 180#ifdef IPX 181 case AF_IPX: 182 type = htons(ETHERTYPE_IPX); 183 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 184 (caddr_t)edst, FDDI_ADDR_LEN); 185 break; 186#endif /* IPX */ 187#ifdef NETATALK 188 case AF_APPLETALK: { 189 struct at_ifaddr *aa; 190 if (!aarpresolve(ifp, m, (struct sockaddr_at *)dst, edst)) 191 return (0); 192 /* 193 * ifaddr is the first thing in at_ifaddr 194 */ 195 if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 196 goto bad; 197 198 /* 199 * In the phase 2 case, we need to prepend an mbuf for the llc header. 200 * Since we must preserve the value of m, which is passed to us by 201 * value, we m_copy() the first mbuf, and use it for our llc header. 202 */ 203 if (aa->aa_flags & AFA_PHASE2) { 204 struct llc llc; 205 206 M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT); 207 if (m == 0) 208 senderr(ENOBUFS); 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(IFP2ENADDR(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 IFQ_HANDOFF(ifp, m, error); 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_create_mbuf_from_ifnet(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(IFP2ENADDR(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 (ip_fastforward(m)) 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, bpf) 560 struct ifnet *ifp; 561 int bpf; 562{ 563 struct ifaddr *ifa; 564 struct sockaddr_dl *sdl; 565 566 ifp->if_type = IFT_FDDI; 567 ifp->if_addrlen = FDDI_ADDR_LEN; 568 ifp->if_hdrlen = 21; 569 570 if_attach(ifp); /* Must be called before additional assignments */ 571 572 ifp->if_mtu = FDDIMTU; 573 ifp->if_output = fddi_output; 574 ifp->if_input = fddi_input; 575 ifp->if_resolvemulti = fddi_resolvemulti; 576 ifp->if_broadcastaddr = fddibroadcastaddr; 577 ifp->if_baudrate = 100000000; 578#ifdef IFF_NOTRAILERS 579 ifp->if_flags |= IFF_NOTRAILERS; 580#endif 581 ifa = ifaddr_byindex(ifp->if_index); 582 if (ifa == NULL) { 583 if_printf(ifp, "%s() no lladdr!\n", __func__); 584 return; 585 } 586 587 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 588 sdl->sdl_type = IFT_FDDI; 589 sdl->sdl_alen = ifp->if_addrlen; 590 bcopy(IFP2ENADDR(ifp), 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 IFP2ENADDR(ifp); 649 } else { 650 bcopy((caddr_t) ina->x_host.c_host, 651 (caddr_t) IFP2ENADDR(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(IFP2ENADDR(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 struct sockaddr_in *sin; 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 MALLOC(sdl, struct sockaddr_dl *, 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 MALLOC(sdl, struct sockaddr_dl *, 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