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