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$ 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 67 static MALLOC_DEFINE(M_FWCOM, "fw_com", "firewire interface internals"); 68 69 struct fw_hwaddr firewire_broadcastaddr = { 70 0xffffffff, 71 0xffffffff, 72 0xff, 73 0xff, 74 0xffff, 75 0xffffffff 76 }; 77 78 static int 79 firewire_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 = 0; 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, (u_char *) destfw, NULL); 148 if (error) 149 return (error == EWOULDBLOCK ? 0 : error); 150 } 151 type = ETHERTYPE_IP; 152 break; 153 154 case AF_ARP: 155 { 156 struct arphdr *ah; 157 ah = mtod(m, struct arphdr *); 158 ah->ar_hrd = htons(ARPHRD_IEEE1394); 159 type = ETHERTYPE_ARP; 160 if (unicast) 161 *destfw = *(struct fw_hwaddr *) ar_tha(ah); 162 163 /* 164 * The standard arp code leaves a hole for the target 165 * hardware address which we need to close up. 166 */ 167 bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln); 168 m_adj(m, -ah->ar_hln); 169 break; 170 } 171 #endif 172 173 #ifdef INET6 174 case AF_INET6: 175 if (unicast) { 176 error = nd6_resolve(fc->fc_ifp, is_gw, m, dst, 177 (u_char *) destfw, NULL); 178 if (error) 179 return (error == EWOULDBLOCK ? 0 : error); 180 } 181 type = ETHERTYPE_IPV6; 182 break; 183 #endif 184 185 default: 186 if_printf(ifp, "can't handle af%d\n", dst->sa_family); 187 error = EAFNOSUPPORT; 188 goto bad; 189 } 190 191 /* 192 * Let BPF tap off a copy before we encapsulate. 193 */ 194 if (bpf_peers_present(ifp->if_bpf)) { 195 struct fw_bpfhdr h; 196 if (unicast) 197 bcopy(destfw, h.firewire_dhost, 8); 198 else 199 bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 200 bcopy(&fc->fc_hwaddr, h.firewire_shost, 8); 201 h.firewire_type = htons(type); 202 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 203 } 204 205 /* 206 * Punt on MCAP for now and send all multicast packets on the 207 * broadcast channel. 208 */ 209 if (m->m_flags & M_MCAST) 210 m->m_flags |= M_BCAST; 211 212 /* 213 * Figure out what speed to use and what the largest supported 214 * packet size is. For unicast, this is the minimum of what we 215 * can speak and what they can hear. For broadcast, lets be 216 * conservative and use S100. We could possibly improve that 217 * by examining the bus manager's speed map or similar. We 218 * also reduce the packet size for broadcast to account for 219 * the GASP header. 220 */ 221 if (unicast) { 222 speed = min(fc->fc_speed, destfw->sspd); 223 psize = min(512 << speed, 2 << destfw->sender_max_rec); 224 } else { 225 speed = 0; 226 psize = 512 - 2*sizeof(uint32_t); 227 } 228 229 /* 230 * Next, we encapsulate, possibly fragmenting the original 231 * datagram if it won't fit into a single packet. 232 */ 233 if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) { 234 /* 235 * No fragmentation is necessary. 236 */ 237 M_PREPEND(m, sizeof(uint32_t), M_NOWAIT); 238 if (!m) { 239 error = ENOBUFS; 240 goto bad; 241 } 242 enc = mtod(m, union fw_encap *); 243 enc->unfrag.ether_type = type; 244 enc->unfrag.lf = FW_ENCAP_UNFRAG; 245 enc->unfrag.reserved = 0; 246 247 /* 248 * Byte swap the encapsulation header manually. 249 */ 250 enc->ul[0] = htonl(enc->ul[0]); 251 252 error = (ifp->if_transmit)(ifp, m); 253 return (error); 254 } else { 255 /* 256 * Fragment the datagram, making sure to leave enough 257 * space for the encapsulation header in each packet. 258 */ 259 fsize = psize - 2*sizeof(uint32_t); 260 dgl = next_dgl++; 261 dsize = m->m_pkthdr.len; 262 foff = 0; 263 while (m) { 264 if (m->m_pkthdr.len > fsize) { 265 /* 266 * Split off the tail segment from the 267 * datagram, copying our tags over. 268 */ 269 mtail = m_split(m, fsize, M_NOWAIT); 270 m_tag_copy_chain(mtail, m, M_NOWAIT); 271 } else { 272 mtail = 0; 273 } 274 275 /* 276 * Add our encapsulation header to this 277 * fragment and hand it off to the link. 278 */ 279 M_PREPEND(m, 2*sizeof(uint32_t), M_NOWAIT); 280 if (!m) { 281 error = ENOBUFS; 282 goto bad; 283 } 284 enc = mtod(m, union fw_encap *); 285 if (foff == 0) { 286 enc->firstfrag.lf = FW_ENCAP_FIRST; 287 enc->firstfrag.reserved1 = 0; 288 enc->firstfrag.reserved2 = 0; 289 enc->firstfrag.datagram_size = dsize - 1; 290 enc->firstfrag.ether_type = type; 291 enc->firstfrag.dgl = dgl; 292 } else { 293 if (mtail) 294 enc->nextfrag.lf = FW_ENCAP_NEXT; 295 else 296 enc->nextfrag.lf = FW_ENCAP_LAST; 297 enc->nextfrag.reserved1 = 0; 298 enc->nextfrag.reserved2 = 0; 299 enc->nextfrag.reserved3 = 0; 300 enc->nextfrag.datagram_size = dsize - 1; 301 enc->nextfrag.fragment_offset = foff; 302 enc->nextfrag.dgl = dgl; 303 } 304 foff += m->m_pkthdr.len - 2*sizeof(uint32_t); 305 306 /* 307 * Byte swap the encapsulation header manually. 308 */ 309 enc->ul[0] = htonl(enc->ul[0]); 310 enc->ul[1] = htonl(enc->ul[1]); 311 312 error = (ifp->if_transmit)(ifp, m); 313 if (error) { 314 if (mtail) 315 m_freem(mtail); 316 return (ENOBUFS); 317 } 318 319 m = mtail; 320 } 321 322 return (0); 323 } 324 325 bad: 326 if (m) 327 m_freem(m); 328 return (error); 329 } 330 331 static struct mbuf * 332 firewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src) 333 { 334 union fw_encap *enc; 335 struct fw_reass *r; 336 struct mbuf *mf, *mprev; 337 int dsize; 338 int fstart, fend, start, end, islast; 339 uint32_t id; 340 341 /* 342 * Find an existing reassembly buffer or create a new one. 343 */ 344 enc = mtod(m, union fw_encap *); 345 id = enc->firstfrag.dgl | (src << 16); 346 STAILQ_FOREACH(r, &fc->fc_frags, fr_link) 347 if (r->fr_id == id) 348 break; 349 if (!r) { 350 r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT); 351 if (!r) { 352 m_freem(m); 353 return 0; 354 } 355 r->fr_id = id; 356 r->fr_frags = 0; 357 STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link); 358 } 359 360 /* 361 * If this fragment overlaps any other fragment, we must discard 362 * the partial reassembly and start again. 363 */ 364 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 365 fstart = 0; 366 else 367 fstart = enc->nextfrag.fragment_offset; 368 fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t); 369 dsize = enc->nextfrag.datagram_size; 370 islast = (enc->nextfrag.lf == FW_ENCAP_LAST); 371 372 for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) { 373 enc = mtod(mf, union fw_encap *); 374 if (enc->nextfrag.datagram_size != dsize) { 375 /* 376 * This fragment must be from a different 377 * packet. 378 */ 379 goto bad; 380 } 381 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 382 start = 0; 383 else 384 start = enc->nextfrag.fragment_offset; 385 end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t); 386 if ((fstart < end && fend > start) || 387 (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) { 388 /* 389 * Overlap - discard reassembly buffer and start 390 * again with this fragment. 391 */ 392 goto bad; 393 } 394 } 395 396 /* 397 * Find where to put this fragment in the list. 398 */ 399 for (mf = r->fr_frags, mprev = NULL; mf; 400 mprev = mf, mf = mf->m_nextpkt) { 401 enc = mtod(mf, union fw_encap *); 402 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 403 start = 0; 404 else 405 start = enc->nextfrag.fragment_offset; 406 if (start >= fend) 407 break; 408 } 409 410 /* 411 * If this is a last fragment and we are not adding at the end 412 * of the list, discard the buffer. 413 */ 414 if (islast && mprev && mprev->m_nextpkt) 415 goto bad; 416 417 if (mprev) { 418 m->m_nextpkt = mprev->m_nextpkt; 419 mprev->m_nextpkt = m; 420 421 /* 422 * Coalesce forwards and see if we can make a whole 423 * datagram. 424 */ 425 enc = mtod(mprev, union fw_encap *); 426 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 427 start = 0; 428 else 429 start = enc->nextfrag.fragment_offset; 430 end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t); 431 while (end == fstart) { 432 /* 433 * Strip off the encap header from m and 434 * append it to mprev, freeing m. 435 */ 436 m_adj(m, 2*sizeof(uint32_t)); 437 mprev->m_nextpkt = m->m_nextpkt; 438 mprev->m_pkthdr.len += m->m_pkthdr.len; 439 m_cat(mprev, m); 440 441 if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) { 442 /* 443 * We have assembled a complete packet 444 * we must be finished. Make sure we have 445 * merged the whole chain. 446 */ 447 STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link); 448 free(r, M_TEMP); 449 m = mprev->m_nextpkt; 450 while (m) { 451 mf = m->m_nextpkt; 452 m_freem(m); 453 m = mf; 454 } 455 mprev->m_nextpkt = NULL; 456 457 return (mprev); 458 } 459 460 /* 461 * See if we can continue merging forwards. 462 */ 463 end = fend; 464 m = mprev->m_nextpkt; 465 if (m) { 466 enc = mtod(m, union fw_encap *); 467 if (enc->firstfrag.lf == FW_ENCAP_FIRST) 468 fstart = 0; 469 else 470 fstart = enc->nextfrag.fragment_offset; 471 fend = fstart + m->m_pkthdr.len 472 - 2*sizeof(uint32_t); 473 } else { 474 break; 475 } 476 } 477 } else { 478 m->m_nextpkt = 0; 479 r->fr_frags = m; 480 } 481 482 return (0); 483 484 bad: 485 while (r->fr_frags) { 486 mf = r->fr_frags; 487 r->fr_frags = mf->m_nextpkt; 488 m_freem(mf); 489 } 490 m->m_nextpkt = 0; 491 r->fr_frags = m; 492 493 return (0); 494 } 495 496 void 497 firewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src) 498 { 499 struct fw_com *fc = IFP2FWC(ifp); 500 union fw_encap *enc; 501 int type, isr; 502 503 /* 504 * The caller has already stripped off the packet header 505 * (stream or wreqb) and marked the mbuf's M_BCAST flag 506 * appropriately. We de-encapsulate the IP packet and pass it 507 * up the line after handling link-level fragmentation. 508 */ 509 if (m->m_pkthdr.len < sizeof(uint32_t)) { 510 if_printf(ifp, "discarding frame without " 511 "encapsulation header (len %u pkt len %u)\n", 512 m->m_len, m->m_pkthdr.len); 513 } 514 515 m = m_pullup(m, sizeof(uint32_t)); 516 if (m == NULL) 517 return; 518 enc = mtod(m, union fw_encap *); 519 520 /* 521 * Byte swap the encapsulation header manually. 522 */ 523 enc->ul[0] = ntohl(enc->ul[0]); 524 525 if (enc->unfrag.lf != 0) { 526 m = m_pullup(m, 2*sizeof(uint32_t)); 527 if (!m) 528 return; 529 enc = mtod(m, union fw_encap *); 530 enc->ul[1] = ntohl(enc->ul[1]); 531 m = firewire_input_fragment(fc, m, src); 532 if (!m) 533 return; 534 enc = mtod(m, union fw_encap *); 535 type = enc->firstfrag.ether_type; 536 m_adj(m, 2*sizeof(uint32_t)); 537 } else { 538 type = enc->unfrag.ether_type; 539 m_adj(m, sizeof(uint32_t)); 540 } 541 542 if (m->m_pkthdr.rcvif == NULL) { 543 if_printf(ifp, "discard frame w/o interface pointer\n"); 544 if_inc_counter(ifp, IFCOUNTER_IERRORS, 1); 545 m_freem(m); 546 return; 547 } 548 #ifdef DIAGNOSTIC 549 if (m->m_pkthdr.rcvif != ifp) { 550 if_printf(ifp, "Warning, frame marked as received on %s\n", 551 m->m_pkthdr.rcvif->if_xname); 552 } 553 #endif 554 555 #ifdef MAC 556 /* 557 * Tag the mbuf with an appropriate MAC label before any other 558 * consumers can get to it. 559 */ 560 mac_ifnet_create_mbuf(ifp, m); 561 #endif 562 563 /* 564 * Give bpf a chance at the packet. The link-level driver 565 * should have left us a tag with the EUID of the sender. 566 */ 567 if (bpf_peers_present(ifp->if_bpf)) { 568 struct fw_bpfhdr h; 569 struct m_tag *mtag; 570 571 mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 572 if (mtag) 573 bcopy(mtag + 1, h.firewire_shost, 8); 574 else 575 bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8); 576 bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8); 577 h.firewire_type = htons(type); 578 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 579 } 580 581 if (ifp->if_flags & IFF_MONITOR) { 582 /* 583 * Interface marked for monitoring; discard packet. 584 */ 585 m_freem(m); 586 return; 587 } 588 589 if_inc_counter(ifp, IFCOUNTER_IBYTES, m->m_pkthdr.len); 590 591 /* Discard packet if interface is not up */ 592 if ((ifp->if_flags & IFF_UP) == 0) { 593 m_freem(m); 594 return; 595 } 596 597 if (m->m_flags & (M_BCAST|M_MCAST)) 598 if_inc_counter(ifp, IFCOUNTER_IMCASTS, 1); 599 600 switch (type) { 601 #ifdef INET 602 case ETHERTYPE_IP: 603 isr = NETISR_IP; 604 break; 605 606 case ETHERTYPE_ARP: 607 { 608 struct arphdr *ah; 609 ah = mtod(m, struct arphdr *); 610 611 /* 612 * Adjust the arp packet to insert an empty tha slot. 613 */ 614 m->m_len += ah->ar_hln; 615 m->m_pkthdr.len += ah->ar_hln; 616 bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln); 617 isr = NETISR_ARP; 618 break; 619 } 620 #endif 621 622 #ifdef INET6 623 case ETHERTYPE_IPV6: 624 isr = NETISR_IPV6; 625 break; 626 #endif 627 628 default: 629 m_freem(m); 630 return; 631 } 632 633 M_SETFIB(m, ifp->if_fib); 634 netisr_dispatch(isr, m); 635 } 636 637 int 638 firewire_ioctl(struct ifnet *ifp, u_long command, caddr_t data) 639 { 640 struct ifaddr *ifa = (struct ifaddr *) data; 641 struct ifreq *ifr = (struct ifreq *) data; 642 int error = 0; 643 644 switch (command) { 645 case SIOCSIFADDR: 646 ifp->if_flags |= IFF_UP; 647 648 switch (ifa->ifa_addr->sa_family) { 649 #ifdef INET 650 case AF_INET: 651 ifp->if_init(ifp->if_softc); /* before arpwhohas */ 652 arp_ifinit(ifp, ifa); 653 break; 654 #endif 655 default: 656 ifp->if_init(ifp->if_softc); 657 break; 658 } 659 break; 660 661 case SIOCGIFADDR: 662 { 663 struct sockaddr *sa; 664 665 sa = (struct sockaddr *) & ifr->ifr_data; 666 bcopy(&IFP2FWC(ifp)->fc_hwaddr, 667 (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr)); 668 } 669 break; 670 671 case SIOCSIFMTU: 672 /* 673 * Set the interface MTU. 674 */ 675 if (ifr->ifr_mtu > 1500) { 676 error = EINVAL; 677 } else { 678 ifp->if_mtu = ifr->ifr_mtu; 679 } 680 break; 681 default: 682 error = EINVAL; /* XXX netbsd has ENOTTY??? */ 683 break; 684 } 685 return (error); 686 } 687 688 static int 689 firewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa, 690 struct sockaddr *sa) 691 { 692 #ifdef INET 693 struct sockaddr_in *sin; 694 #endif 695 #ifdef INET6 696 struct sockaddr_in6 *sin6; 697 #endif 698 699 switch(sa->sa_family) { 700 case AF_LINK: 701 /* 702 * No mapping needed. 703 */ 704 *llsa = 0; 705 return 0; 706 707 #ifdef INET 708 case AF_INET: 709 sin = (struct sockaddr_in *)sa; 710 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr))) 711 return EADDRNOTAVAIL; 712 *llsa = 0; 713 return 0; 714 #endif 715 #ifdef INET6 716 case AF_INET6: 717 sin6 = (struct sockaddr_in6 *)sa; 718 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { 719 /* 720 * An IP6 address of 0 means listen to all 721 * of the Ethernet multicast address used for IP6. 722 * (This is used for multicast routers.) 723 */ 724 ifp->if_flags |= IFF_ALLMULTI; 725 *llsa = 0; 726 return 0; 727 } 728 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) 729 return EADDRNOTAVAIL; 730 *llsa = 0; 731 return 0; 732 #endif 733 734 default: 735 /* 736 * Well, the text isn't quite right, but it's the name 737 * that counts... 738 */ 739 return EAFNOSUPPORT; 740 } 741 } 742 743 void 744 firewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc) 745 { 746 struct fw_com *fc = IFP2FWC(ifp); 747 struct ifaddr *ifa; 748 struct sockaddr_dl *sdl; 749 static const char* speeds[] = { 750 "S100", "S200", "S400", "S800", 751 "S1600", "S3200" 752 }; 753 754 fc->fc_speed = llc->sspd; 755 STAILQ_INIT(&fc->fc_frags); 756 757 ifp->if_addrlen = sizeof(struct fw_hwaddr); 758 ifp->if_hdrlen = 0; 759 if_attach(ifp); 760 ifp->if_mtu = 1500; /* XXX */ 761 ifp->if_output = firewire_output; 762 ifp->if_resolvemulti = firewire_resolvemulti; 763 ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr; 764 765 ifa = ifp->if_addr; 766 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__)); 767 sdl = (struct sockaddr_dl *)ifa->ifa_addr; 768 sdl->sdl_type = IFT_IEEE1394; 769 sdl->sdl_alen = ifp->if_addrlen; 770 bcopy(llc, LLADDR(sdl), ifp->if_addrlen); 771 772 bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394, 773 sizeof(struct fw_hwaddr)); 774 775 if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n", 776 (uint8_t *) &llc->sender_unique_ID_hi, ":", 777 ntohs(llc->sender_unicast_FIFO_hi), 778 ntohl(llc->sender_unicast_FIFO_lo), 779 speeds[llc->sspd], 780 (2 << llc->sender_max_rec)); 781 } 782 783 void 784 firewire_ifdetach(struct ifnet *ifp) 785 { 786 bpfdetach(ifp); 787 if_detach(ifp); 788 } 789 790 void 791 firewire_busreset(struct ifnet *ifp) 792 { 793 struct fw_com *fc = IFP2FWC(ifp); 794 struct fw_reass *r; 795 struct mbuf *m; 796 797 /* 798 * Discard any partial datagrams since the host ids may have changed. 799 */ 800 while ((r = STAILQ_FIRST(&fc->fc_frags))) { 801 STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link); 802 while (r->fr_frags) { 803 m = r->fr_frags; 804 r->fr_frags = m->m_nextpkt; 805 m_freem(m); 806 } 807 free(r, M_TEMP); 808 } 809 } 810 811 static void * 812 firewire_alloc(u_char type, struct ifnet *ifp) 813 { 814 struct fw_com *fc; 815 816 fc = malloc(sizeof(struct fw_com), M_FWCOM, M_WAITOK | M_ZERO); 817 fc->fc_ifp = ifp; 818 819 return (fc); 820 } 821 822 static void 823 firewire_free(void *com, u_char type) 824 { 825 826 free(com, M_FWCOM); 827 } 828 829 static int 830 firewire_modevent(module_t mod, int type, void *data) 831 { 832 833 switch (type) { 834 case MOD_LOAD: 835 if_register_com_alloc(IFT_IEEE1394, 836 firewire_alloc, firewire_free); 837 break; 838 case MOD_UNLOAD: 839 if_deregister_com_alloc(IFT_IEEE1394); 840 break; 841 default: 842 return (EOPNOTSUPP); 843 } 844 845 return (0); 846 } 847 848 static moduledata_t firewire_mod = { 849 "if_firewire", 850 firewire_modevent, 851 0 852 }; 853 854 DECLARE_MODULE(if_firewire, firewire_mod, SI_SUB_INIT_IF, SI_ORDER_ANY); 855 MODULE_VERSION(if_firewire, 1); 856