if_fwsubr.c revision 130407
1275988Sngie/*
2240116Smarcel * Copyright (c) 2004 Doug Rabson
3240116Smarcel * Copyright (c) 1982, 1989, 1993
4240116Smarcel *	The Regents of the University of California.  All rights reserved.
5240116Smarcel *
6240116Smarcel * Redistribution and use in source and binary forms, with or without
7240116Smarcel * modification, are permitted provided that the following conditions
8240116Smarcel * are met:
9240116Smarcel * 1. Redistributions of source code must retain the above copyright
10240116Smarcel *    notice, this list of conditions and the following disclaimer.
11240116Smarcel * 2. Redistributions in binary form must reproduce the above copyright
12240116Smarcel *    notice, this list of conditions and the following disclaimer in the
13240116Smarcel *    documentation and/or other materials provided with the distribution.
14240116Smarcel * 3. All advertising materials mentioning features or use of this software
15240116Smarcel *    must display the following acknowledgement:
16240116Smarcel *	This product includes software developed by the University of
17240116Smarcel *	California, Berkeley and its contributors.
18240116Smarcel * 4. Neither the name of the University nor the names of its contributors
19240116Smarcel *    may be used to endorse or promote products derived from this software
20240116Smarcel *    without specific prior written permission.
21240116Smarcel *
22240116Smarcel * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23240116Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24275988Sngie * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25240116Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26275988Sngie * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27275988Sngie * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28240116Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29240116Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30240116Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31240116Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32240116Smarcel * SUCH DAMAGE.
33240116Smarcel *
34240116Smarcel * $FreeBSD: head/sys/net/if_fwsubr.c 130407 2004-06-13 10:54:36Z dfr $
35240116Smarcel */
36240116Smarcel
37240116Smarcel#include "opt_inet.h"
38240116Smarcel#include "opt_inet6.h"
39240116Smarcel
40240116Smarcel#include <sys/param.h>
41240116Smarcel#include <sys/systm.h>
42275988Sngie#include <sys/kernel.h>
43275988Sngie#include <sys/malloc.h>
44275988Sngie#include <sys/mbuf.h>
45275988Sngie#include <sys/socket.h>
46275988Sngie#include <sys/sockio.h>
47240116Smarcel
48240116Smarcel#include <net/if.h>
49240116Smarcel#include <net/netisr.h>
50240116Smarcel#include <net/route.h>
51240116Smarcel#include <net/if_llc.h>
52240116Smarcel#include <net/if_dl.h>
53240116Smarcel#include <net/if_types.h>
54240116Smarcel#include <net/bpf.h>
55240116Smarcel#include <net/firewire.h>
56240116Smarcel
57240116Smarcel#if defined(INET) || defined(INET6)
58240116Smarcel#include <netinet/in.h>
59240116Smarcel#include <netinet/in_var.h>
60240116Smarcel#include <netinet/if_ether.h>
61240116Smarcel#include <netinet/ip_fw.h>
62240116Smarcel#include <netinet/ip_dummynet.h>
63240116Smarcel#endif
64240116Smarcel#ifdef INET6
65240116Smarcel#include <netinet6/nd6.h>
66240116Smarcel#endif
67240116Smarcel
68240116Smarcel#define IFP2FC(IFP) ((struct fw_com *)IFP)
69240116Smarcel
70240116Smarcelstruct fw_hwaddr firewire_broadcastaddr = {
71240116Smarcel	0xffffffff,
72240116Smarcel	0xffffffff,
73240116Smarcel	0xff,
74240116Smarcel	0xff,
75240116Smarcel	0xffff,
76240116Smarcel	0xffffffff
77240116Smarcel};
78240116Smarcel
79240116Smarcelstatic int
80240116Smarcelfirewire_output(struct ifnet *ifp, struct mbuf *m, struct sockaddr *dst,
81240116Smarcel    struct rtentry *rt0)
82240116Smarcel{
83240116Smarcel	struct fw_com *fc = (struct fw_com *) ifp;
84240116Smarcel	int error, type;
85240116Smarcel	struct rtentry *rt;
86240116Smarcel	struct m_tag *mtag;
87240116Smarcel	union fw_encap *enc;
88240116Smarcel	struct fw_hwaddr *destfw;
89240116Smarcel	uint8_t speed;
90240116Smarcel	uint16_t psize, fsize, dsize;
91240116Smarcel	struct mbuf *mtail;
92240116Smarcel	int unicast, dgl, foff;
93240116Smarcel	static int next_dgl;
94240116Smarcel
95240116Smarcel	GIANT_REQUIRED;
96240116Smarcel
97240116Smarcel	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) {
98240116Smarcel		error = ENETDOWN;
99240116Smarcel		goto bad;
100240116Smarcel	}
101240116Smarcel
102240116Smarcel	error = rt_check(&rt, &rt0, dst);
103240116Smarcel	if (error)
104240116Smarcel		goto bad;
105240116Smarcel
106240116Smarcel	/*
107240116Smarcel	 * For unicast, we make a tag to store the lladdr of the
108240116Smarcel	 * destination. This might not be the first time we have seen
109240116Smarcel	 * the packet (for instance, the arp code might be trying to
110240116Smarcel	 * re-send it after receiving an arp reply) so we only
111240116Smarcel	 * allocate a tag if there isn't one there already. For
112240116Smarcel	 * multicast, we will eventually use a different tag to store
113240116Smarcel	 * the channel number.
114240116Smarcel	 */
115240116Smarcel	unicast = !(m->m_flags & (M_BCAST | M_MCAST));
116240116Smarcel	if (unicast) {
117240116Smarcel		mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR, NULL);
118240116Smarcel		if (!mtag) {
119240116Smarcel			mtag = m_tag_alloc(MTAG_FIREWIRE, MTAG_FIREWIRE_HWADDR,
120240116Smarcel			    sizeof (struct fw_hwaddr), M_NOWAIT);
121240116Smarcel			if (!mtag) {
122240116Smarcel				error = ENOMEM;
123240116Smarcel				goto bad;
124240116Smarcel			}
125240116Smarcel			m_tag_prepend(m, mtag);
126240116Smarcel		}
127240116Smarcel		destfw = (struct fw_hwaddr *)(mtag + 1);
128240116Smarcel	} else {
129240116Smarcel		destfw = 0;
130240116Smarcel	}
131240116Smarcel
132240116Smarcel	switch (dst->sa_family) {
133240116Smarcel#ifdef AF_INET
134240116Smarcel	case AF_INET:
135240116Smarcel		/*
136240116Smarcel		 * Only bother with arp for unicast. Allocation of
137240116Smarcel		 * channels etc. for firewire is quite different and
138240116Smarcel		 * doesn't fit into the arp model.
139240116Smarcel		 */
140240116Smarcel		if (unicast) {
141240116Smarcel			error = arpresolve(ifp, rt, m, dst, (u_char *) destfw);
142240116Smarcel			if (error)
143240116Smarcel				return (error == EWOULDBLOCK ? 0 : error);
144240116Smarcel		}
145240116Smarcel		type = ETHERTYPE_IP;
146240116Smarcel		break;
147240116Smarcel
148240116Smarcel	case AF_ARP:
149240116Smarcel	{
150240116Smarcel		struct arphdr *ah;
151240116Smarcel		ah = mtod(m, struct arphdr *);
152240116Smarcel		ah->ar_hrd = htons(ARPHRD_IEEE1394);
153240116Smarcel		type = ETHERTYPE_ARP;
154240116Smarcel		if (unicast)
155240116Smarcel			*destfw = *(struct fw_hwaddr *) ar_tha(ah);
156240116Smarcel
157240116Smarcel		/*
158240116Smarcel		 * The standard arp code leaves a hole for the target
159240116Smarcel		 * hardware address which we need to close up.
160240116Smarcel		 */
161240116Smarcel		bcopy(ar_tpa(ah), ar_tha(ah), ah->ar_pln);
162240116Smarcel		m_adj(m, -ah->ar_hln);
163240116Smarcel		break;
164240116Smarcel	}
165240116Smarcel#endif
166240116Smarcel
167240116Smarcel#ifdef INET6
168240116Smarcel	case AF_INET6:
169240116Smarcel		if (unicast) {
170240116Smarcel			error = nd6_storelladdr(&fc->fc_if, rt, m, dst,
171240116Smarcel			    (u_char *) destfw);
172240116Smarcel			if (error)
173240116Smarcel				return (error);
174240116Smarcel		}
175240116Smarcel		type = ETHERTYPE_IPV6;
176240116Smarcel		break;
177240116Smarcel#endif
178240116Smarcel
179240116Smarcel	default:
180240116Smarcel		if_printf(ifp, "can't handle af%d\n", dst->sa_family);
181240116Smarcel		error = EAFNOSUPPORT;
182240116Smarcel		goto bad;
183240116Smarcel	}
184240116Smarcel
185240116Smarcel	/*
186240116Smarcel	 * Let BPF tap off a copy before we encapsulate.
187240116Smarcel	 */
188240116Smarcel	if (ifp->if_bpf) {
189240116Smarcel		struct fw_bpfhdr h;
190240116Smarcel		if (unicast)
191240116Smarcel			bcopy(destfw, h.firewire_dhost, 8);
192240116Smarcel		else
193240116Smarcel			bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8);
194240116Smarcel		bcopy(&fc->fc_hwaddr, h.firewire_shost, 8);
195240116Smarcel		h.firewire_type = htons(type);
196240116Smarcel		bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
197240116Smarcel	}
198240116Smarcel
199240116Smarcel	/*
200240116Smarcel	 * Punt on MCAP for now and send all multicast packets on the
201240116Smarcel	 * broadcast channel.
202240116Smarcel	 */
203240116Smarcel	if (m->m_flags & M_MCAST)
204240116Smarcel		m->m_flags |= M_BCAST;
205240116Smarcel
206240116Smarcel	/*
207240116Smarcel	 * Figure out what speed to use and what the largest supported
208240116Smarcel	 * packet size is. For unicast, this is the minimum of what we
209240116Smarcel	 * can speak and what they can hear. For broadcast, lets be
210240116Smarcel	 * conservative and use S100. We could possibly improve that
211240116Smarcel	 * by examining the bus manager's speed map or similar. We
212240116Smarcel	 * also reduce the packet size for broadcast to account for
213240116Smarcel	 * the GASP header.
214240116Smarcel	 */
215240116Smarcel	if (unicast) {
216240116Smarcel		speed = min(fc->fc_speed, destfw->sspd);
217240116Smarcel		psize = min(512 << speed, 2 << destfw->sender_max_rec);
218240116Smarcel	} else {
219240116Smarcel		speed = 0;
220240116Smarcel		psize = 512 - 2*sizeof(uint32_t);
221240116Smarcel	}
222240116Smarcel
223240116Smarcel	/*
224240116Smarcel	 * Next, we encapsulate, possibly fragmenting the original
225240116Smarcel	 * datagram if it won't fit into a single packet.
226240116Smarcel	 */
227240116Smarcel	if (m->m_pkthdr.len <= psize - sizeof(uint32_t)) {
228240116Smarcel		/*
229240116Smarcel		 * No fragmentation is necessary.
230240116Smarcel		 */
231240116Smarcel		M_PREPEND(m, sizeof(uint32_t), M_DONTWAIT);
232240116Smarcel		if (!m) {
233240116Smarcel			error = ENOBUFS;
234240116Smarcel			goto bad;
235240116Smarcel		}
236240116Smarcel		enc = mtod(m, union fw_encap *);
237240116Smarcel		enc->unfrag.ether_type = type;
238240116Smarcel		enc->unfrag.lf = FW_ENCAP_UNFRAG;
239240116Smarcel
240240116Smarcel		/*
241240116Smarcel		 * Byte swap the encapsulation header manually.
242240116Smarcel		 */
243240116Smarcel		enc->ul[0] = htonl(enc->ul[0]);
244240116Smarcel
245240116Smarcel		return (IF_HANDOFF(&ifp->if_snd, m, ifp) ? 0 : ENOBUFS);
246240116Smarcel	} else {
247240116Smarcel		/*
248240116Smarcel		 * Fragment the datagram, making sure to leave enough
249240116Smarcel		 * space for the encapsulation header in each packet.
250240116Smarcel		 */
251240116Smarcel		fsize = psize - 2*sizeof(uint32_t);
252240116Smarcel		dgl = next_dgl++;
253240116Smarcel		dsize = m->m_pkthdr.len;
254240116Smarcel		foff = 0;
255240116Smarcel		while (m) {
256240116Smarcel			if (m->m_pkthdr.len > fsize) {
257240116Smarcel				/*
258240116Smarcel				 * Split off the tail segment from the
259240116Smarcel				 * datagram, copying our tags over.
260240116Smarcel				 */
261240116Smarcel				mtail = m_split(m, fsize, M_DONTWAIT);
262240116Smarcel				m_tag_copy_chain(mtail, m, M_NOWAIT);
263240116Smarcel			} else {
264240116Smarcel				mtail = 0;
265240116Smarcel			}
266240116Smarcel
267240116Smarcel			/*
268240116Smarcel			 * Add our encapsulation header to this
269240116Smarcel			 * fragment and hand it off to the link.
270240116Smarcel			 */
271240116Smarcel			M_PREPEND(m, 2*sizeof(uint32_t), M_DONTWAIT);
272240116Smarcel			if (!m) {
273240116Smarcel				error = ENOBUFS;
274240116Smarcel				goto bad;
275240116Smarcel			}
276240116Smarcel			enc = mtod(m, union fw_encap *);
277240116Smarcel			if (foff == 0) {
278240116Smarcel				enc->firstfrag.lf = FW_ENCAP_FIRST;
279240116Smarcel				enc->firstfrag.datagram_size = dsize - 1;
280240116Smarcel				enc->firstfrag.ether_type = type;
281240116Smarcel				enc->firstfrag.dgl = dgl;
282240116Smarcel			} else {
283240116Smarcel				if (mtail)
284240116Smarcel					enc->nextfrag.lf = FW_ENCAP_NEXT;
285240116Smarcel				else
286240116Smarcel					enc->nextfrag.lf = FW_ENCAP_LAST;
287240116Smarcel				enc->nextfrag.datagram_size = dsize - 1;
288240116Smarcel				enc->nextfrag.fragment_offset = foff;
289240116Smarcel				enc->nextfrag.dgl = dgl;
290240116Smarcel			}
291240116Smarcel			foff += m->m_pkthdr.len - 2*sizeof(uint32_t);
292240116Smarcel
293240116Smarcel			/*
294240116Smarcel			 * Byte swap the encapsulation header manually.
295240116Smarcel			 */
296240116Smarcel			enc->ul[0] = htonl(enc->ul[0]);
297240116Smarcel			enc->ul[1] = htonl(enc->ul[1]);
298240116Smarcel
299240116Smarcel			if (!IF_HANDOFF(&ifp->if_snd, m, ifp)) {
300240116Smarcel				if (mtail)
301240116Smarcel					m_freem(mtail);
302240116Smarcel				return (ENOBUFS);
303240116Smarcel			}
304240116Smarcel
305240116Smarcel			m = mtail;
306240116Smarcel		}
307240116Smarcel
308240116Smarcel		return (0);
309240116Smarcel	}
310240116Smarcel
311240116Smarcelbad:
312240116Smarcel	if (m)
313240116Smarcel		m_freem(m);
314240116Smarcel	return (error);
315240116Smarcel}
316240116Smarcel
317240116Smarcelstatic struct mbuf *
318240116Smarcelfirewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src)
319240116Smarcel{
320240116Smarcel	union fw_encap *enc;
321240116Smarcel	struct fw_reass *r;
322240116Smarcel	struct mbuf *mf, *mprev;
323240116Smarcel	int dsize;
324240116Smarcel	int fstart, fend, start, end, islast;
325240116Smarcel	uint32_t id;
326240116Smarcel
327240116Smarcel	GIANT_REQUIRED;
328240116Smarcel
329240116Smarcel	/*
330240116Smarcel	 * Find an existing reassembly buffer or create a new one.
331240116Smarcel	 */
332240116Smarcel	enc = mtod(m, union fw_encap *);
333240116Smarcel	id = enc->firstfrag.dgl | (src << 16);
334240116Smarcel	STAILQ_FOREACH(r, &fc->fc_frags, fr_link)
335240116Smarcel		if (r->fr_id == id)
336240116Smarcel			break;
337240116Smarcel	if (!r) {
338240116Smarcel		r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT);
339240116Smarcel		if (!r) {
340240116Smarcel			m_freem(m);
341240116Smarcel			return 0;
342240116Smarcel		}
343240116Smarcel		r->fr_id = id;
344240116Smarcel		r->fr_frags = 0;
345240116Smarcel		STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link);
346240116Smarcel	}
347240116Smarcel
348240116Smarcel	/*
349240116Smarcel	 * If this fragment overlaps any other fragment, we must discard
350240116Smarcel	 * the partial reassembly and start again.
351240116Smarcel	 */
352240116Smarcel	if (enc->firstfrag.lf == FW_ENCAP_FIRST)
353240116Smarcel		fstart = 0;
354240116Smarcel	else
355240116Smarcel		fstart = enc->nextfrag.fragment_offset;
356240116Smarcel	fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t);
357240116Smarcel	dsize = enc->nextfrag.datagram_size;
358240116Smarcel	islast = (enc->nextfrag.lf == FW_ENCAP_LAST);
359240116Smarcel
360240116Smarcel	for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) {
361240116Smarcel		enc = mtod(mf, union fw_encap *);
362240116Smarcel		if (enc->nextfrag.datagram_size != dsize) {
363240116Smarcel			/*
364240116Smarcel			 * This fragment must be from a different
365240116Smarcel			 * packet.
366240116Smarcel			 */
367240116Smarcel			goto bad;
368240116Smarcel		}
369240116Smarcel		if (enc->firstfrag.lf == FW_ENCAP_FIRST)
370240116Smarcel			start = 0;
371240116Smarcel		else
372240116Smarcel			start = enc->nextfrag.fragment_offset;
373240116Smarcel		end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t);
374240116Smarcel		if ((fstart < end && fend > start) ||
375240116Smarcel		    (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) {
376240116Smarcel			/*
377240116Smarcel			 * Overlap - discard reassembly buffer and start
378240116Smarcel			 * again with this fragment.
379240116Smarcel			 */
380240116Smarcel			goto bad;
381240116Smarcel		}
382240116Smarcel	}
383240116Smarcel
384240116Smarcel	/*
385240116Smarcel	 * Find where to put this fragment in the list.
386240116Smarcel	 */
387240116Smarcel	for (mf = r->fr_frags, mprev = NULL; mf;
388240116Smarcel	    mprev = mf, mf = mf->m_nextpkt) {
389240116Smarcel		enc = mtod(mf, union fw_encap *);
390240116Smarcel		if (enc->firstfrag.lf == FW_ENCAP_FIRST)
391240116Smarcel			start = 0;
392240116Smarcel		else
393240116Smarcel			start = enc->nextfrag.fragment_offset;
394240116Smarcel		if (start >= fend)
395240116Smarcel			break;
396240116Smarcel	}
397240116Smarcel
398240116Smarcel	/*
399240116Smarcel	 * If this is a last fragment and we are not adding at the end
400240116Smarcel	 * of the list, discard the buffer.
401240116Smarcel	 */
402240116Smarcel	if (islast && mprev && mprev->m_nextpkt)
403240116Smarcel		goto bad;
404240116Smarcel
405240116Smarcel	if (mprev) {
406240116Smarcel		m->m_nextpkt = mprev->m_nextpkt;
407240116Smarcel		mprev->m_nextpkt = m;
408240116Smarcel
409240116Smarcel		/*
410240116Smarcel		 * Coalesce forwards and see if we can make a whole
411240116Smarcel		 * datagram.
412240116Smarcel		 */
413240116Smarcel		enc = mtod(mprev, union fw_encap *);
414240116Smarcel		if (enc->firstfrag.lf == FW_ENCAP_FIRST)
415240116Smarcel			start = 0;
416240116Smarcel		else
417240116Smarcel			start = enc->nextfrag.fragment_offset;
418240116Smarcel		end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t);
419240116Smarcel		while (end == fstart) {
420240116Smarcel			/*
421240116Smarcel			 * Strip off the encap header from m and
422240116Smarcel			 * append it to mprev, freeing m.
423240116Smarcel			 */
424240116Smarcel			m_adj(m, 2*sizeof(uint32_t));
425240116Smarcel			mprev->m_nextpkt = m->m_nextpkt;
426240116Smarcel			mprev->m_pkthdr.len += m->m_pkthdr.len;
427240116Smarcel			m_cat(mprev, m);
428240116Smarcel
429240116Smarcel			if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) {
430240116Smarcel				/*
431240116Smarcel				 * We have assembled a complete packet
432240116Smarcel				 * we must be finished. Make sure we have
433240116Smarcel				 * merged the whole chain.
434240116Smarcel				 */
435240116Smarcel				STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link);
436240116Smarcel				free(r, M_TEMP);
437240116Smarcel				m = mprev->m_nextpkt;
438240116Smarcel				while (m) {
439240116Smarcel					mf = m->m_nextpkt;
440240116Smarcel					m_freem(m);
441240116Smarcel					m = mf;
442240116Smarcel				}
443240116Smarcel				mprev->m_nextpkt = NULL;
444240116Smarcel
445240116Smarcel				return (mprev);
446240116Smarcel			}
447240116Smarcel
448240116Smarcel			/*
449240116Smarcel			 * See if we can continue merging forwards.
450240116Smarcel			 */
451240116Smarcel			end = fend;
452240116Smarcel			m = mprev->m_nextpkt;
453240116Smarcel			if (m) {
454240116Smarcel				enc = mtod(m, union fw_encap *);
455240116Smarcel				if (enc->firstfrag.lf == FW_ENCAP_FIRST)
456240116Smarcel					fstart = 0;
457240116Smarcel				else
458240116Smarcel					fstart = enc->nextfrag.fragment_offset;
459240116Smarcel				fend = fstart + m->m_pkthdr.len
460240116Smarcel				    - 2*sizeof(uint32_t);
461240116Smarcel			} else {
462240116Smarcel				break;
463240116Smarcel			}
464240116Smarcel		}
465240116Smarcel	} else {
466240116Smarcel		m->m_nextpkt = 0;
467240116Smarcel		r->fr_frags = m;
468240116Smarcel	}
469240116Smarcel
470240116Smarcel	return (0);
471240116Smarcel
472240116Smarcelbad:
473240116Smarcel	while (r->fr_frags) {
474240116Smarcel		mf = r->fr_frags;
475240116Smarcel		r->fr_frags = mf->m_nextpkt;
476240116Smarcel		m_freem(mf);
477240116Smarcel	}
478240116Smarcel	m->m_nextpkt = 0;
479240116Smarcel	r->fr_frags = m;
480240116Smarcel
481240116Smarcel	return (0);
482240116Smarcel}
483240116Smarcel
484240116Smarcelvoid
485240116Smarcelfirewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src)
486240116Smarcel{
487240116Smarcel	struct fw_com *fc = (struct fw_com *) ifp;
488240116Smarcel	union fw_encap *enc;
489240116Smarcel	int type, isr;
490240116Smarcel
491240116Smarcel	GIANT_REQUIRED;
492240116Smarcel
493240116Smarcel	/*
494240116Smarcel	 * The caller has already stripped off the packet header
495240116Smarcel	 * (stream or wreqb) and marked the mbuf's M_BCAST flag
496240116Smarcel	 * appropriately. We de-encapsulate the IP packet and pass it
497240116Smarcel	 * up the line after handling link-level fragmentation.
498240116Smarcel	 */
499240116Smarcel	if (m->m_pkthdr.len < sizeof(uint32_t)) {
500240116Smarcel		if_printf(ifp, "discarding frame without "
501240116Smarcel		    "encapsulation header (len %u pkt len %u)\n",
502240116Smarcel		    m->m_len, m->m_pkthdr.len);
503240116Smarcel	}
504240116Smarcel
505240116Smarcel	m = m_pullup(m, sizeof(uint32_t));
506240116Smarcel	enc = mtod(m, union fw_encap *);
507240116Smarcel
508240116Smarcel	/*
509240116Smarcel	 * Byte swap the encapsulation header manually.
510240116Smarcel	 */
511240116Smarcel	enc->ul[0] = htonl(enc->ul[0]);
512240116Smarcel
513240116Smarcel	if (enc->unfrag.lf != 0) {
514240116Smarcel		m = m_pullup(m, 2*sizeof(uint32_t));
515240116Smarcel		if (!m)
516240116Smarcel			return;
517240116Smarcel		enc = mtod(m, union fw_encap *);
518240116Smarcel		enc->ul[1] = htonl(enc->ul[1]);
519240116Smarcel		m = firewire_input_fragment(fc, m, src);
520240116Smarcel		if (!m)
521240116Smarcel			return;
522240116Smarcel		enc = mtod(m, union fw_encap *);
523240116Smarcel		type = enc->firstfrag.ether_type;
524240116Smarcel		m_adj(m, 2*sizeof(uint32_t));
525240116Smarcel	} else {
526240116Smarcel		type = enc->unfrag.ether_type;
527240116Smarcel		m_adj(m, sizeof(uint32_t));
528240116Smarcel	}
529240116Smarcel
530240116Smarcel	if (m->m_pkthdr.rcvif == NULL) {
531240116Smarcel		if_printf(ifp, "discard frame w/o interface pointer\n");
532240116Smarcel		ifp->if_ierrors++;
533240116Smarcel		m_freem(m);
534240116Smarcel		return;
535240116Smarcel	}
536240116Smarcel#ifdef DIAGNOSTIC
537240116Smarcel	if (m->m_pkthdr.rcvif != ifp) {
538240116Smarcel		if_printf(ifp, "Warning, frame marked as received on %s\n",
539240116Smarcel			m->m_pkthdr.rcvif->if_xname);
540240116Smarcel	}
541240116Smarcel#endif
542240116Smarcel
543240116Smarcel#ifdef MAC
544240116Smarcel	/*
545240116Smarcel	 * Tag the mbuf with an appropriate MAC label before any other
546240116Smarcel	 * consumers can get to it.
547240116Smarcel	 */
548240116Smarcel	mac_create_mbuf_from_ifnet(ifp, m);
549240116Smarcel#endif
550240116Smarcel
551240116Smarcel	/*
552240116Smarcel	 * Give bpf a chance at the packet. The link-level driver
553240116Smarcel	 * should have left us a tag with the EUID of the sender.
554240116Smarcel	 */
555240116Smarcel	if (ifp->if_bpf) {
556240116Smarcel		struct fw_bpfhdr h;
557240116Smarcel		struct m_tag *mtag;
558240116Smarcel
559240116Smarcel		mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0);
560240116Smarcel		if (mtag)
561240116Smarcel			bcopy(mtag + 1, h.firewire_shost, 8);
562240116Smarcel		else
563240116Smarcel			bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8);
564240116Smarcel		bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8);
565240116Smarcel		h.firewire_type = htons(type);
566240116Smarcel		bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
567240116Smarcel	}
568240116Smarcel
569240116Smarcel	if (ifp->if_flags & IFF_MONITOR) {
570240116Smarcel		/*
571240116Smarcel		 * Interface marked for monitoring; discard packet.
572240116Smarcel		 */
573240116Smarcel		m_freem(m);
574240116Smarcel		return;
575240116Smarcel	}
576240116Smarcel
577240116Smarcel	ifp->if_ibytes += m->m_pkthdr.len;
578240116Smarcel
579240116Smarcel	/* Discard packet if interface is not up */
580240116Smarcel	if ((ifp->if_flags & IFF_UP) == 0) {
581240116Smarcel		m_freem(m);
582240116Smarcel		return;
583240116Smarcel	}
584240116Smarcel
585240116Smarcel	if (m->m_flags & (M_BCAST|M_MCAST))
586240116Smarcel		ifp->if_imcasts++;
587240116Smarcel
588240116Smarcel	switch (type) {
589240116Smarcel#ifdef INET
590240116Smarcel	case ETHERTYPE_IP:
591240116Smarcel		if (ip_fastforward(m))
592240116Smarcel			return;
593240116Smarcel		isr = NETISR_IP;
594240116Smarcel		break;
595240116Smarcel
596240116Smarcel	case ETHERTYPE_ARP:
597240116Smarcel	{
598240116Smarcel		struct arphdr *ah;
599240116Smarcel		ah = mtod(m, struct arphdr *);
600240116Smarcel
601240116Smarcel		/*
602240116Smarcel		 * Adjust the arp packet to insert an empty tha slot.
603240116Smarcel		 */
604240116Smarcel		m->m_len += ah->ar_hln;
605240116Smarcel		m->m_pkthdr.len += ah->ar_hln;
606240116Smarcel		bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln);
607240116Smarcel		isr = NETISR_ARP;
608240116Smarcel		break;
609240116Smarcel	}
610240116Smarcel#endif
611240116Smarcel
612240116Smarcel#ifdef INET6
613240116Smarcel	case ETHERTYPE_IPV6:
614240116Smarcel		isr = NETISR_IPV6;
615240116Smarcel		break;
616240116Smarcel#endif
617240116Smarcel
618240116Smarcel	default:
619240116Smarcel		m_freem(m);
620240116Smarcel		return;
621240116Smarcel	}
622240116Smarcel
623240116Smarcel	netisr_dispatch(isr, m);
624240116Smarcel}
625240116Smarcel
626240116Smarcelint
627240116Smarcelfirewire_ioctl(struct ifnet *ifp, int command, caddr_t data)
628240116Smarcel{
629240116Smarcel	struct ifaddr *ifa = (struct ifaddr *) data;
630240116Smarcel	struct ifreq *ifr = (struct ifreq *) data;
631240116Smarcel	int error = 0;
632240116Smarcel
633240116Smarcel	switch (command) {
634240116Smarcel	case SIOCSIFADDR:
635240116Smarcel		ifp->if_flags |= IFF_UP;
636240116Smarcel
637240116Smarcel		switch (ifa->ifa_addr->sa_family) {
638240116Smarcel#ifdef INET
639240116Smarcel		case AF_INET:
640240116Smarcel			ifp->if_init(ifp->if_softc);	/* before arpwhohas */
641240116Smarcel			arp_ifinit(ifp, ifa);
642240116Smarcel			break;
643240116Smarcel#endif
644240116Smarcel		default:
645240116Smarcel			ifp->if_init(ifp->if_softc);
646240116Smarcel			break;
647240116Smarcel		}
648240116Smarcel		break;
649240116Smarcel
650240116Smarcel	case SIOCGIFADDR:
651240116Smarcel		{
652240116Smarcel			struct sockaddr *sa;
653240116Smarcel
654240116Smarcel			sa = (struct sockaddr *) & ifr->ifr_data;
655240116Smarcel			bcopy(&IFP2FC(ifp)->fc_hwaddr,
656240116Smarcel			    (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr));
657240116Smarcel		}
658240116Smarcel		break;
659240116Smarcel
660240116Smarcel	case SIOCSIFMTU:
661240116Smarcel		/*
662240116Smarcel		 * Set the interface MTU.
663240116Smarcel		 */
664240116Smarcel		if (ifr->ifr_mtu > 1500) {
665240116Smarcel			error = EINVAL;
666240116Smarcel		} else {
667240116Smarcel			ifp->if_mtu = ifr->ifr_mtu;
668240116Smarcel		}
669240116Smarcel		break;
670240116Smarcel	default:
671240116Smarcel		error = EINVAL;			/* XXX netbsd has ENOTTY??? */
672240116Smarcel		break;
673240116Smarcel	}
674240116Smarcel	return (error);
675240116Smarcel}
676240116Smarcel
677240116Smarcelstatic int
678240116Smarcelfirewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
679240116Smarcel    struct sockaddr *sa)
680240116Smarcel{
681240116Smarcel#ifdef INET
682240116Smarcel	struct sockaddr_in *sin;
683240116Smarcel#endif
684240116Smarcel#ifdef INET6
685240116Smarcel	struct sockaddr_in6 *sin6;
686240116Smarcel#endif
687240116Smarcel
688240116Smarcel	switch(sa->sa_family) {
689240116Smarcel	case AF_LINK:
690240116Smarcel		/*
691240116Smarcel		 * No mapping needed.
692240116Smarcel		 */
693240116Smarcel		*llsa = 0;
694240116Smarcel		return 0;
695240116Smarcel
696240116Smarcel#ifdef INET
697240116Smarcel	case AF_INET:
698240116Smarcel		sin = (struct sockaddr_in *)sa;
699240116Smarcel		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
700240116Smarcel			return EADDRNOTAVAIL;
701240116Smarcel		*llsa = 0;
702240116Smarcel		return 0;
703240116Smarcel#endif
704240116Smarcel#ifdef INET6
705240116Smarcel	case AF_INET6:
706240116Smarcel		sin6 = (struct sockaddr_in6 *)sa;
707240116Smarcel		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
708240116Smarcel			/*
709240116Smarcel			 * An IP6 address of 0 means listen to all
710240116Smarcel			 * of the Ethernet multicast address used for IP6.
711240116Smarcel			 * (This is used for multicast routers.)
712240116Smarcel			 */
713240116Smarcel			ifp->if_flags |= IFF_ALLMULTI;
714240116Smarcel			*llsa = 0;
715240116Smarcel			return 0;
716240116Smarcel		}
717240116Smarcel		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
718240116Smarcel			return EADDRNOTAVAIL;
719240116Smarcel		*llsa = 0;
720240116Smarcel		return 0;
721240116Smarcel#endif
722240116Smarcel
723240116Smarcel	default:
724240116Smarcel		/*
725240116Smarcel		 * Well, the text isn't quite right, but it's the name
726240116Smarcel		 * that counts...
727240116Smarcel		 */
728240116Smarcel		return EAFNOSUPPORT;
729240116Smarcel	}
730240116Smarcel}
731240116Smarcel
732240116Smarcelvoid
733240116Smarcelfirewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc)
734240116Smarcel{
735240116Smarcel	struct fw_com *fc = (struct fw_com *) ifp;
736240116Smarcel	struct ifaddr *ifa;
737240116Smarcel	struct sockaddr_dl *sdl;
738240116Smarcel	static const char* speeds[] = {
739240116Smarcel		"S100", "S200", "S400", "S800",
740240116Smarcel		"S1600", "S3200"
741240116Smarcel	};
742240116Smarcel
743240116Smarcel	fc->fc_speed = llc->sspd;
744240116Smarcel	STAILQ_INIT(&fc->fc_frags);
745240116Smarcel
746240116Smarcel	ifp->if_type = IFT_IEEE1394;
747240116Smarcel	ifp->if_addrlen = sizeof(struct fw_hwaddr);
748240116Smarcel	ifp->if_hdrlen = 0;
749240116Smarcel	if_attach(ifp);
750240116Smarcel	ifp->if_mtu = 1500;	/* XXX */
751240116Smarcel	ifp->if_output = firewire_output;
752240116Smarcel	ifp->if_resolvemulti = firewire_resolvemulti;
753240116Smarcel	ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr;
754240116Smarcel
755240116Smarcel	ifa = ifaddr_byindex(ifp->if_index);
756240116Smarcel	KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
757240116Smarcel	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
758240116Smarcel	sdl->sdl_type = IFT_IEEE1394;
759240116Smarcel	sdl->sdl_alen = ifp->if_addrlen;
760240116Smarcel	bcopy(llc, LLADDR(sdl), ifp->if_addrlen);
761240116Smarcel
762240116Smarcel	bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394,
763240116Smarcel	    sizeof(struct fw_hwaddr));
764240116Smarcel
765240116Smarcel	if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n",
766240116Smarcel	    (uint8_t *) &llc->sender_unique_ID_hi, ":",
767240116Smarcel	    ntohs(llc->sender_unicast_FIFO_hi),
768240116Smarcel	    ntohl(llc->sender_unicast_FIFO_lo),
769240116Smarcel	    speeds[llc->sspd],
770240116Smarcel	    (2 << llc->sender_max_rec));
771240116Smarcel}
772240116Smarcel
773240116Smarcelvoid
774240116Smarcelfirewire_ifdetach(struct ifnet *ifp)
775240116Smarcel{
776240116Smarcel	bpfdetach(ifp);
777240116Smarcel	if_detach(ifp);
778240116Smarcel}
779240116Smarcel
780240116Smarcelvoid
781240116Smarcelfirewire_busreset(struct ifnet *ifp)
782240116Smarcel{
783240116Smarcel	struct fw_com *fc = (struct fw_com *) ifp;
784240116Smarcel	struct fw_reass *r;
785240116Smarcel	struct mbuf *m;
786240116Smarcel
787240116Smarcel	/*
788240116Smarcel	 * Discard any partial datagrams since the host ids may have changed.
789240116Smarcel	 */
790240116Smarcel	while ((r = STAILQ_FIRST(&fc->fc_frags))) {
791240116Smarcel		STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link);
792240116Smarcel		while (r->fr_frags) {
793240116Smarcel			m = r->fr_frags;
794240116Smarcel			r->fr_frags = m->m_nextpkt;
795240116Smarcel			m_freem(m);
796240116Smarcel		}
797240116Smarcel		free(r, M_TEMP);
798240116Smarcel	}
799240116Smarcel}
800240116Smarcel