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