1 /* $NetBSD: if_ieee1394subr.c,v 1.36 2007/08/30 02:17:35 dyoung Exp $ */ 2 3 /* 4 * Copyright (c) 2000 The NetBSD Foundation, Inc. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to The NetBSD Foundation 8 * by Atsushi Onoe. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed by the NetBSD 21 * Foundation, Inc. and its contributors. 22 * 4. Neither the name of The NetBSD Foundation nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/cdefs.h> 40 __KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.36 2007/08/30 02:17:35 dyoung Exp $"); 41 42 #include "opt_inet.h" 43 #include "bpfilter.h" 44 45 #include <sys/param.h> 46 #include <sys/systm.h> 47 #include <sys/socket.h> 48 #include <sys/sockio.h> 49 #include <sys/kernel.h> 50 #include <sys/mbuf.h> 51 #include <sys/device.h> 52 53 #include <net/if.h> 54 #include <net/if_dl.h> 55 #include <net/if_ieee1394.h> 56 #include <net/if_types.h> 57 #include <net/if_media.h> 58 #include <net/ethertypes.h> 59 #include <net/netisr.h> 60 #include <net/route.h> 61 62 #if NBPFILTER > 0 63 #include <net/bpf.h> 64 #endif 65 66 #ifdef INET 67 #include <netinet/in.h> 68 #include <netinet/in_var.h> 69 #include <netinet/if_inarp.h> 70 #endif /* INET */ 71 #ifdef INET6 72 #include <netinet/in.h> 73 #include <netinet6/in6_var.h> 74 #include <netinet6/nd6.h> 75 #endif /* INET6 */ 76 77 #include <dev/ieee1394/fw_port.h> 78 #include <dev/ieee1394/firewire.h> 79 80 #include <dev/ieee1394/firewirereg.h> 81 #include <dev/ieee1394/iec13213.h> 82 #include <dev/ieee1394/if_fwipvar.h> 83 84 #define IEEE1394_REASS_TIMEOUT 3 /* 3 sec */ 85 86 #define senderr(e) do { error = (e); goto bad; } while(0/*CONSTCOND*/) 87 88 static int ieee1394_output(struct ifnet *, struct mbuf *, 89 const struct sockaddr *, struct rtentry *); 90 static struct mbuf *ieee1394_reass(struct ifnet *, struct mbuf *, u_int16_t); 91 92 static int 93 ieee1394_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst, 94 struct rtentry *rt0) 95 { 96 u_int16_t etype = 0; 97 struct mbuf *m; 98 int s, hdrlen, error = 0; 99 struct rtentry *rt; 100 struct mbuf *mcopy = NULL; 101 struct ieee1394_hwaddr *hwdst, baddr; 102 const struct ieee1394_hwaddr *myaddr; 103 ALTQ_DECL(struct altq_pktattr pktattr;) 104 #ifdef INET 105 struct arphdr *ah; 106 #endif /* INET */ 107 struct m_tag *mtag; 108 int unicast; 109 110 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) 111 senderr(ENETDOWN); 112 if ((rt = rt0) != NULL) { 113 if ((rt->rt_flags & RTF_UP) == 0) { 114 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) { 115 rt->rt_refcnt--; 116 if (rt->rt_ifp != ifp) 117 return (*rt->rt_ifp->if_output) 118 (ifp, m0, dst, rt); 119 } else 120 senderr(EHOSTUNREACH); 121 } 122 if (rt->rt_flags & RTF_GATEWAY) { 123 if (rt->rt_gwroute == NULL) 124 goto lookup; 125 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) { 126 rtfree(rt); 127 rt = rt0; 128 lookup: 129 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1); 130 if ((rt = rt->rt_gwroute) == NULL) 131 senderr(EHOSTUNREACH); 132 /* the "G" test below also prevents rt == rt0 */ 133 if ((rt->rt_flags & RTF_GATEWAY) || 134 (rt->rt_ifp != ifp)) { 135 rt->rt_refcnt--; 136 rt0->rt_gwroute = NULL; 137 senderr(EHOSTUNREACH); 138 } 139 } 140 } 141 if (rt->rt_flags & RTF_REJECT) 142 if (rt->rt_rmx.rmx_expire == 0 || 143 time_second < rt->rt_rmx.rmx_expire) 144 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH); 145 } 146 147 /* 148 * If the queueing discipline needs packet classification, 149 * do it before prepending link headers. 150 */ 151 IFQ_CLASSIFY(&ifp->if_snd, m0, dst->sa_family, &pktattr); 152 153 /* 154 * For unicast, we make a tag to store the lladdr of the 155 * destination. This might not be the first time we have seen 156 * the packet (for instance, the arp code might be trying to 157 * re-send it after receiving an arp reply) so we only 158 * allocate a tag if there isn't one there already. For 159 * multicast, we will eventually use a different tag to store 160 * the channel number. 161 */ 162 unicast = !(m0->m_flags & (M_BCAST | M_MCAST)); 163 if (unicast) { 164 mtag = 165 m_tag_locate(m0, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL); 166 if (!mtag) { 167 mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, 168 sizeof (struct ieee1394_hwaddr), M_NOWAIT); 169 if (!mtag) { 170 error = ENOMEM; 171 goto bad; 172 } 173 m_tag_prepend(m0, mtag); 174 } 175 hwdst = (struct ieee1394_hwaddr *)(mtag + 1); 176 } else { 177 hwdst = &baddr; 178 } 179 180 switch (dst->sa_family) { 181 #ifdef INET 182 case AF_INET: 183 if (unicast && (!arpresolve(ifp, rt, m0, dst, (u_char *)hwdst))) 184 return 0; /* if not yet resolved */ 185 /* if broadcasting on a simplex interface, loopback a copy */ 186 if ((m0->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX)) 187 mcopy = m_copy(m0, 0, M_COPYALL); 188 etype = htons(ETHERTYPE_IP); 189 break; 190 case AF_ARP: 191 ah = mtod(m0, struct arphdr *); 192 ah->ar_hrd = htons(ARPHRD_IEEE1394); 193 etype = htons(ETHERTYPE_ARP); 194 break; 195 #endif /* INET */ 196 #ifdef INET6 197 case AF_INET6: 198 if (unicast && (!nd6_storelladdr(ifp, rt, m0, dst, 199 hwdst->iha_uid, IEEE1394_ADDR_LEN))) { 200 /* something bad happened */ 201 return 0; 202 } 203 etype = htons(ETHERTYPE_IPV6); 204 break; 205 #endif /* INET6 */ 206 207 case pseudo_AF_HDRCMPLT: 208 case AF_UNSPEC: 209 /* TODO? */ 210 default: 211 printf("%s: can't handle af%d\n", ifp->if_xname, 212 dst->sa_family); 213 senderr(EAFNOSUPPORT); 214 break; 215 } 216 217 if (mcopy) 218 looutput(ifp, mcopy, dst, rt); 219 myaddr = (const struct ieee1394_hwaddr *)CLLADDR(ifp->if_sadl); 220 #if NBPFILTER > 0 221 if (ifp->if_bpf) { 222 struct ieee1394_bpfhdr h; 223 if (unicast) 224 memcpy(h.ibh_dhost, hwdst->iha_uid, 8); 225 else 226 memcpy(h.ibh_dhost, 227 ((const struct ieee1394_hwaddr *) 228 ifp->if_broadcastaddr)->iha_uid, 8); 229 memcpy(h.ibh_shost, myaddr->iha_uid, 8); 230 h.ibh_type = etype; 231 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m0); 232 } 233 #endif 234 if ((ifp->if_flags & IFF_SIMPLEX) && 235 unicast && 236 memcmp(hwdst, myaddr, IEEE1394_ADDR_LEN) == 0) 237 return looutput(ifp, m0, dst, rt); 238 239 /* 240 * XXX: 241 * The maximum possible rate depends on the topology. 242 * So the determination of maxrec and fragmentation should be 243 * called from the driver after probing the topology map. 244 */ 245 if (unicast) { 246 hdrlen = IEEE1394_GASP_LEN; 247 hwdst->iha_speed = 0; /* XXX */ 248 } else 249 hdrlen = 0; 250 251 if (hwdst->iha_speed > myaddr->iha_speed) 252 hwdst->iha_speed = myaddr->iha_speed; 253 if (hwdst->iha_maxrec > myaddr->iha_maxrec) 254 hwdst->iha_maxrec = myaddr->iha_maxrec; 255 if (hwdst->iha_maxrec > (8 + hwdst->iha_speed)) 256 hwdst->iha_maxrec = 8 + hwdst->iha_speed; 257 if (hwdst->iha_maxrec < 8) 258 hwdst->iha_maxrec = 8; 259 260 m0 = ieee1394_fragment(ifp, m0, (2<<hwdst->iha_maxrec) - hdrlen, etype); 261 if (m0 == NULL) 262 senderr(ENOBUFS); 263 264 s = splnet(); 265 ifp->if_obytes += m0->m_pkthdr.len; 266 if (m0->m_flags & M_MCAST) 267 ifp->if_omcasts++; 268 while ((m = m0) != NULL) { 269 m0 = m->m_nextpkt; 270 if (m == NULL) { 271 splx(s); 272 senderr(ENOBUFS); 273 } 274 IFQ_ENQUEUE(&ifp->if_snd, m, &pktattr, error); 275 if (error) { 276 /* mbuf is already freed */ 277 splx(s); 278 goto bad; 279 } 280 } 281 if ((ifp->if_flags & IFF_OACTIVE) == 0) 282 (*ifp->if_start)(ifp); 283 splx(s); 284 return 0; 285 286 bad: 287 while (m0 != NULL) { 288 m = m0->m_nextpkt; 289 m_freem(m0); 290 m0 = m; 291 } 292 293 return error; 294 } 295 296 struct mbuf * 297 ieee1394_fragment(struct ifnet *ifp, struct mbuf *m0, int maxsize, 298 u_int16_t etype) 299 { 300 struct ieee1394com *ic = (struct ieee1394com *)ifp; 301 int totlen, fraglen, off; 302 struct mbuf *m, **mp; 303 struct ieee1394_fraghdr *ifh; 304 struct ieee1394_unfraghdr *iuh; 305 306 totlen = m0->m_pkthdr.len; 307 if (totlen + sizeof(struct ieee1394_unfraghdr) <= maxsize) { 308 M_PREPEND(m0, sizeof(struct ieee1394_unfraghdr), M_DONTWAIT); 309 if (m0 == NULL) 310 goto bad; 311 iuh = mtod(m0, struct ieee1394_unfraghdr *); 312 iuh->iuh_ft = 0; 313 iuh->iuh_etype = etype; 314 return m0; 315 } 316 317 fraglen = maxsize - sizeof(struct ieee1394_fraghdr); 318 319 M_PREPEND(m0, sizeof(struct ieee1394_fraghdr), M_DONTWAIT); 320 if (m0 == NULL) 321 goto bad; 322 ifh = mtod(m0, struct ieee1394_fraghdr *); 323 ifh->ifh_ft_size = htons(IEEE1394_FT_MORE | (totlen - 1)); 324 ifh->ifh_etype_off = etype; 325 ifh->ifh_dgl = htons(ic->ic_dgl); 326 ifh->ifh_reserved = 0; 327 off = fraglen; 328 mp = &m0->m_nextpkt; 329 while (off < totlen) { 330 if (off + fraglen > totlen) 331 fraglen = totlen - off; 332 MGETHDR(m, M_DONTWAIT, MT_HEADER); 333 if (m == NULL) 334 goto bad; 335 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST); /* copy bcast */ 336 MH_ALIGN(m, sizeof(struct ieee1394_fraghdr)); 337 m->m_len = sizeof(struct ieee1394_fraghdr); 338 ifh = mtod(m, struct ieee1394_fraghdr *); 339 ifh->ifh_ft_size = 340 htons(IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE | (totlen - 1)); 341 ifh->ifh_etype_off = htons(off); 342 ifh->ifh_dgl = htons(ic->ic_dgl); 343 ifh->ifh_reserved = 0; 344 m->m_next = m_copy(m0, sizeof(*ifh) + off, fraglen); 345 if (m->m_next == NULL) 346 goto bad; 347 m->m_pkthdr.len = sizeof(*ifh) + fraglen; 348 off += fraglen; 349 *mp = m; 350 mp = &m->m_nextpkt; 351 } 352 ifh->ifh_ft_size &= ~htons(IEEE1394_FT_MORE); /* last fragment */ 353 m_adj(m0, -(m0->m_pkthdr.len - maxsize)); 354 355 ic->ic_dgl++; 356 return m0; 357 358 bad: 359 while ((m = m0) != NULL) { 360 m0 = m->m_nextpkt; 361 m->m_nextpkt = NULL; 362 m_freem(m); 363 } 364 return NULL; 365 } 366 367 void 368 ieee1394_input(struct ifnet *ifp, struct mbuf *m, u_int16_t src) 369 { 370 struct ifqueue *inq; 371 u_int16_t etype; 372 int s; 373 struct ieee1394_unfraghdr *iuh; 374 375 if ((ifp->if_flags & IFF_UP) == 0) { 376 m_freem(m); 377 return; 378 } 379 if (m->m_len < sizeof(*iuh)) { 380 if ((m = m_pullup(m, sizeof(*iuh))) == NULL) 381 return; 382 } 383 384 iuh = mtod(m, struct ieee1394_unfraghdr *); 385 386 if (ntohs(iuh->iuh_ft) & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE)) { 387 if ((m = ieee1394_reass(ifp, m, src)) == NULL) 388 return; 389 iuh = mtod(m, struct ieee1394_unfraghdr *); 390 } 391 etype = ntohs(iuh->iuh_etype); 392 393 /* strip off the ieee1394 header */ 394 m_adj(m, sizeof(*iuh)); 395 #if NBPFILTER > 0 396 if (ifp->if_bpf) { 397 struct ieee1394_bpfhdr h; 398 struct m_tag *mtag; 399 const struct ieee1394_hwaddr *myaddr; 400 401 mtag = m_tag_locate(m, 402 MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0); 403 if (mtag) 404 memcpy(h.ibh_shost, mtag + 1, 8); 405 else 406 memset(h.ibh_shost, 0, 8); 407 if (m->m_flags & M_BCAST) 408 memcpy(h.ibh_dhost, 409 ((const struct ieee1394_hwaddr *) 410 ifp->if_broadcastaddr)->iha_uid, 8); 411 else { 412 myaddr = 413 (const struct ieee1394_hwaddr *)CLLADDR(ifp->if_sadl); 414 memcpy(h.ibh_dhost, myaddr->iha_uid, 8); 415 } 416 h.ibh_type = htons(etype); 417 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m); 418 } 419 #endif 420 421 switch (etype) { 422 #ifdef INET 423 case ETHERTYPE_IP: 424 schednetisr(NETISR_IP); 425 inq = &ipintrq; 426 break; 427 428 case ETHERTYPE_ARP: 429 schednetisr(NETISR_ARP); 430 inq = &arpintrq; 431 break; 432 #endif /* INET */ 433 434 #ifdef INET6 435 case ETHERTYPE_IPV6: 436 schednetisr(NETISR_IPV6); 437 inq = &ip6intrq; 438 break; 439 #endif /* INET6 */ 440 441 default: 442 m_freem(m); 443 return; 444 } 445 446 s = splnet(); 447 if (IF_QFULL(inq)) { 448 IF_DROP(inq); 449 m_freem(m); 450 } else 451 IF_ENQUEUE(inq, m); 452 splx(s); 453 } 454 455 static struct mbuf * 456 ieee1394_reass(struct ifnet *ifp, struct mbuf *m0, u_int16_t src) 457 { 458 struct ieee1394com *ic = (struct ieee1394com *)ifp; 459 struct ieee1394_fraghdr *ifh; 460 struct ieee1394_unfraghdr *iuh; 461 struct ieee1394_reassq *rq; 462 struct ieee1394_reass_pkt *rp, *trp, *nrp = NULL; 463 int len; 464 u_int16_t etype, off, ftype, size, dgl; 465 u_int32_t id; 466 467 if (m0->m_len < sizeof(*ifh)) { 468 if ((m0 = m_pullup(m0, sizeof(*ifh))) == NULL) 469 return NULL; 470 } 471 ifh = mtod(m0, struct ieee1394_fraghdr *); 472 m_adj(m0, sizeof(*ifh)); 473 size = ntohs(ifh->ifh_ft_size); 474 ftype = size & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE); 475 size = (size & ~ftype) + 1; 476 dgl = ntohs(ifh->ifh_dgl); 477 len = m0->m_pkthdr.len; 478 id = dgl | (src << 16); 479 if (ftype & IEEE1394_FT_SUBSEQ) { 480 m_tag_delete_chain(m0, NULL); 481 m0->m_flags &= ~M_PKTHDR; 482 etype = 0; 483 off = ntohs(ifh->ifh_etype_off); 484 } else { 485 etype = ifh->ifh_etype_off; 486 off = 0; 487 } 488 489 for (rq = LIST_FIRST(&ic->ic_reassq); ; rq = LIST_NEXT(rq, rq_node)) { 490 if (rq == NULL) { 491 /* 492 * Create a new reassemble queue head for the node. 493 */ 494 rq = malloc(sizeof(*rq), M_FTABLE, M_NOWAIT); 495 if (rq == NULL) { 496 m_freem(m0); 497 return NULL; 498 } 499 rq->fr_id = id; 500 LIST_INIT(&rq->rq_pkt); 501 LIST_INSERT_HEAD(&ic->ic_reassq, rq, rq_node); 502 break; 503 } 504 if (rq->fr_id == id) 505 break; 506 } 507 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) { 508 nrp = LIST_NEXT(rp, rp_next); 509 if (rp->rp_dgl != dgl) 510 continue; 511 /* 512 * sanity check: 513 * datagram size must be same for all fragments, and 514 * no overlap is allowed. 515 */ 516 if (rp->rp_size != size || 517 (off < rp->rp_off + rp->rp_len && off + len > rp->rp_off)) { 518 /* 519 * This happens probably due to wrapping dgl value. 520 * Destroy all previously received fragment and 521 * enqueue current fragment. 522 */ 523 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; 524 rp = nrp) { 525 nrp = LIST_NEXT(rp, rp_next); 526 if (rp->rp_dgl == dgl) { 527 LIST_REMOVE(rp, rp_next); 528 m_freem(rp->rp_m); 529 free(rp, M_FTABLE); 530 } 531 } 532 break; 533 } 534 if (rp->rp_off + rp->rp_len == off) { 535 /* 536 * All the subsequent fragments received in sequence 537 * come here. 538 * Concatinate mbuf to previous one instead of 539 * allocating new reassemble queue structure, 540 * and try to merge more with the subsequent fragment 541 * in the queue. 542 */ 543 m_cat(rp->rp_m, m0); 544 rp->rp_len += len; 545 while (rp->rp_off + rp->rp_len < size && 546 nrp != NULL && nrp->rp_dgl == dgl && 547 nrp->rp_off == rp->rp_off + rp->rp_len) { 548 LIST_REMOVE(nrp, rp_next); 549 m_cat(rp->rp_m, nrp->rp_m); 550 rp->rp_len += nrp->rp_len; 551 free(nrp, M_FTABLE); 552 nrp = LIST_NEXT(rp, rp_next); 553 } 554 m0 = NULL; /* mark merged */ 555 break; 556 } 557 if (off + m0->m_pkthdr.len == rp->rp_off) { 558 m_cat(m0, rp->rp_m); 559 rp->rp_m = m0; 560 rp->rp_off = off; 561 rp->rp_etype = etype; /* over writing trust etype */ 562 rp->rp_len += len; 563 m0 = NULL; /* mark merged */ 564 break; 565 } 566 if (rp->rp_off > off) { 567 /* insert before rp */ 568 nrp = rp; 569 break; 570 } 571 if (nrp == NULL || nrp->rp_dgl != dgl) { 572 /* insert after rp */ 573 nrp = NULL; 574 break; 575 } 576 } 577 if (m0 == NULL) { 578 if (rp->rp_off != 0 || rp->rp_len != size) 579 return NULL; 580 /* fragment done */ 581 LIST_REMOVE(rp, rp_next); 582 m0 = rp->rp_m; 583 m0->m_pkthdr.len = rp->rp_len; 584 M_PREPEND(m0, sizeof(*iuh), M_DONTWAIT); 585 if (m0 != NULL) { 586 iuh = mtod(m0, struct ieee1394_unfraghdr *); 587 iuh->iuh_ft = 0; 588 iuh->iuh_etype = rp->rp_etype; 589 } 590 free(rp, M_FTABLE); 591 return m0; 592 } 593 594 /* 595 * New fragment received. Allocate reassemble queue structure. 596 */ 597 trp = malloc(sizeof(*trp), M_FTABLE, M_NOWAIT); 598 if (trp == NULL) { 599 m_freem(m0); 600 return NULL; 601 } 602 trp->rp_m = m0; 603 trp->rp_size = size; 604 trp->rp_etype = etype; /* valid only if off==0 */ 605 trp->rp_off = off; 606 trp->rp_dgl = dgl; 607 trp->rp_len = len; 608 trp->rp_ttl = IEEE1394_REASS_TIMEOUT; 609 if (trp->rp_ttl <= ifp->if_timer) 610 trp->rp_ttl = ifp->if_timer + 1; 611 612 if (rp == NULL) { 613 /* first fragment for the dgl */ 614 LIST_INSERT_HEAD(&rq->rq_pkt, trp, rp_next); 615 } else if (nrp == NULL) { 616 /* no next fragment for the dgl */ 617 LIST_INSERT_AFTER(rp, trp, rp_next); 618 } else { 619 /* there is a hole */ 620 LIST_INSERT_BEFORE(nrp, trp, rp_next); 621 } 622 return NULL; 623 } 624 625 void 626 ieee1394_drain(struct ifnet *ifp) 627 { 628 struct ieee1394com *ic = (struct ieee1394com *)ifp; 629 struct ieee1394_reassq *rq; 630 struct ieee1394_reass_pkt *rp; 631 632 while ((rq = LIST_FIRST(&ic->ic_reassq)) != NULL) { 633 LIST_REMOVE(rq, rq_node); 634 while ((rp = LIST_FIRST(&rq->rq_pkt)) != NULL) { 635 LIST_REMOVE(rp, rp_next); 636 m_freem(rp->rp_m); 637 free(rp, M_FTABLE); 638 } 639 free(rq, M_FTABLE); 640 } 641 } 642 643 void 644 ieee1394_watchdog(struct ifnet *ifp) 645 { 646 struct ieee1394com *ic = (struct ieee1394com *)ifp; 647 struct ieee1394_reassq *rq; 648 struct ieee1394_reass_pkt *rp, *nrp; 649 int dec; 650 651 dec = (ifp->if_timer > 0) ? ifp->if_timer : 1; 652 for (rq = LIST_FIRST(&ic->ic_reassq); rq != NULL; 653 rq = LIST_NEXT(rq, rq_node)) { 654 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) { 655 nrp = LIST_NEXT(rp, rp_next); 656 if (rp->rp_ttl >= dec) 657 rp->rp_ttl -= dec; 658 else { 659 LIST_REMOVE(rp, rp_next); 660 m_freem(rp->rp_m); 661 free(rp, M_FTABLE); 662 } 663 } 664 } 665 } 666 667 const char * 668 ieee1394_sprintf(const u_int8_t *laddr) 669 { 670 static char buf[3*8]; 671 672 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", 673 laddr[0], laddr[1], laddr[2], laddr[3], 674 laddr[4], laddr[5], laddr[6], laddr[7]); 675 return buf; 676 } 677 678 void 679 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr) 680 { 681 struct ieee1394_hwaddr *baddr; 682 struct ieee1394com *ic = (struct ieee1394com *)ifp; 683 684 ifp->if_type = IFT_IEEE1394; 685 ifp->if_addrlen = sizeof(struct ieee1394_hwaddr); 686 ifp->if_hdrlen = sizeof(struct ieee1394_header); 687 ifp->if_dlt = DLT_EN10MB; /* XXX */ 688 ifp->if_mtu = IEEE1394MTU; 689 ifp->if_output = ieee1394_output; 690 ifp->if_drain = ieee1394_drain; 691 ifp->if_watchdog = ieee1394_watchdog; 692 ifp->if_timer = 1; 693 if (ifp->if_baudrate == 0) 694 ifp->if_baudrate = IF_Mbps(100); 695 696 if_alloc_sadl(ifp); 697 (void)sockaddr_dl_setaddr(ifp->if_sadl, ifp->if_sadl->sdl_len, 698 hwaddr, ifp->if_addrlen); 699 700 baddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK); 701 memset(baddr->iha_uid, 0xff, IEEE1394_ADDR_LEN); 702 baddr->iha_speed = 0; /*XXX: how to determine the speed for bcast? */ 703 baddr->iha_maxrec = 512 << baddr->iha_speed; 704 memset(baddr->iha_offset, 0, sizeof(baddr->iha_offset)); 705 ifp->if_broadcastaddr = (uint8_t *)baddr; 706 LIST_INIT(&ic->ic_reassq); 707 #if NBPFILTER > 0 708 bpfattach(ifp, 709 DLT_APPLE_IP_OVER_IEEE1394, sizeof(struct ieee1394_hwaddr)); 710 #endif 711 } 712 713 void 714 ieee1394_ifdetach(struct ifnet *ifp) 715 { 716 ieee1394_drain(ifp); 717 #if NBPFILTER > 0 718 bpfdetach(ifp); 719 #endif 720 free(__UNCONST(ifp->if_broadcastaddr), M_DEVBUF); 721 ifp->if_broadcastaddr = NULL; 722 #if 0 /* done in if_detach() */ 723 if_free_sadl(ifp); 724 #endif 725 } 726 727 int 728 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, void *data) 729 { 730 struct ifreq *ifr = (struct ifreq *)data; 731 struct ifaddr *ifa = (struct ifaddr *)data; 732 int error = 0; 733 #if __NetBSD_Version__ < 105080000 734 int fw_init(struct ifnet *); 735 void fw_stop(struct ifnet *, int); 736 #endif 737 738 switch (cmd) { 739 case SIOCSIFADDR: 740 ifp->if_flags |= IFF_UP; 741 switch (ifa->ifa_addr->sa_family) { 742 #ifdef INET 743 case AF_INET: 744 #if __NetBSD_Version__ >= 105080000 745 if ((error = (*ifp->if_init)(ifp)) != 0) 746 #else 747 if ((error = fw_init(ifp)) != 0) 748 #endif 749 break; 750 arp_ifinit(ifp, ifa); 751 break; 752 #endif /* INET */ 753 default: 754 #if __NetBSD_Version__ >= 105080000 755 error = (*ifp->if_init)(ifp); 756 #else 757 error = fw_init(ifp); 758 #endif 759 break; 760 } 761 break; 762 763 case SIOCGIFADDR: 764 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data, 765 CLLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN); 766 break; 767 768 case SIOCSIFMTU: 769 if (ifr->ifr_mtu > IEEE1394MTU) 770 error = EINVAL; 771 else 772 ifp->if_mtu = ifr->ifr_mtu; 773 break; 774 775 default: 776 error = ENOTTY; 777 break; 778 } 779 780 return error; 781 } 782