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