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