1/*- 2 * Copyright (c) 2004 Doug Rabson 3 * Copyright (c) 1982, 1989, 1993 4 * The Regents of the University of California. All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 4. Neither the name of the University nor the names of its contributors 15 * may be used to endorse or promote products derived from this software 16 * without specific prior written permission. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $FreeBSD: stable/11/sys/net/if_fwsubr.c 369819 2021-05-17 10:01:37Z avatar $ 31 */ 32 33#include "opt_inet.h" 34#include "opt_inet6.h" 35 36#include <sys/param.h> 37#include <sys/systm.h> 38#include <sys/kernel.h> 39#include <sys/malloc.h> 40#include <sys/mbuf.h> 41#include <sys/module.h> 42#include <sys/socket.h> 43#include <sys/sockio.h> 44 45#include <net/if.h> 46#include <net/if_var.h> 47#include <net/netisr.h> 48#include <net/route.h> 49#include <net/if_llc.h> 50#include <net/if_dl.h> 51#include <net/if_types.h> 52#include <net/bpf.h> 53#include <net/firewire.h> 54#include <net/if_llatbl.h> 55 56#if defined(INET) || defined(INET6) 57#include <netinet/in.h> 58#include <netinet/in_var.h> 59#include <netinet/if_ether.h> 60#endif 61#ifdef INET6 62#include <netinet6/nd6.h> 63#endif 64 65#include <security/mac/mac_framework.h> 66 67static MALLOC_DEFINE(M_FWCOM, "fw_com", "firewire interface internals"); 68 69struct fw_hwaddr firewire_broadcastaddr = { 70 0xffffffff, 71 0xffffffff, 72 0xff, 73 0xff, 74 0xffff, 75 0xffffffff 76}; 77 78static int 79firewire_output(struct ifnet *ifp, struct mbuf *m, const struct sockaddr *dst, 80 struct route *ro) 81{ 82 struct fw_com *fc = IFP2FWC(ifp); 83 int error, type; 84 struct m_tag *mtag; 85 union fw_encap *enc; 86 struct fw_hwaddr *destfw; 87 uint8_t speed; 88 uint16_t psize, fsize, dsize; 89 struct mbuf *mtail; 90 int unicast, dgl, foff; 91 static int next_dgl; 92#if defined(INET) || defined(INET6) 93 int is_gw = 0; 94#endif 95 96#ifdef MAC 97 error = mac_ifnet_check_transmit(ifp, m); 98 if (error) 99 goto bad; 100#endif 101 102 if (!((ifp->if_flags & IFF_UP) && 103 (ifp->if_drv_flags & IFF_DRV_RUNNING))) { 104 error = ENETDOWN; 105 goto bad; 106 } 107 108#if defined(INET) || defined(INET6) 109 if (ro != NULL) 110 is_gw = (ro->ro_flags & RT_HAS_GW) != 0; 111#endif 112 /* 113 * For unicast, we make a tag to store the lladdr of the 114 * destination. This might not be the first time we have seen 115 * the packet (for instance, the arp code might be trying to 116 * re-send it after receiving an arp reply) so we only 117 * allocate a tag if there isn't one there already. For 118 * multicast, we will eventually use a different tag to store 119 * the channel number. 120 */ 121 unicast = !(m->m_flags & (M_BCAST | M_MCAST)); 122 if (unicast) { 123 mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); 124 if (!mtag) { 125 mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 126 sizeof (struct fw_hwaddr), M_NOWAIT); 127 if (!mtag) { 128 error = ENOMEM; 129 goto bad; 130 } 131 m_tag_prepend(m, mtag); 132 } 133 destfw = (struct fw_hwaddr *)(mtag + 1); 134 } else { 135 destfw = NULL; 136 } 137 138 switch (dst->sa_family) { 139#ifdef INET 140 case AF_INET: 141 /* 142 * Only bother with arp for unicast. Allocation of 143 * channels etc. for firewire is quite different and 144 * doesn't fit into the arp model. 145 */ 146 if (unicast) { 147 error = arpresolve(ifp, is_gw, m, dst, 148 (u_char *) destfw, NULL, NULL); 149 if (error) 150 return (error == EWOULDBLOCK ? 0 : error); 151 } 152 type = ETHERTYPE_IP; 153 break; 154 155 case AF_ARP: 156 { 157 struct arphdr *ah; 158 ah = mtod(m, struct arphdr *); 159 ah->ar_hrd = htons(ARPHRD_IEEE1394); 160 type = ETHERTYPE_ARP; 161 if (unicast) 162 *destfw = *(struct fw_hwaddr *) ar_tha(ah); 163 164 /* 165 * The standard arp code leaves a hole for the target 166 * hardware address which we need to close up. 167 */ 168 bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); 169 m_adj(m, -ah->ar_hln); 170 break; 171 } 172#endif 173 174#ifdef INET6 175 case AF_INET6: 176 if (unicast) { 177 error = nd6_resolve(fc->fc_ifp, is_gw, m, dst, 178 (u_char *) destfw, NULL, NULL); 179 if (error) 180 return (error == EWOULDBLOCK ? 0 : error); 181 } 182 type = ETHERTYPE_IPV6; 183 break; 184#endif 185 186 default: 187 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 188 error = EAFNOSUPPORT; 189 goto bad; 190 } 191 192 /* 193 * Let BPF tap off a copy before we encapsulate. 194 */ 195 if (bpf_peers_present(ifp->if_bpf)) { 196 struct fw_bpfhdr h; 197 if (unicast) 198 bcopy(destfw, h.firewire_dhost, 8); 199 else 200 bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 201 bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); 202 h.firewire_type = htons(type); 203 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 204 } 205 206 /* 207 * Punt on MCAP for now and send all multicast packets on the 208 * broadcast channel. 209 */ 210 if (m->m_flags & M_MCAST) 211 m->m_flags |= M_BCAST; 212 213 /* 214 * Figure out what speed to use and what the largest supported 215 * packet size is. For unicast, this is the minimum of what we 216 * can speak and what they can hear. For broadcast, lets be 217 * conservative and use S100. We could possibly improve that 218 * by examining the bus manager's speed map or similar. We 219 * also reduce the packet size for broadcast to account for 220 * the GASP header. 221 */ 222 if (unicast) { 223 speed = min(fc->fc_speed, destfw->sspd); 224 psize = min(512 << speed, 2 << destfw->sender_max_rec); 225 } else { 226 speed = 0; 227 psize = 512 - 2*sizeof(uint32_t); 228 } 229 230 /* 231 * Next, we encapsulate, possibly fragmenting the original 232 * datagram if it won't fit into a single packet. 233 */ 234 if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { 235 /* 236 * No fragmentation is necessary. 237 */ 238 M_PREPEND(m, sizeof(uint32_t), M_NOWAIT); 239 if (!m) { 240 error = ENOBUFS; 241 goto bad; 242 } 243 enc = mtod(m, union fw_encap *); 244 enc->unfrag.ether_type = type; 245 enc->unfrag.lf = FW_ENCAP_UNFRAG; 246 enc->unfrag.reserved = 0; 247 248 /* 249 * Byte swap the encapsulation header manually. 250 */ 251 enc->ul[0] = htonl(enc->ul[0]); 252 253 error = (ifp->if_transmit)(ifp, m); 254 return (error); 255 } else { 256 /* 257 * Fragment the datagram, making sure to leave enough 258 * space for the encapsulation header in each packet. 259 */ 260 fsize = psize - 2*sizeof(uint32_t); 261 dgl = next_dgl++; 262 dsize = m->m_pkthdr.len; 263 foff = 0; 264 while (m) { 265 if (m->m_pkthdr.len > fsize) { 266 /* 267 * Split off the tail segment from the 268 * datagram, copying our tags over. 269 */ 270 mtail = m_split(m, fsize, M_NOWAIT); 271 m_tag_copy_chain(mtail, m, M_NOWAIT); 272 } else { 273 mtail = NULL; 274 } 275 276 /* 277 * Add our encapsulation header to this 278 * fragment and hand it off to the link. 279 */ 280 M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT); 281 if (!m) { 282 error = ENOBUFS; 283 goto bad; 284 } 285 enc = mtod(m, union fw_encap *); 286 if (foff == 0) { 287 enc->firstfrag.lf = FW_ENCAP_FIRST; 288 enc->firstfrag.reserved1 = 0; 289 enc->firstfrag.reserved2 = 0; 290 enc->firstfrag.datagram_size = dsize - 1; 291 enc->firstfrag.ether_type = type; 292 enc->firstfrag.dgl = dgl; 293 } else { 294 if (mtail) 295 enc->nextfrag.lf = FW_ENCAP_NEXT; 296 else 297 enc->nextfrag.lf = FW_ENCAP_LAST; 298 enc->nextfrag.reserved1 = 0; 299 enc->nextfrag.reserved2 = 0; 300 enc->nextfrag.reserved3 = 0; 301 enc->nextfrag.datagram_size = dsize - 1; 302 enc->nextfrag.fragment_offset = foff; 303 enc->nextfrag.dgl = dgl; 304 } 305 foff += m->m_pkthdr.len - 2*sizeof(uint32_t); 306 307 /* 308 * Byte swap the encapsulation header manually. 309 */ 310 enc->ul[0] = htonl(enc->ul[0]); 311 enc->ul[1] = htonl(enc->ul[1]); 312 313 error = (ifp->if_transmit)(ifp, m); 314 if (error) { 315 if (mtail) 316 m_freem(mtail); 317 return (ENOBUFS); 318 } 319 320 m = mtail; 321 } 322 323 return (0); 324 } 325 326bad: 327 if (m) 328 m_freem(m); 329 return (error); 330} 331 332static struct mbuf * 333firewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) 334{ 335 union fw_encap *enc; 336 struct fw_reass *r; 337 struct mbuf *mf, *mprev; 338 int dsize; 339 int fstart, fend, start, end, islast; 340 uint32_t id; 341 342 /* 343 * Find an existing reassembly buffer or create a new one. 344 */ 345 enc = mtod(m, union fw_encap *); 346 id = enc->firstfrag.dgl | (src << 16); 347 STAILQ_FOREACH(r, &fc->fc_frags, fr_link) 348 if (r->fr_id == id) 349 break; 350 if (!r) { 351 r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); 352 if (!r) { 353 m_freem(m); 354 return 0; 355 } 356 r->fr_id = id; 357 r->fr_frags = 0; 358 STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); 359 } 360 361 /* 362 * If this fragment overlaps any other fragment, we must discard 363 * the partial reassembly and start again. 364 */ 365 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 366 fstart = 0; 367 else 368 fstart = enc->nextfrag.fragment_offset; 369 fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); 370 dsize = enc->nextfrag.datagram_size; 371 islast = (enc->nextfrag.lf == FW_ENCAP_LAST); 372 373 for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { 374 enc = mtod(mf, union fw_encap *); 375 if (enc->nextfrag.datagram_size != dsize) { 376 /* 377 * This fragment must be from a different 378 * packet. 379 */ 380 goto bad; 381 } 382 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 383 start = 0; 384 else 385 start = enc->nextfrag.fragment_offset; 386 end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); 387 if ((fstart < end && fend > start) || 388 (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { 389 /* 390 * Overlap - discard reassembly buffer and start 391 * again with this fragment. 392 */ 393 goto bad; 394 } 395 } 396 397 /* 398 * Find where to put this fragment in the list. 399 */ 400 for (mf = r->fr_frags, mprev = NULL; mf; 401 mprev = mf, mf = mf->m_nextpkt) { 402 enc = mtod(mf, union fw_encap *); 403 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 404 start = 0; 405 else 406 start = enc->nextfrag.fragment_offset; 407 if (start >= fend) 408 break; 409 } 410 411 /* 412 * If this is a last fragment and we are not adding at the end 413 * of the list, discard the buffer. 414 */ 415 if (islast && mprev && mprev->m_nextpkt) 416 goto bad; 417 418 if (mprev) { 419 m->m_nextpkt = mprev->m_nextpkt; 420 mprev->m_nextpkt = m; 421 422 /* 423 * Coalesce forwards and see if we can make a whole 424 * datagram. 425 */ 426 enc = mtod(mprev, union fw_encap *); 427 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 428 start = 0; 429 else 430 start = enc->nextfrag.fragment_offset; 431 end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t); 432 while (end == fstart) { 433 /* 434 * Strip off the encap header from m and 435 * append it to mprev, freeing m. 436 */ 437 m_adj(m, 2*sizeof(uint32_t)); 438 mprev->m_nextpkt = m->m_nextpkt; 439 mprev->m_pkthdr.len += m->m_pkthdr.len; 440 m_cat(mprev, m); 441 442 if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) { 443 /* 444 * We have assembled a complete packet 445 * we must be finished. Make sure we have 446 * merged the whole chain. 447 */ 448 STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link); 449 free(r, M_TEMP); 450 m = mprev->m_nextpkt; 451 while (m) { 452 mf = m->m_nextpkt; 453 m_freem(m); 454 m = mf; 455 } 456 mprev->m_nextpkt = NULL; 457 458 return (mprev); 459 } 460 461 /* 462 * See if we can continue merging forwards. 463 */ 464 end = fend; 465 m = mprev->m_nextpkt; 466 if (m) { 467 enc = mtod(m, union fw_encap *); 468 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 469 fstart = 0; 470 else 471 fstart = enc->nextfrag.fragment_offset; 472 fend = fstart + m->m_pkthdr.len 473 - 2*sizeof(uint32_t); 474 } else { 475 break; 476 } 477 } 478 } else { 479 m->m_nextpkt = 0; 480 r->fr_frags = m; 481 } 482 483 return (0); 484 485bad: 486 while (r->fr_frags) { 487 mf = r->fr_frags; 488 r->fr_frags = mf->m_nextpkt; 489 m_freem(mf); 490 } 491 m->m_nextpkt = 0; 492 r->fr_frags = m; 493 494 return (0); 495} 496 497void 498firewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src) 499{ 500 struct fw_com *fc = IFP2FWC(ifp); 501 union fw_encap *enc; 502 int type, isr; 503 504 /* 505 * The caller has already stripped off the packet header 506 * (stream or wreqb) and marked the mbuf's M_BCAST flag 507 * appropriately. We de-encapsulate the IP packet and pass it 508 * up the line after handling link-level fragmentation. 509 */ 510 if (m->m_pkthdr.len < sizeof(uint32_t)) { 511 if_printf(ifp, "discarding frame without " 512 "encapsulation header (len %u pkt len %u)\n", 513 m->m_len, m->m_pkthdr.len); 514 } 515 516 m = m_pullup(m, sizeof(uint32_t)); 517 if (m == NULL) 518 return; 519 enc = mtod(m, union fw_encap *); 520 521 /* 522 * Byte swap the encapsulation header manually. 523 */ 524 enc->ul[0] = ntohl(enc->ul[0]); 525 526 if (enc->unfrag.lf != 0) { 527 m = m_pullup(m, 2*sizeof(uint32_t)); 528 if (!m) 529 return; 530 enc = mtod(m, union fw_encap *); 531 enc->ul[1] = ntohl(enc->ul[1]); 532 m = firewire_input_fragment(fc, m, src); 533 if (!m) 534 return; 535 enc = mtod(m, union fw_encap *); 536 type = enc->firstfrag.ether_type; 537 m_adj(m, 2*sizeof(uint32_t)); 538 } else { 539 type = enc->unfrag.ether_type; 540 m_adj(m, sizeof(uint32_t)); 541 } 542 543 if (m->m_pkthdr.rcvif == NULL) { 544 if_printf(ifp, "discard frame w/o interface pointer\n"); 545 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 546 m_freem(m); 547 return; 548 } 549#ifdef DIAGNOSTIC 550 if (m->m_pkthdr.rcvif != ifp) { 551 if_printf(ifp, "Warning, frame marked as received on %s\n", 552 m->m_pkthdr.rcvif->if_xname); 553 } 554#endif 555 556#ifdef MAC 557 /* 558 * Tag the mbuf with an appropriate MAC label before any other 559 * consumers can get to it. 560 */ 561 mac_ifnet_create_mbuf(ifp, m); 562#endif 563 564 /* 565 * Give bpf a chance at the packet. The link-level driver 566 * should have left us a tag with the EUID of the sender. 567 */ 568 if (bpf_peers_present(ifp->if_bpf)) { 569 struct fw_bpfhdr h; 570 struct m_tag *mtag; 571 572 mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 573 if (mtag) 574 bcopy(mtag + 1, h.firewire_shost, 8); 575 else 576 bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 577 bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8); 578 h.firewire_type = htons(type); 579 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 580 } 581 582 if (ifp->if_flags & IFF_MONITOR) { 583 /* 584 * Interface marked for monitoring; discard packet. 585 */ 586 m_freem(m); 587 return; 588 } 589 590 if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 591 592 /* Discard packet if interface is not up */ 593 if ((ifp->if_flags & IFF_UP) == 0) { 594 m_freem(m); 595 return; 596 } 597 598 if (m->m_flags & (M_BCAST|M_MCAST)) 599 if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 600 601 switch (type) { 602#ifdef INET 603 case ETHERTYPE_IP: 604 isr = NETISR_IP; 605 break; 606 607 case ETHERTYPE_ARP: 608 { 609 struct arphdr *ah; 610 ah = mtod(m, struct arphdr *); 611 612 /* 613 * Adjust the arp packet to insert an empty tha slot. 614 */ 615 m->m_len += ah->ar_hln; 616 m->m_pkthdr.len += ah->ar_hln; 617 bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln); 618 isr = NETISR_ARP; 619 break; 620 } 621#endif 622 623#ifdef INET6 624 case ETHERTYPE_IPV6: 625 isr = NETISR_IPV6; 626 break; 627#endif 628 629 default: 630 m_freem(m); 631 return; 632 } 633 634 M_SETFIB(m, ifp->if_fib); 635 CURVNET_SET_QUIET(ifp->if_vnet); 636 netisr_dispatch(isr, m); 637 CURVNET_RESTORE(); 638} 639 640int 641firewire_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 642{ 643 struct ifaddr *ifa = (struct ifaddr *) data; 644 struct ifreq *ifr = (struct ifreq *) data; 645 int error = 0; 646 647 switch (command) { 648 case SIOCSIFADDR: 649 ifp->if_flags |= IFF_UP; 650 651 switch (ifa->ifa_addr->sa_family) { 652#ifdef INET 653 case AF_INET: 654 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 655 arp_ifinit(ifp, ifa); 656 break; 657#endif 658 default: 659 ifp->if_init(ifp->if_softc); 660 break; 661 } 662 break; 663 664 case SIOCGIFADDR: 665 bcopy(&IFP2FWC(ifp)->fc_hwaddr, &ifr->ifr_addr.sa_data[0], 666 sizeof(struct fw_hwaddr)); 667 break; 668 669 case SIOCSIFMTU: 670 /* 671 * Set the interface MTU. 672 */ 673 if (ifr->ifr_mtu > 1500) { 674 error = EINVAL; 675 } else { 676 ifp->if_mtu = ifr->ifr_mtu; 677 } 678 break; 679 default: 680 error = EINVAL; /* XXX netbsd has ENOTTY??? */ 681 break; 682 } 683 return (error); 684} 685 686static int 687firewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 688 struct sockaddr *sa) 689{ 690#ifdef INET 691 struct sockaddr_in *sin; 692#endif 693#ifdef INET6 694 struct sockaddr_in6 *sin6; 695#endif 696 697 switch(sa->sa_family) { 698 case AF_LINK: 699 /* 700 * No mapping needed. 701 */ 702 *llsa = NULL; 703 return 0; 704 705#ifdef INET 706 case AF_INET: 707 sin = (struct sockaddr_in *)sa; 708 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 709 return EADDRNOTAVAIL; 710 *llsa = NULL; 711 return 0; 712#endif 713#ifdef INET6 714 case AF_INET6: 715 sin6 = (struct sockaddr_in6 *)sa; 716 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 717 /* 718 * An IP6 address of 0 means listen to all 719 * of the Ethernet multicast address used for IP6. 720 * (This is used for multicast routers.) 721 */ 722 ifp->if_flags |= IFF_ALLMULTI; 723 *llsa = NULL; 724 return 0; 725 } 726 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 727 return EADDRNOTAVAIL; 728 *llsa = NULL; 729 return 0; 730#endif 731 732 default: 733 /* 734 * Well, the text isn't quite right, but it's the name 735 * that counts... 736 */ 737 return EAFNOSUPPORT; 738 } 739} 740 741void 742firewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc) 743{ 744 struct fw_com *fc = IFP2FWC(ifp); 745 struct ifaddr *ifa; 746 struct sockaddr_dl *sdl; 747 static const char* speeds[] = { 748 "S100", "S200", "S400", "S800", 749 "S1600", "S3200" 750 }; 751 752 fc->fc_speed = llc->sspd; 753 STAILQ_INIT(&fc->fc_frags); 754 755 ifp->if_addrlen = sizeof(struct fw_hwaddr); 756 ifp->if_hdrlen = 0; 757 if_attach(ifp); 758 ifp->if_mtu = 1500; /* XXX */ 759 ifp->if_output = firewire_output; 760 ifp->if_resolvemulti = firewire_resolvemulti; 761 ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr; 762 763 ifa = ifp->if_addr; 764 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 765 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 766 sdl->sdl_type = IFT_IEEE1394; 767 sdl->sdl_alen = ifp->if_addrlen; 768 bcopy(llc, LLADDR(sdl), ifp->if_addrlen); 769 770 bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394, 771 sizeof(struct fw_hwaddr)); 772 773 if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n", 774 (uint8_t *) &llc->sender_unique_ID_hi, ":", 775 ntohs(llc->sender_unicast_FIFO_hi), 776 ntohl(llc->sender_unicast_FIFO_lo), 777 speeds[llc->sspd], 778 (2 << llc->sender_max_rec)); 779} 780 781void 782firewire_ifdetach(struct ifnet *ifp) 783{ 784 bpfdetach(ifp); 785 if_detach(ifp); 786} 787 788void 789firewire_busreset(struct ifnet *ifp) 790{ 791 struct fw_com *fc = IFP2FWC(ifp); 792 struct fw_reass *r; 793 struct mbuf *m; 794 795 /* 796 * Discard any partial datagrams since the host ids may have changed. 797 */ 798 while ((r = STAILQ_FIRST(&fc->fc_frags))) { 799 STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link); 800 while (r->fr_frags) { 801 m = r->fr_frags; 802 r->fr_frags = m->m_nextpkt; 803 m_freem(m); 804 } 805 free(r, M_TEMP); 806 } 807} 808 809static void * 810firewire_alloc(u_char type, struct ifnet *ifp) 811{ 812 struct fw_com *fc; 813 814 fc = malloc(sizeof(struct fw_com), M_FWCOM, M_WAITOK | M_ZERO); 815 fc->fc_ifp = ifp; 816 817 return (fc); 818} 819 820static void 821firewire_free(void *com, u_char type) 822{ 823 824 free(com, M_FWCOM); 825} 826 827static int 828firewire_modevent(module_t mod, int type, void *data) 829{ 830 831 switch (type) { 832 case MOD_LOAD: 833 if_register_com_alloc(IFT_IEEE1394, 834 firewire_alloc, firewire_free); 835 break; 836 case MOD_UNLOAD: 837 if_deregister_com_alloc(IFT_IEEE1394); 838 break; 839 default: 840 return (EOPNOTSUPP); 841 } 842 843 return (0); 844} 845 846static moduledata_t firewire_mod = { 847 "if_firewire", 848 firewire_modevent, 849 0 850}; 851 852DECLARE_MODULE(if_firewire, firewire_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 853MODULE_VERSION(if_firewire, 1); 854