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