if_fddisubr.c revision 93381
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 93381 2002-03-29 10:29:10Z mdodd $ 37 */ 38 39#include "opt_atalk.h" 40#include "opt_inet.h" 41#include "opt_inet6.h" 42#include "opt_ipx.h" 43 44#include <sys/param.h> 45#include <sys/systm.h> 46#include <sys/kernel.h> 47#include <sys/malloc.h> 48#include <sys/mbuf.h> 49#include <sys/module.h> 50#include <sys/socket.h> 51#include <sys/sockio.h> 52 53#include <net/if.h> 54#include <net/if_llc.h> 55#include <net/if_dl.h> 56#include <net/if_types.h> 57#include <net/netisr.h> 58#include <net/route.h> 59#include <net/bpf.h> 60#include <net/fddi.h> 61 62#if defined(INET) || defined(INET6) 63#include <netinet/in.h> 64#include <netinet/in_var.h> 65#include <netinet/if_ether.h> 66#endif 67#ifdef INET6 68#include <netinet6/nd6.h> 69#endif 70 71#ifdef IPX 72#include <netipx/ipx.h> 73#include <netipx/ipx_if.h> 74#endif 75 76#ifdef NS 77#include <netns/ns.h> 78#include <netns/ns_if.h> 79#endif 80 81#ifdef DECNET 82#include <netdnet/dn.h> 83#endif 84 85#ifdef NETATALK 86#include <netatalk/at.h> 87#include <netatalk/at_var.h> 88#include <netatalk/at_extern.h> 89 90extern u_char at_org_code[ 3 ]; 91extern u_char aarp_org_code[ 3 ]; 92#endif /* NETATALK */ 93 94static int fddi_resolvemulti(struct ifnet *, struct sockaddr **, 95 struct sockaddr *); 96 97#define IFP2AC(IFP) ((struct arpcom *)IFP) 98#define senderr(e) { error = (e); goto bad; } 99 100/* 101 * FDDI output routine. 102 * Encapsulate a packet of type family for the local net. 103 * Use trailer local net encapsulation if enough data in first 104 * packet leaves a multiple of 512 bytes of data in remainder. 105 * Assumes that ifp is actually pointer to arpcom structure. 106 */ 107int 108fddi_output(ifp, m, dst, rt0) 109 struct ifnet *ifp; 110 struct mbuf *m; 111 struct sockaddr *dst; 112 struct rtentry *rt0; 113{ 114 u_int16_t type; 115 int loop_copy = 0, error = 0, hdrcmplt = 0; 116 u_char esrc[FDDI_ADDR_LEN], edst[FDDI_ADDR_LEN]; 117 struct rtentry *rt; 118 struct fddi_header *fh; 119 struct arpcom *ac = IFP2AC(ifp); 120 121 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 122 senderr(ENETDOWN); 123 getmicrotime(&ifp->if_lastchange); 124 if ((rt = rt0) != NULL) { 125 if ((rt->rt_flags & RTF_UP) == 0) { 126 if ((rt0 = rt = rtalloc1(dst, 1, 0UL)) != NULL) 127 rt->rt_refcnt--; 128 else 129 senderr(EHOSTUNREACH); 130 } 131 if (rt->rt_flags & RTF_GATEWAY) { 132 if (rt->rt_gwroute == 0) 133 goto lookup; 134 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 135 rtfree(rt); rt = rt0; 136 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0UL); 137 if ((rt = rt->rt_gwroute) == 0) 138 senderr(EHOSTUNREACH); 139 } 140 } 141 if (rt->rt_flags & RTF_REJECT) 142 if (rt->rt_rmx.rmx_expire == 0 || 143 time_second < rt->rt_rmx.rmx_expire) 144 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 145 } 146 switch (dst->sa_family) { 147 148#ifdef INET 149 case AF_INET: { 150 if (!arpresolve(ifp, rt, m, dst, edst, rt0)) 151 return (0); /* if not yet resolved */ 152 type = htons(ETHERTYPE_IP); 153 break; 154 } 155#endif 156#ifdef INET6 157 case AF_INET6: 158 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst)) { 159 /* Something bad happened */ 160 return (0); 161 } 162 type = htons(ETHERTYPE_IPV6); 163 break; 164#endif 165#ifdef IPX 166 case AF_IPX: 167 type = htons(ETHERTYPE_IPX); 168 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host), 169 (caddr_t)edst, FDDI_ADDR_LEN); 170 break; 171#endif 172#ifdef NETATALK 173 case AF_APPLETALK: { 174 struct at_ifaddr *aa; 175 if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst)) 176 return (0); 177 /* 178 * ifaddr is the first thing in at_ifaddr 179 */ 180 if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0) 181 goto bad; 182 183 /* 184 * In the phase 2 case, we need to prepend an mbuf for the llc header. 185 * Since we must preserve the value of m, which is passed to us by 186 * value, we m_copy() the first mbuf, and use it for our llc header. 187 */ 188 if (aa->aa_flags & AFA_PHASE2) { 189 struct llc llc; 190 191 M_PREPEND(m, LLC_SNAPFRAMELEN, M_TRYWAIT); 192 if (m == 0) 193 senderr(ENOBUFS); 194 llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP; 195 llc.llc_control = LLC_UI; 196 bcopy(at_org_code, llc.llc_snap.org_code, sizeof(at_org_code)); 197 llc.llc_snap.ether_type = htons(ETHERTYPE_AT); 198 bcopy(&llc, mtod(m, caddr_t), LLC_SNAPFRAMELEN); 199 type = 0; 200 } else { 201 type = htons(ETHERTYPE_AT); 202 } 203 break; 204 } 205#endif /* NETATALK */ 206#ifdef NS 207 case AF_NS: 208 type = htons(ETHERTYPE_NS); 209 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host), 210 (caddr_t)edst, FDDI_ADDR_LEN); 211 break; 212#endif 213 214 case pseudo_AF_HDRCMPLT: 215 { 216 struct ether_header *eh; 217 hdrcmplt = 1; 218 eh = (struct ether_header *)dst->sa_data; 219 bcopy((caddr_t)eh->ether_shost, (caddr_t)esrc, FDDI_ADDR_LEN); 220 /* FALLTHROUGH */ 221 } 222 223 case AF_UNSPEC: 224 { 225 struct ether_header *eh; 226 loop_copy = -1; 227 eh = (struct ether_header *)dst->sa_data; 228 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, FDDI_ADDR_LEN); 229 if (*edst & 1) 230 m->m_flags |= (M_BCAST|M_MCAST); 231 type = eh->ether_type; 232 break; 233 } 234 235 case AF_IMPLINK: 236 { 237 fh = mtod(m, struct fddi_header *); 238 error = EPROTONOSUPPORT; 239 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) { 240 case FDDIFC_LLC_ASYNC: { 241 /* legal priorities are 0 through 7 */ 242 if ((fh->fddi_fc & FDDIFC_Z) > 7) 243 goto bad; 244 break; 245 } 246 case FDDIFC_LLC_SYNC: { 247 /* FDDIFC_Z bits reserved, must be zero */ 248 if (fh->fddi_fc & FDDIFC_Z) 249 goto bad; 250 break; 251 } 252 case FDDIFC_SMT: { 253 /* FDDIFC_Z bits must be non zero */ 254 if ((fh->fddi_fc & FDDIFC_Z) == 0) 255 goto bad; 256 break; 257 } 258 default: { 259 /* anything else is too dangerous */ 260 goto bad; 261 } 262 } 263 error = 0; 264 if (fh->fddi_dhost[0] & 1) 265 m->m_flags |= (M_BCAST|M_MCAST); 266 goto queue_it; 267 } 268 default: 269 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit, 270 dst->sa_family); 271 senderr(EAFNOSUPPORT); 272 } 273 274 /* 275 * Add LLC header. 276 */ 277 if (type != 0) { 278 struct llc *l; 279 M_PREPEND(m, LLC_SNAPFRAMELEN, M_DONTWAIT); 280 if (m == 0) 281 senderr(ENOBUFS); 282 l = mtod(m, struct llc *); 283 l->llc_control = LLC_UI; 284 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP; 285 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0; 286 bcopy((caddr_t)&type, (caddr_t)&l->llc_snap.ether_type, 287 sizeof(u_int16_t)); 288 } 289 290 /* 291 * Add local net header. If no space in first mbuf, 292 * allocate another. 293 */ 294 M_PREPEND(m, FDDI_HDR_LEN, M_DONTWAIT); 295 if (m == 0) 296 senderr(ENOBUFS); 297 fh = mtod(m, struct fddi_header *); 298 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4; 299 bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN); 300 queue_it: 301 if (hdrcmplt) 302 bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost, FDDI_ADDR_LEN); 303 else 304 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost, 305 FDDI_ADDR_LEN); 306 307 /* 308 * If a simplex interface, and the packet is being sent to our 309 * Ethernet address or a broadcast address, loopback a copy. 310 * XXX To make a simplex device behave exactly like a duplex 311 * device, we should copy in the case of sending to our own 312 * ethernet address (thus letting the original actually appear 313 * on the wire). However, we don't do that here for security 314 * reasons and compatibility with the original behavior. 315 */ 316 if ((ifp->if_flags & IFF_SIMPLEX) && (loop_copy != -1)) { 317 if ((m->m_flags & M_BCAST) || loop_copy) { 318 struct mbuf *n = m_copy(m, 0, (int)M_COPYALL); 319 320 (void) if_simloop(ifp, 321 n, dst->sa_family, FDDI_HDR_LEN); 322 } else if (bcmp(fh->fddi_dhost, 323 fh->fddi_shost, FDDI_ADDR_LEN) == 0) { 324 (void) if_simloop(ifp, 325 m, dst->sa_family, FDDI_HDR_LEN); 326 return (0); /* XXX */ 327 } 328 } 329 330 if (! IF_HANDOFF(&ifp->if_snd, m, ifp)) 331 senderr(ENOBUFS); 332 return (error); 333 334bad: 335 ifp->if_oerrors++; 336 if (m) 337 m_freem(m); 338 return (error); 339} 340 341/* 342 * Process a received FDDI packet; 343 * the packet is in the mbuf chain m without 344 * the fddi header, which is provided separately. 345 */ 346void 347fddi_input(ifp, fh, m) 348 struct ifnet *ifp; 349 struct fddi_header *fh; 350 struct mbuf *m; 351{ 352 struct ifqueue *inq; 353 struct llc *l; 354 355 /* 356 * Discard packet if interface is not up. 357 */ 358 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 359 goto dropanyway; 360 361 /* 362 * Discard non local unicast packets when interface 363 * is in promiscuous mode. 364 */ 365 if ((ifp->if_flags & IFF_PROMISC) && ((fh->fddi_dhost[0] & 1) == 0) && 366 (bcmp(IFP2AC(ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost, 367 FDDI_ADDR_LEN) != 0)) 368 goto dropanyway; 369 370 /* 371 * Set mbuf flags for bcast/mcast. 372 */ 373 if (fh->fddi_dhost[0] & 1) { 374 if (bcmp((caddr_t)ifp->if_broadcastaddr, 375 (caddr_t)fh->fddi_dhost, FDDI_ADDR_LEN) == 0) 376 m->m_flags |= M_BCAST; 377 else 378 m->m_flags |= M_MCAST; 379 ifp->if_imcasts++; 380 } 381 382 /* 383 * Update interface statistics. 384 */ 385 getmicrotime(&ifp->if_lastchange); 386 ifp->if_ibytes += (m->m_pkthdr.len + FDDI_HDR_LEN); 387 388#ifdef M_LINK0 389 /* 390 * If this has a LLC priority of 0, then mark it so upper 391 * layers have a hint that it really came via a FDDI/Ethernet 392 * bridge. 393 */ 394 if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0) 395 m->m_flags |= M_LINK0; 396#endif 397 398 m = m_pullup(m, sizeof(struct llc)); 399 if (m == 0) { 400 ifp->if_ierrors++; 401 goto dropanyway; 402 } 403 l = mtod(m, struct llc *); 404 405 switch (l->llc_dsap) { 406 case LLC_SNAP_LSAP: 407 { 408 u_int16_t type; 409 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP) { 410 ifp->if_noproto++; 411 goto dropanyway; 412 } 413#ifdef NETATALK 414 if (Bcmp(&(l->llc_snap.org_code)[0], at_org_code, 415 sizeof(at_org_code)) == 0 && 416 ntohs(l->llc_snap.ether_type) == ETHERTYPE_AT) { 417 inq = &atintrq2; 418 m_adj(m, LLC_SNAPFRAMELEN); 419 schednetisr(NETISR_ATALK); 420 break; 421 } 422 423 if (Bcmp(&(l->llc_snap.org_code)[0], aarp_org_code, 424 sizeof(aarp_org_code)) == 0 && 425 ntohs(l->llc_snap.ether_type) == ETHERTYPE_AARP) { 426 m_adj(m, LLC_SNAPFRAMELEN); 427 aarpinput(IFP2AC(ifp), m); /* XXX */ 428 return; 429 } 430#endif /* NETATALK */ 431 if (l->llc_snap.org_code[0] != 0 || 432 l->llc_snap.org_code[1] != 0 || 433 l->llc_snap.org_code[2] != 0) { 434 ifp->if_noproto++; 435 goto dropanyway; 436 } 437 438 type = ntohs(l->llc_snap.ether_type); 439 m_adj(m, LLC_SNAPFRAMELEN); 440 441 switch (type) { 442#ifdef INET 443 case ETHERTYPE_IP: 444 if (ipflow_fastforward(m)) 445 return; 446 schednetisr(NETISR_IP); 447 inq = &ipintrq; 448 break; 449 450 case ETHERTYPE_ARP: 451 if (ifp->if_flags & IFF_NOARP) 452 goto dropanyway; 453 schednetisr(NETISR_ARP); 454 inq = &arpintrq; 455 break; 456#endif 457#ifdef INET6 458 case ETHERTYPE_IPV6: 459 schednetisr(NETISR_IPV6); 460 inq = &ip6intrq; 461 break; 462#endif 463#ifdef IPX 464 case ETHERTYPE_IPX: 465 schednetisr(NETISR_IPX); 466 inq = &ipxintrq; 467 break; 468#endif 469#ifdef NS 470 case ETHERTYPE_NS: 471 schednetisr(NETISR_NS); 472 inq = &nsintrq; 473 break; 474#endif 475#ifdef DECNET 476 case ETHERTYPE_DECNET: 477 schednetisr(NETISR_DECNET); 478 inq = &decnetintrq; 479 break; 480#endif 481#ifdef NETATALK 482 case ETHERTYPE_AT: 483 schednetisr(NETISR_ATALK); 484 inq = &atintrq1; 485 break; 486 case ETHERTYPE_AARP: 487 /* probably this should be done with a NETISR as well */ 488 aarpinput(IFP2AC(ifp), m); /* XXX */ 489 return; 490#endif /* NETATALK */ 491 default: 492 /* printf("fddi_input: unknown protocol 0x%x\n", type); */ 493 ifp->if_noproto++; 494 goto dropanyway; 495 } 496 break; 497 } 498 499 default: 500 /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */ 501 ifp->if_noproto++; 502 goto dropanyway; 503 } 504 505 (void) IF_HANDOFF(inq, m, NULL); 506 return; 507 508dropanyway: 509 ifp->if_iqdrops++; 510 if (m) 511 m_freem(m); 512 return; 513} 514 515/* 516 * Perform common duties while attaching to interface list 517 */ 518void 519fddi_ifattach(ifp) 520 struct ifnet *ifp; 521{ 522 struct ifaddr *ifa; 523 struct sockaddr_dl *sdl; 524 525 ifp->if_type = IFT_FDDI; 526 ifp->if_addrlen = FDDI_ADDR_LEN; 527 ifp->if_hdrlen = 21; 528 529 if_attach(ifp); /* Must be called before additional assignments */ 530 531 ifp->if_mtu = FDDIMTU; 532 ifp->if_output = fddi_output; 533 ifp->if_resolvemulti = fddi_resolvemulti; 534 ifp->if_broadcastaddr = fddibroadcastaddr; 535 ifp->if_baudrate = 100000000; 536#ifdef IFF_NOTRAILERS 537 ifp->if_flags |= IFF_NOTRAILERS; 538#endif 539 ifa = ifaddr_byindex(ifp->if_index); 540 if (ifa == NULL) { 541 printf("%s(): no lladdr for %s%d!\n", __FUNCTION__, 542 ifp->if_name, ifp->if_unit); 543 return; 544 } 545 546 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 547 sdl->sdl_type = IFT_FDDI; 548 sdl->sdl_alen = ifp->if_addrlen; 549 bcopy(IFP2AC(ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen); 550 551 return; 552} 553 554static int 555fddi_resolvemulti(ifp, llsa, sa) 556 struct ifnet *ifp; 557 struct sockaddr **llsa; 558 struct sockaddr *sa; 559{ 560 struct sockaddr_dl *sdl; 561 struct sockaddr_in *sin; 562#ifdef INET6 563 struct sockaddr_in6 *sin6; 564#endif 565 u_char *e_addr; 566 567 switch(sa->sa_family) { 568 case AF_LINK: 569 /* 570 * No mapping needed. Just check that it's a valid MC address. 571 */ 572 sdl = (struct sockaddr_dl *)sa; 573 e_addr = LLADDR(sdl); 574 if ((e_addr[0] & 1) != 1) 575 return (EADDRNOTAVAIL); 576 *llsa = 0; 577 return (0); 578 579#ifdef INET 580 case AF_INET: 581 sin = (struct sockaddr_in *)sa; 582 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 583 return (EADDRNOTAVAIL); 584 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 585 M_WAITOK); 586 sdl->sdl_len = sizeof *sdl; 587 sdl->sdl_family = AF_LINK; 588 sdl->sdl_index = ifp->if_index; 589 sdl->sdl_type = IFT_FDDI; 590 sdl->sdl_nlen = 0; 591 sdl->sdl_alen = FDDI_ADDR_LEN; 592 sdl->sdl_slen = 0; 593 e_addr = LLADDR(sdl); 594 ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr); 595 *llsa = (struct sockaddr *)sdl; 596 return (0); 597#endif 598#ifdef INET6 599 case AF_INET6: 600 sin6 = (struct sockaddr_in6 *)sa; 601 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 602 /* 603 * An IP6 address of 0 means listen to all 604 * of the Ethernet multicast address used for IP6. 605 * (This is used for multicast routers.) 606 */ 607 ifp->if_flags |= IFF_ALLMULTI; 608 *llsa = 0; 609 return (0); 610 } 611 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 612 return (EADDRNOTAVAIL); 613 MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR, 614 M_WAITOK); 615 sdl->sdl_len = sizeof *sdl; 616 sdl->sdl_family = AF_LINK; 617 sdl->sdl_index = ifp->if_index; 618 sdl->sdl_type = IFT_FDDI; 619 sdl->sdl_nlen = 0; 620 sdl->sdl_alen = FDDI_ADDR_LEN; 621 sdl->sdl_slen = 0; 622 e_addr = LLADDR(sdl); 623 ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr); 624 *llsa = (struct sockaddr *)sdl; 625 return (0); 626#endif 627 628 default: 629 /* 630 * Well, the text isn't quite right, but it's the name 631 * that counts... 632 */ 633 return (EAFNOSUPPORT); 634 } 635 636 return (0); 637} 638 639static moduledata_t fddi_mod = { 640 "fddi", /* module name */ 641 NULL, /* event handler */ 642 0 /* extra data */ 643}; 644 645DECLARE_MODULE(fddi, fddi_mod, SI_SUB_PSEUDO, SI_ORDER_ANY); 646MODULE_VERSION(fddi, 1); 647