FreeBSD/Linux Kernel Cross Reference
sys/net/if_fwsubr.c
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: releng/5.4/sys/net/if_fwsubr.c 145335 2005-04-20 19:11:07Z cvs2svn $
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
68 struct fw_hwaddr firewire_broadcastaddr = {
69 0xffffffff,
70 0xffffffff,
71 0xff,
72 0xff,
73 0xffff,
74 0xffffffff
75 };
76
77 static int
78 firewire_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 enc->unfrag.reserved = 0;
242
243 /*
244 * Byte swap the encapsulation header manually.
245 */
246 enc->ul[0] = htonl(enc->ul[0]);
247
248 IFQ_HANDOFF(ifp, m, error);
249 return (error);
250 } else {
251 /*
252 * Fragment the datagram, making sure to leave enough
253 * space for the encapsulation header in each packet.
254 */
255 fsize = psize - 2*sizeof(uint32_t);
256 dgl = next_dgl++;
257 dsize = m->m_pkthdr.len;
258 foff = 0;
259 while (m) {
260 if (m->m_pkthdr.len > fsize) {
261 /*
262 * Split off the tail segment from the
263 * datagram, copying our tags over.
264 */
265 mtail = m_split(m, fsize, M_DONTWAIT);
266 m_tag_copy_chain(mtail, m, M_NOWAIT);
267 } else {
268 mtail = 0;
269 }
270
271 /*
272 * Add our encapsulation header to this
273 * fragment and hand it off to the link.
274 */
275 M_PREPEND(m, 2*sizeof(uint32_t), M_DONTWAIT);
276 if (!m) {
277 error = ENOBUFS;
278 goto bad;
279 }
280 enc = mtod(m, union fw_encap *);
281 if (foff == 0) {
282 enc->firstfrag.lf = FW_ENCAP_FIRST;
283 enc->firstfrag.reserved1 = 0;
284 enc->firstfrag.reserved2 = 0;
285 enc->firstfrag.datagram_size = dsize - 1;
286 enc->firstfrag.ether_type = type;
287 enc->firstfrag.dgl = dgl;
288 } else {
289 if (mtail)
290 enc->nextfrag.lf = FW_ENCAP_NEXT;
291 else
292 enc->nextfrag.lf = FW_ENCAP_LAST;
293 enc->nextfrag.reserved1 = 0;
294 enc->nextfrag.reserved2 = 0;
295 enc->nextfrag.reserved3 = 0;
296 enc->nextfrag.datagram_size = dsize - 1;
297 enc->nextfrag.fragment_offset = foff;
298 enc->nextfrag.dgl = dgl;
299 }
300 foff += m->m_pkthdr.len - 2*sizeof(uint32_t);
301
302 /*
303 * Byte swap the encapsulation header manually.
304 */
305 enc->ul[0] = htonl(enc->ul[0]);
306 enc->ul[1] = htonl(enc->ul[1]);
307
308 IFQ_HANDOFF(ifp, m, error);
309 if (error) {
310 if (mtail)
311 m_freem(mtail);
312 return (ENOBUFS);
313 }
314
315 m = mtail;
316 }
317
318 return (0);
319 }
320
321 bad:
322 if (m)
323 m_freem(m);
324 return (error);
325 }
326
327 static struct mbuf *
328 firewire_input_fragment(struct fw_com *fc, struct mbuf *m, int src)
329 {
330 union fw_encap *enc;
331 struct fw_reass *r;
332 struct mbuf *mf, *mprev;
333 int dsize;
334 int fstart, fend, start, end, islast;
335 uint32_t id;
336
337 GIANT_REQUIRED;
338
339 /*
340 * Find an existing reassembly buffer or create a new one.
341 */
342 enc = mtod(m, union fw_encap *);
343 id = enc->firstfrag.dgl | (src << 16);
344 STAILQ_FOREACH(r, &fc->fc_frags, fr_link)
345 if (r->fr_id == id)
346 break;
347 if (!r) {
348 r = malloc(sizeof(struct fw_reass), M_TEMP, M_NOWAIT);
349 if (!r) {
350 m_freem(m);
351 return 0;
352 }
353 r->fr_id = id;
354 r->fr_frags = 0;
355 STAILQ_INSERT_HEAD(&fc->fc_frags, r, fr_link);
356 }
357
358 /*
359 * If this fragment overlaps any other fragment, we must discard
360 * the partial reassembly and start again.
361 */
362 if (enc->firstfrag.lf == FW_ENCAP_FIRST)
363 fstart = 0;
364 else
365 fstart = enc->nextfrag.fragment_offset;
366 fend = fstart + m->m_pkthdr.len - 2*sizeof(uint32_t);
367 dsize = enc->nextfrag.datagram_size;
368 islast = (enc->nextfrag.lf == FW_ENCAP_LAST);
369
370 for (mf = r->fr_frags; mf; mf = mf->m_nextpkt) {
371 enc = mtod(mf, union fw_encap *);
372 if (enc->nextfrag.datagram_size != dsize) {
373 /*
374 * This fragment must be from a different
375 * packet.
376 */
377 goto bad;
378 }
379 if (enc->firstfrag.lf == FW_ENCAP_FIRST)
380 start = 0;
381 else
382 start = enc->nextfrag.fragment_offset;
383 end = start + mf->m_pkthdr.len - 2*sizeof(uint32_t);
384 if ((fstart < end && fend > start) ||
385 (islast && enc->nextfrag.lf == FW_ENCAP_LAST)) {
386 /*
387 * Overlap - discard reassembly buffer and start
388 * again with this fragment.
389 */
390 goto bad;
391 }
392 }
393
394 /*
395 * Find where to put this fragment in the list.
396 */
397 for (mf = r->fr_frags, mprev = NULL; mf;
398 mprev = mf, mf = mf->m_nextpkt) {
399 enc = mtod(mf, union fw_encap *);
400 if (enc->firstfrag.lf == FW_ENCAP_FIRST)
401 start = 0;
402 else
403 start = enc->nextfrag.fragment_offset;
404 if (start >= fend)
405 break;
406 }
407
408 /*
409 * If this is a last fragment and we are not adding at the end
410 * of the list, discard the buffer.
411 */
412 if (islast && mprev && mprev->m_nextpkt)
413 goto bad;
414
415 if (mprev) {
416 m->m_nextpkt = mprev->m_nextpkt;
417 mprev->m_nextpkt = m;
418
419 /*
420 * Coalesce forwards and see if we can make a whole
421 * datagram.
422 */
423 enc = mtod(mprev, union fw_encap *);
424 if (enc->firstfrag.lf == FW_ENCAP_FIRST)
425 start = 0;
426 else
427 start = enc->nextfrag.fragment_offset;
428 end = start + mprev->m_pkthdr.len - 2*sizeof(uint32_t);
429 while (end == fstart) {
430 /*
431 * Strip off the encap header from m and
432 * append it to mprev, freeing m.
433 */
434 m_adj(m, 2*sizeof(uint32_t));
435 mprev->m_nextpkt = m->m_nextpkt;
436 mprev->m_pkthdr.len += m->m_pkthdr.len;
437 m_cat(mprev, m);
438
439 if (mprev->m_pkthdr.len == dsize + 1 + 2*sizeof(uint32_t)) {
440 /*
441 * We have assembled a complete packet
442 * we must be finished. Make sure we have
443 * merged the whole chain.
444 */
445 STAILQ_REMOVE(&fc->fc_frags, r, fw_reass, fr_link);
446 free(r, M_TEMP);
447 m = mprev->m_nextpkt;
448 while (m) {
449 mf = m->m_nextpkt;
450 m_freem(m);
451 m = mf;
452 }
453 mprev->m_nextpkt = NULL;
454
455 return (mprev);
456 }
457
458 /*
459 * See if we can continue merging forwards.
460 */
461 end = fend;
462 m = mprev->m_nextpkt;
463 if (m) {
464 enc = mtod(m, union fw_encap *);
465 if (enc->firstfrag.lf == FW_ENCAP_FIRST)
466 fstart = 0;
467 else
468 fstart = enc->nextfrag.fragment_offset;
469 fend = fstart + m->m_pkthdr.len
470 - 2*sizeof(uint32_t);
471 } else {
472 break;
473 }
474 }
475 } else {
476 m->m_nextpkt = 0;
477 r->fr_frags = m;
478 }
479
480 return (0);
481
482 bad:
483 while (r->fr_frags) {
484 mf = r->fr_frags;
485 r->fr_frags = mf->m_nextpkt;
486 m_freem(mf);
487 }
488 m->m_nextpkt = 0;
489 r->fr_frags = m;
490
491 return (0);
492 }
493
494 void
495 firewire_input(struct ifnet *ifp, struct mbuf *m, uint16_t src)
496 {
497 struct fw_com *fc = (struct fw_com *) ifp;
498 union fw_encap *enc;
499 int type, isr;
500
501 GIANT_REQUIRED;
502
503 /*
504 * The caller has already stripped off the packet header
505 * (stream or wreqb) and marked the mbuf's M_BCAST flag
506 * appropriately. We de-encapsulate the IP packet and pass it
507 * up the line after handling link-level fragmentation.
508 */
509 if (m->m_pkthdr.len < sizeof(uint32_t)) {
510 if_printf(ifp, "discarding frame without "
511 "encapsulation header (len %u pkt len %u)\n",
512 m->m_len, m->m_pkthdr.len);
513 }
514
515 m = m_pullup(m, sizeof(uint32_t));
516 enc = mtod(m, union fw_encap *);
517
518 /*
519 * Byte swap the encapsulation header manually.
520 */
521 enc->ul[0] = htonl(enc->ul[0]);
522
523 if (enc->unfrag.lf != 0) {
524 m = m_pullup(m, 2*sizeof(uint32_t));
525 if (!m)
526 return;
527 enc = mtod(m, union fw_encap *);
528 enc->ul[1] = htonl(enc->ul[1]);
529 m = firewire_input_fragment(fc, m, src);
530 if (!m)
531 return;
532 enc = mtod(m, union fw_encap *);
533 type = enc->firstfrag.ether_type;
534 m_adj(m, 2*sizeof(uint32_t));
535 } else {
536 type = enc->unfrag.ether_type;
537 m_adj(m, sizeof(uint32_t));
538 }
539
540 if (m->m_pkthdr.rcvif == NULL) {
541 if_printf(ifp, "discard frame w/o interface pointer\n");
542 ifp->if_ierrors++;
543 m_freem(m);
544 return;
545 }
546 #ifdef DIAGNOSTIC
547 if (m->m_pkthdr.rcvif != ifp) {
548 if_printf(ifp, "Warning, frame marked as received on %s\n",
549 m->m_pkthdr.rcvif->if_xname);
550 }
551 #endif
552
553 #ifdef MAC
554 /*
555 * Tag the mbuf with an appropriate MAC label before any other
556 * consumers can get to it.
557 */
558 mac_create_mbuf_from_ifnet(ifp, m);
559 #endif
560
561 /*
562 * Give bpf a chance at the packet. The link-level driver
563 * should have left us a tag with the EUID of the sender.
564 */
565 if (ifp->if_bpf) {
566 struct fw_bpfhdr h;
567 struct m_tag *mtag;
568
569 mtag = m_tag_locate(m, MTAG_FIREWIRE, MTAG_FIREWIRE_SENDER_EUID, 0);
570 if (mtag)
571 bcopy(mtag + 1, h.firewire_shost, 8);
572 else
573 bcopy(&firewire_broadcastaddr, h.firewire_dhost, 8);
574 bcopy(&fc->fc_hwaddr, h.firewire_dhost, 8);
575 h.firewire_type = htons(type);
576 bpf_mtap2(ifp->if_bpf, &h, sizeof(h), m);
577 }
578
579 if (ifp->if_flags & IFF_MONITOR) {
580 /*
581 * Interface marked for monitoring; discard packet.
582 */
583 m_freem(m);
584 return;
585 }
586
587 ifp->if_ibytes += m->m_pkthdr.len;
588
589 /* Discard packet if interface is not up */
590 if ((ifp->if_flags & IFF_UP) == 0) {
591 m_freem(m);
592 return;
593 }
594
595 if (m->m_flags & (M_BCAST|M_MCAST))
596 ifp->if_imcasts++;
597
598 switch (type) {
599 #ifdef INET
600 case ETHERTYPE_IP:
601 if (ip_fastforward(m))
602 return;
603 isr = NETISR_IP;
604 break;
605
606 case ETHERTYPE_ARP:
607 {
608 struct arphdr *ah;
609 ah = mtod(m, struct arphdr *);
610
611 /*
612 * Adjust the arp packet to insert an empty tha slot.
613 */
614 m->m_len += ah->ar_hln;
615 m->m_pkthdr.len += ah->ar_hln;
616 bcopy(ar_tha(ah), ar_tpa(ah), ah->ar_pln);
617 isr = NETISR_ARP;
618 break;
619 }
620 #endif
621
622 #ifdef INET6
623 case ETHERTYPE_IPV6:
624 isr = NETISR_IPV6;
625 break;
626 #endif
627
628 default:
629 m_freem(m);
630 return;
631 }
632
633 netisr_dispatch(isr, m);
634 }
635
636 int
637 firewire_ioctl(struct ifnet *ifp, int command, caddr_t data)
638 {
639 struct ifaddr *ifa = (struct ifaddr *) data;
640 struct ifreq *ifr = (struct ifreq *) data;
641 int error = 0;
642
643 switch (command) {
644 case SIOCSIFADDR:
645 ifp->if_flags |= IFF_UP;
646
647 switch (ifa->ifa_addr->sa_family) {
648 #ifdef INET
649 case AF_INET:
650 ifp->if_init(ifp->if_softc); /* before arpwhohas */
651 arp_ifinit(ifp, ifa);
652 break;
653 #endif
654 default:
655 ifp->if_init(ifp->if_softc);
656 break;
657 }
658 break;
659
660 case SIOCGIFADDR:
661 {
662 struct sockaddr *sa;
663
664 sa = (struct sockaddr *) & ifr->ifr_data;
665 bcopy(&IFP2FC(ifp)->fc_hwaddr,
666 (caddr_t) sa->sa_data, sizeof(struct fw_hwaddr));
667 }
668 break;
669
670 case SIOCSIFMTU:
671 /*
672 * Set the interface MTU.
673 */
674 if (ifr->ifr_mtu > 1500) {
675 error = EINVAL;
676 } else {
677 ifp->if_mtu = ifr->ifr_mtu;
678 }
679 break;
680 default:
681 error = EINVAL; /* XXX netbsd has ENOTTY??? */
682 break;
683 }
684 return (error);
685 }
686
687 static int
688 firewire_resolvemulti(struct ifnet *ifp, struct sockaddr **llsa,
689 struct sockaddr *sa)
690 {
691 #ifdef INET
692 struct sockaddr_in *sin;
693 #endif
694 #ifdef INET6
695 struct sockaddr_in6 *sin6;
696 #endif
697
698 switch(sa->sa_family) {
699 case AF_LINK:
700 /*
701 * No mapping needed.
702 */
703 *llsa = 0;
704 return 0;
705
706 #ifdef INET
707 case AF_INET:
708 sin = (struct sockaddr_in *)sa;
709 if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
710 return EADDRNOTAVAIL;
711 *llsa = 0;
712 return 0;
713 #endif
714 #ifdef INET6
715 case AF_INET6:
716 sin6 = (struct sockaddr_in6 *)sa;
717 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
718 /*
719 * An IP6 address of 0 means listen to all
720 * of the Ethernet multicast address used for IP6.
721 * (This is used for multicast routers.)
722 */
723 ifp->if_flags |= IFF_ALLMULTI;
724 *llsa = 0;
725 return 0;
726 }
727 if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
728 return EADDRNOTAVAIL;
729 *llsa = 0;
730 return 0;
731 #endif
732
733 default:
734 /*
735 * Well, the text isn't quite right, but it's the name
736 * that counts...
737 */
738 return EAFNOSUPPORT;
739 }
740 }
741
742 void
743 firewire_ifattach(struct ifnet *ifp, struct fw_hwaddr *llc)
744 {
745 struct fw_com *fc = (struct fw_com *) ifp;
746 struct ifaddr *ifa;
747 struct sockaddr_dl *sdl;
748 static const char* speeds[] = {
749 "S100", "S200", "S400", "S800",
750 "S1600", "S3200"
751 };
752
753 fc->fc_speed = llc->sspd;
754 STAILQ_INIT(&fc->fc_frags);
755
756 ifp->if_type = IFT_IEEE1394;
757 ifp->if_addrlen = sizeof(struct fw_hwaddr);
758 ifp->if_hdrlen = 0;
759 if_attach(ifp);
760 ifp->if_mtu = 1500; /* XXX */
761 ifp->if_output = firewire_output;
762 ifp->if_resolvemulti = firewire_resolvemulti;
763 ifp->if_broadcastaddr = (u_char *) &firewire_broadcastaddr;
764
765 ifa = ifaddr_byindex(ifp->if_index);
766 KASSERT(ifa != NULL, ("%s: no lladdr!\n", __func__));
767 sdl = (struct sockaddr_dl *)ifa->ifa_addr;
768 sdl->sdl_type = IFT_IEEE1394;
769 sdl->sdl_alen = ifp->if_addrlen;
770 bcopy(llc, LLADDR(sdl), ifp->if_addrlen);
771
772 bpfattach(ifp, DLT_APPLE_IP_OVER_IEEE1394,
773 sizeof(struct fw_hwaddr));
774
775 if_printf(ifp, "Firewire address: %8D @ 0x%04x%08x, %s, maxrec %d\n",
776 (uint8_t *) &llc->sender_unique_ID_hi, ":",
777 ntohs(llc->sender_unicast_FIFO_hi),
778 ntohl(llc->sender_unicast_FIFO_lo),
779 speeds[llc->sspd],
780 (2 << llc->sender_max_rec));
781 }
782
783 void
784 firewire_ifdetach(struct ifnet *ifp)
785 {
786 bpfdetach(ifp);
787 if_detach(ifp);
788 }
789
790 void
791 firewire_busreset(struct ifnet *ifp)
792 {
793 struct fw_com *fc = (struct fw_com *) ifp;
794 struct fw_reass *r;
795 struct mbuf *m;
796
797 /*
798 * Discard any partial datagrams since the host ids may have changed.
799 */
800 while ((r = STAILQ_FIRST(&fc->fc_frags))) {
801 STAILQ_REMOVE_HEAD(&fc->fc_frags, fr_link);
802 while (r->fr_frags) {
803 m = r->fr_frags;
804 r->fr_frags = m->m_nextpkt;
805 m_freem(m);
806 }
807 free(r, M_TEMP);
808 }
809 }
Cache object: 1e75b2ef4044da1b22566bd430fd24bd
|