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