1 /* $NetBSD: if_ieee1394subr.c,v 1.40 2008/04/28 20:24:09 martin Exp $ */
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
32 #include <sys/cdefs.h>
33 __KERNEL_RCSID(0, "$NetBSD: if_ieee1394subr.c,v 1.40 2008/04/28 20:24:09 martin Exp $");
38 #include <sys/param.h>
39 #include <sys/systm.h>
40 #include <sys/socket.h>
41 #include <sys/sockio.h>
42 #include <sys/kernel.h>
44 #include <sys/device.h>
47 #include <net/if_dl.h>
48 #include <net/if_ieee1394.h>
49 #include <net/if_types.h>
50 #include <net/if_media.h>
51 #include <net/ethertypes.h>
52 #include <net/netisr.h>
53 #include <net/route.h>
60 #include <netinet/in.h>
61 #include <netinet/in_var.h>
62 #include <netinet/if_inarp.h>
65 #include <netinet/in.h>
66 #include <netinet6/in6_var.h>
67 #include <netinet6/nd6.h>
70 #include <dev/ieee1394/fw_port.h>
71 #include <dev/ieee1394/firewire.h>
73 #include <dev/ieee1394/firewirereg.h>
74 #include <dev/ieee1394/iec13213.h>
75 #include <dev/ieee1394/if_fwipvar.h>
77 #define IEEE1394_REASS_TIMEOUT 3 /* 3 sec */
79 #define senderr(e) do { error = (e); goto bad; } while(0/*CONSTCOND*/)
81 static int ieee1394_output(struct ifnet
*, struct mbuf
*,
82 const struct sockaddr
*, struct rtentry
*);
83 static struct mbuf
*ieee1394_reass(struct ifnet
*, struct mbuf
*, uint16_t);
86 ieee1394_output(struct ifnet
*ifp
, struct mbuf
*m0
, const struct sockaddr
*dst
,
91 int s
, hdrlen
, error
= 0;
93 struct mbuf
*mcopy
= NULL
;
94 struct ieee1394_hwaddr
*hwdst
, baddr
;
95 const struct ieee1394_hwaddr
*myaddr
;
96 ALTQ_DECL(struct altq_pktattr pktattr
;)
103 if ((ifp
->if_flags
& (IFF_UP
|IFF_RUNNING
)) != (IFF_UP
|IFF_RUNNING
))
105 if ((rt
= rt0
) != NULL
) {
106 if ((rt
->rt_flags
& RTF_UP
) == 0) {
107 if ((rt0
= rt
= rtalloc1(dst
, 1)) != NULL
) {
109 if (rt
->rt_ifp
!= ifp
)
110 return (*rt
->rt_ifp
->if_output
)
113 senderr(EHOSTUNREACH
);
115 if (rt
->rt_flags
& RTF_GATEWAY
) {
116 if (rt
->rt_gwroute
== NULL
)
118 if (((rt
= rt
->rt_gwroute
)->rt_flags
& RTF_UP
) == 0) {
122 rt
->rt_gwroute
= rtalloc1(rt
->rt_gateway
, 1);
123 if ((rt
= rt
->rt_gwroute
) == NULL
)
124 senderr(EHOSTUNREACH
);
125 /* the "G" test below also prevents rt == rt0 */
126 if ((rt
->rt_flags
& RTF_GATEWAY
) ||
127 (rt
->rt_ifp
!= ifp
)) {
129 rt0
->rt_gwroute
= NULL
;
130 senderr(EHOSTUNREACH
);
134 if (rt
->rt_flags
& RTF_REJECT
)
135 if (rt
->rt_rmx
.rmx_expire
== 0 ||
136 time_second
< rt
->rt_rmx
.rmx_expire
)
137 senderr(rt
== rt0
? EHOSTDOWN
: EHOSTUNREACH
);
141 * If the queueing discipline needs packet classification,
142 * do it before prepending link headers.
144 IFQ_CLASSIFY(&ifp
->if_snd
, m0
, dst
->sa_family
, &pktattr
);
147 * For unicast, we make a tag to store the lladdr of the
148 * destination. This might not be the first time we have seen
149 * the packet (for instance, the arp code might be trying to
150 * re-send it after receiving an arp reply) so we only
151 * allocate a tag if there isn't one there already. For
152 * multicast, we will eventually use a different tag to store
153 * the channel number.
155 unicast
= !(m0
->m_flags
& (M_BCAST
| M_MCAST
));
158 m_tag_locate(m0
, MTAG_FIREWIRE
, MTAG_FIREWIRE_HWADDR
, NULL
);
160 mtag
= m_tag_alloc(MTAG_FIREWIRE
, MTAG_FIREWIRE_HWADDR
,
161 sizeof (struct ieee1394_hwaddr
), M_NOWAIT
);
166 m_tag_prepend(m0
, mtag
);
168 hwdst
= (struct ieee1394_hwaddr
*)(mtag
+ 1);
173 switch (dst
->sa_family
) {
176 if (unicast
&& (!arpresolve(ifp
, rt
, m0
, dst
, (u_char
*)hwdst
)))
177 return 0; /* if not yet resolved */
178 /* if broadcasting on a simplex interface, loopback a copy */
179 if ((m0
->m_flags
& M_BCAST
) && (ifp
->if_flags
& IFF_SIMPLEX
))
180 mcopy
= m_copy(m0
, 0, M_COPYALL
);
181 etype
= htons(ETHERTYPE_IP
);
184 ah
= mtod(m0
, struct arphdr
*);
185 ah
->ar_hrd
= htons(ARPHRD_IEEE1394
);
186 etype
= htons(ETHERTYPE_ARP
);
191 if (unicast
&& (!nd6_storelladdr(ifp
, rt
, m0
, dst
,
192 hwdst
->iha_uid
, IEEE1394_ADDR_LEN
))) {
193 /* something bad happened */
196 etype
= htons(ETHERTYPE_IPV6
);
200 case pseudo_AF_HDRCMPLT
:
204 printf("%s: can't handle af%d\n", ifp
->if_xname
,
206 senderr(EAFNOSUPPORT
);
211 looutput(ifp
, mcopy
, dst
, rt
);
212 myaddr
= (const struct ieee1394_hwaddr
*)CLLADDR(ifp
->if_sadl
);
215 struct ieee1394_bpfhdr h
;
217 memcpy(h
.ibh_dhost
, hwdst
->iha_uid
, 8);
220 ((const struct ieee1394_hwaddr
*)
221 ifp
->if_broadcastaddr
)->iha_uid
, 8);
222 memcpy(h
.ibh_shost
, myaddr
->iha_uid
, 8);
224 bpf_mtap2(ifp
->if_bpf
, &h
, sizeof(h
), m0
);
227 if ((ifp
->if_flags
& IFF_SIMPLEX
) &&
229 memcmp(hwdst
, myaddr
, IEEE1394_ADDR_LEN
) == 0)
230 return looutput(ifp
, m0
, dst
, rt
);
234 * The maximum possible rate depends on the topology.
235 * So the determination of maxrec and fragmentation should be
236 * called from the driver after probing the topology map.
239 hdrlen
= IEEE1394_GASP_LEN
;
240 hwdst
->iha_speed
= 0; /* XXX */
244 if (hwdst
->iha_speed
> myaddr
->iha_speed
)
245 hwdst
->iha_speed
= myaddr
->iha_speed
;
246 if (hwdst
->iha_maxrec
> myaddr
->iha_maxrec
)
247 hwdst
->iha_maxrec
= myaddr
->iha_maxrec
;
248 if (hwdst
->iha_maxrec
> (8 + hwdst
->iha_speed
))
249 hwdst
->iha_maxrec
= 8 + hwdst
->iha_speed
;
250 if (hwdst
->iha_maxrec
< 8)
251 hwdst
->iha_maxrec
= 8;
253 m0
= ieee1394_fragment(ifp
, m0
, (2<<hwdst
->iha_maxrec
) - hdrlen
, etype
);
258 ifp
->if_obytes
+= m0
->m_pkthdr
.len
;
259 if (m0
->m_flags
& M_MCAST
)
261 while ((m
= m0
) != NULL
) {
267 IFQ_ENQUEUE(&ifp
->if_snd
, m
, &pktattr
, error
);
269 /* mbuf is already freed */
274 if ((ifp
->if_flags
& IFF_OACTIVE
) == 0)
275 (*ifp
->if_start
)(ifp
);
290 ieee1394_fragment(struct ifnet
*ifp
, struct mbuf
*m0
, int maxsize
,
293 struct ieee1394com
*ic
= (struct ieee1394com
*)ifp
;
294 int totlen
, fraglen
, off
;
295 struct mbuf
*m
, **mp
;
296 struct ieee1394_fraghdr
*ifh
;
297 struct ieee1394_unfraghdr
*iuh
;
299 totlen
= m0
->m_pkthdr
.len
;
300 if (totlen
+ sizeof(struct ieee1394_unfraghdr
) <= maxsize
) {
301 M_PREPEND(m0
, sizeof(struct ieee1394_unfraghdr
), M_DONTWAIT
);
304 iuh
= mtod(m0
, struct ieee1394_unfraghdr
*);
306 iuh
->iuh_etype
= etype
;
310 fraglen
= maxsize
- sizeof(struct ieee1394_fraghdr
);
312 M_PREPEND(m0
, sizeof(struct ieee1394_fraghdr
), M_DONTWAIT
);
315 ifh
= mtod(m0
, struct ieee1394_fraghdr
*);
316 ifh
->ifh_ft_size
= htons(IEEE1394_FT_MORE
| (totlen
- 1));
317 ifh
->ifh_etype_off
= etype
;
318 ifh
->ifh_dgl
= htons(ic
->ic_dgl
);
319 ifh
->ifh_reserved
= 0;
322 while (off
< totlen
) {
323 if (off
+ fraglen
> totlen
)
324 fraglen
= totlen
- off
;
325 MGETHDR(m
, M_DONTWAIT
, MT_HEADER
);
328 m
->m_flags
|= m0
->m_flags
& (M_BCAST
|M_MCAST
); /* copy bcast */
329 MH_ALIGN(m
, sizeof(struct ieee1394_fraghdr
));
330 m
->m_len
= sizeof(struct ieee1394_fraghdr
);
331 ifh
= mtod(m
, struct ieee1394_fraghdr
*);
333 htons(IEEE1394_FT_SUBSEQ
| IEEE1394_FT_MORE
| (totlen
- 1));
334 ifh
->ifh_etype_off
= htons(off
);
335 ifh
->ifh_dgl
= htons(ic
->ic_dgl
);
336 ifh
->ifh_reserved
= 0;
337 m
->m_next
= m_copy(m0
, sizeof(*ifh
) + off
, fraglen
);
338 if (m
->m_next
== NULL
)
340 m
->m_pkthdr
.len
= sizeof(*ifh
) + fraglen
;
345 ifh
->ifh_ft_size
&= ~htons(IEEE1394_FT_MORE
); /* last fragment */
346 m_adj(m0
, -(m0
->m_pkthdr
.len
- maxsize
));
352 while ((m
= m0
) != NULL
) {
361 ieee1394_input(struct ifnet
*ifp
, struct mbuf
*m
, uint16_t src
)
366 struct ieee1394_unfraghdr
*iuh
;
368 if ((ifp
->if_flags
& IFF_UP
) == 0) {
372 if (m
->m_len
< sizeof(*iuh
)) {
373 if ((m
= m_pullup(m
, sizeof(*iuh
))) == NULL
)
377 iuh
= mtod(m
, struct ieee1394_unfraghdr
*);
379 if (ntohs(iuh
->iuh_ft
) & (IEEE1394_FT_SUBSEQ
| IEEE1394_FT_MORE
)) {
380 if ((m
= ieee1394_reass(ifp
, m
, src
)) == NULL
)
382 iuh
= mtod(m
, struct ieee1394_unfraghdr
*);
384 etype
= ntohs(iuh
->iuh_etype
);
386 /* strip off the ieee1394 header */
387 m_adj(m
, sizeof(*iuh
));
390 struct ieee1394_bpfhdr h
;
392 const struct ieee1394_hwaddr
*myaddr
;
394 mtag
= m_tag_locate(m
,
395 MTAG_FIREWIRE
, MTAG_FIREWIRE_SENDER_EUID
, 0);
397 memcpy(h
.ibh_shost
, mtag
+ 1, 8);
399 memset(h
.ibh_shost
, 0, 8);
400 if (m
->m_flags
& M_BCAST
)
402 ((const struct ieee1394_hwaddr
*)
403 ifp
->if_broadcastaddr
)->iha_uid
, 8);
406 (const struct ieee1394_hwaddr
*)CLLADDR(ifp
->if_sadl
);
407 memcpy(h
.ibh_dhost
, myaddr
->iha_uid
, 8);
409 h
.ibh_type
= htons(etype
);
410 bpf_mtap2(ifp
->if_bpf
, &h
, sizeof(h
), m
);
417 schednetisr(NETISR_IP
);
422 schednetisr(NETISR_ARP
);
429 schednetisr(NETISR_IPV6
);
449 ieee1394_reass(struct ifnet
*ifp
, struct mbuf
*m0
, uint16_t src
)
451 struct ieee1394com
*ic
= (struct ieee1394com
*)ifp
;
452 struct ieee1394_fraghdr
*ifh
;
453 struct ieee1394_unfraghdr
*iuh
;
454 struct ieee1394_reassq
*rq
;
455 struct ieee1394_reass_pkt
*rp
, *trp
, *nrp
= NULL
;
457 uint16_t etype
, off
, ftype
, size
, dgl
;
460 if (m0
->m_len
< sizeof(*ifh
)) {
461 if ((m0
= m_pullup(m0
, sizeof(*ifh
))) == NULL
)
464 ifh
= mtod(m0
, struct ieee1394_fraghdr
*);
465 m_adj(m0
, sizeof(*ifh
));
466 size
= ntohs(ifh
->ifh_ft_size
);
467 ftype
= size
& (IEEE1394_FT_SUBSEQ
| IEEE1394_FT_MORE
);
468 size
= (size
& ~ftype
) + 1;
469 dgl
= ntohs(ifh
->ifh_dgl
);
470 len
= m0
->m_pkthdr
.len
;
471 id
= dgl
| (src
<< 16);
472 if (ftype
& IEEE1394_FT_SUBSEQ
) {
473 m_tag_delete_chain(m0
, NULL
);
474 m0
->m_flags
&= ~M_PKTHDR
;
476 off
= ntohs(ifh
->ifh_etype_off
);
478 etype
= ifh
->ifh_etype_off
;
482 for (rq
= LIST_FIRST(&ic
->ic_reassq
); ; rq
= LIST_NEXT(rq
, rq_node
)) {
485 * Create a new reassemble queue head for the node.
487 rq
= malloc(sizeof(*rq
), M_FTABLE
, M_NOWAIT
);
493 LIST_INIT(&rq
->rq_pkt
);
494 LIST_INSERT_HEAD(&ic
->ic_reassq
, rq
, rq_node
);
500 for (rp
= LIST_FIRST(&rq
->rq_pkt
); rp
!= NULL
; rp
= nrp
) {
501 nrp
= LIST_NEXT(rp
, rp_next
);
502 if (rp
->rp_dgl
!= dgl
)
506 * datagram size must be same for all fragments, and
507 * no overlap is allowed.
509 if (rp
->rp_size
!= size
||
510 (off
< rp
->rp_off
+ rp
->rp_len
&& off
+ len
> rp
->rp_off
)) {
512 * This happens probably due to wrapping dgl value.
513 * Destroy all previously received fragment and
514 * enqueue current fragment.
516 for (rp
= LIST_FIRST(&rq
->rq_pkt
); rp
!= NULL
;
518 nrp
= LIST_NEXT(rp
, rp_next
);
519 if (rp
->rp_dgl
== dgl
) {
520 LIST_REMOVE(rp
, rp_next
);
527 if (rp
->rp_off
+ rp
->rp_len
== off
) {
529 * All the subsequent fragments received in sequence
531 * Concatinate mbuf to previous one instead of
532 * allocating new reassemble queue structure,
533 * and try to merge more with the subsequent fragment
538 while (rp
->rp_off
+ rp
->rp_len
< size
&&
539 nrp
!= NULL
&& nrp
->rp_dgl
== dgl
&&
540 nrp
->rp_off
== rp
->rp_off
+ rp
->rp_len
) {
541 LIST_REMOVE(nrp
, rp_next
);
542 m_cat(rp
->rp_m
, nrp
->rp_m
);
543 rp
->rp_len
+= nrp
->rp_len
;
545 nrp
= LIST_NEXT(rp
, rp_next
);
547 m0
= NULL
; /* mark merged */
550 if (off
+ m0
->m_pkthdr
.len
== rp
->rp_off
) {
554 rp
->rp_etype
= etype
; /* over writing trust etype */
556 m0
= NULL
; /* mark merged */
559 if (rp
->rp_off
> off
) {
560 /* insert before rp */
564 if (nrp
== NULL
|| nrp
->rp_dgl
!= dgl
) {
565 /* insert after rp */
571 if (rp
->rp_off
!= 0 || rp
->rp_len
!= size
)
574 LIST_REMOVE(rp
, rp_next
);
576 m0
->m_pkthdr
.len
= rp
->rp_len
;
577 M_PREPEND(m0
, sizeof(*iuh
), M_DONTWAIT
);
579 iuh
= mtod(m0
, struct ieee1394_unfraghdr
*);
581 iuh
->iuh_etype
= rp
->rp_etype
;
588 * New fragment received. Allocate reassemble queue structure.
590 trp
= malloc(sizeof(*trp
), M_FTABLE
, M_NOWAIT
);
597 trp
->rp_etype
= etype
; /* valid only if off==0 */
601 trp
->rp_ttl
= IEEE1394_REASS_TIMEOUT
;
602 if (trp
->rp_ttl
<= ifp
->if_timer
)
603 trp
->rp_ttl
= ifp
->if_timer
+ 1;
606 /* first fragment for the dgl */
607 LIST_INSERT_HEAD(&rq
->rq_pkt
, trp
, rp_next
);
608 } else if (nrp
== NULL
) {
609 /* no next fragment for the dgl */
610 LIST_INSERT_AFTER(rp
, trp
, rp_next
);
612 /* there is a hole */
613 LIST_INSERT_BEFORE(nrp
, trp
, rp_next
);
619 ieee1394_drain(struct ifnet
*ifp
)
621 struct ieee1394com
*ic
= (struct ieee1394com
*)ifp
;
622 struct ieee1394_reassq
*rq
;
623 struct ieee1394_reass_pkt
*rp
;
625 while ((rq
= LIST_FIRST(&ic
->ic_reassq
)) != NULL
) {
626 LIST_REMOVE(rq
, rq_node
);
627 while ((rp
= LIST_FIRST(&rq
->rq_pkt
)) != NULL
) {
628 LIST_REMOVE(rp
, rp_next
);
637 ieee1394_watchdog(struct ifnet
*ifp
)
639 struct ieee1394com
*ic
= (struct ieee1394com
*)ifp
;
640 struct ieee1394_reassq
*rq
;
641 struct ieee1394_reass_pkt
*rp
, *nrp
;
644 dec
= (ifp
->if_timer
> 0) ? ifp
->if_timer
: 1;
645 for (rq
= LIST_FIRST(&ic
->ic_reassq
); rq
!= NULL
;
646 rq
= LIST_NEXT(rq
, rq_node
)) {
647 for (rp
= LIST_FIRST(&rq
->rq_pkt
); rp
!= NULL
; rp
= nrp
) {
648 nrp
= LIST_NEXT(rp
, rp_next
);
649 if (rp
->rp_ttl
>= dec
)
652 LIST_REMOVE(rp
, rp_next
);
661 ieee1394_sprintf(const uint8_t *laddr
)
663 static char buf
[3*8];
665 snprintf(buf
, sizeof(buf
), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
666 laddr
[0], laddr
[1], laddr
[2], laddr
[3],
667 laddr
[4], laddr
[5], laddr
[6], laddr
[7]);
672 ieee1394_ifattach(struct ifnet
*ifp
, const struct ieee1394_hwaddr
*hwaddr
)
674 struct ieee1394_hwaddr
*baddr
;
675 struct ieee1394com
*ic
= (struct ieee1394com
*)ifp
;
677 ifp
->if_type
= IFT_IEEE1394
;
678 ifp
->if_hdrlen
= sizeof(struct ieee1394_header
);
679 ifp
->if_dlt
= DLT_EN10MB
; /* XXX */
680 ifp
->if_mtu
= IEEE1394MTU
;
681 ifp
->if_output
= ieee1394_output
;
682 ifp
->if_drain
= ieee1394_drain
;
683 ifp
->if_watchdog
= ieee1394_watchdog
;
685 if (ifp
->if_baudrate
== 0)
686 ifp
->if_baudrate
= IF_Mbps(100);
688 if_set_sadl(ifp
, hwaddr
, sizeof(struct ieee1394_hwaddr
), true);
690 baddr
= malloc(ifp
->if_addrlen
, M_DEVBUF
, M_WAITOK
);
691 memset(baddr
->iha_uid
, 0xff, IEEE1394_ADDR_LEN
);
692 baddr
->iha_speed
= 0; /*XXX: how to determine the speed for bcast? */
693 baddr
->iha_maxrec
= 512 << baddr
->iha_speed
;
694 memset(baddr
->iha_offset
, 0, sizeof(baddr
->iha_offset
));
695 ifp
->if_broadcastaddr
= (uint8_t *)baddr
;
696 LIST_INIT(&ic
->ic_reassq
);
699 DLT_APPLE_IP_OVER_IEEE1394
, sizeof(struct ieee1394_hwaddr
));
704 ieee1394_ifdetach(struct ifnet
*ifp
)
710 free(__UNCONST(ifp
->if_broadcastaddr
), M_DEVBUF
);
711 ifp
->if_broadcastaddr
= NULL
;
712 #if 0 /* done in if_detach() */
718 ieee1394_ioctl(struct ifnet
*ifp
, u_long cmd
, void *data
)
720 struct ifreq
*ifr
= (struct ifreq
*)data
;
721 struct ifaddr
*ifa
= (struct ifaddr
*)data
;
726 ifp
->if_flags
|= IFF_UP
;
727 switch (ifa
->ifa_addr
->sa_family
) {
730 if ((error
= (*ifp
->if_init
)(ifp
)) != 0)
732 arp_ifinit(ifp
, ifa
);
736 error
= (*ifp
->if_init
)(ifp
);
742 if (ifr
->ifr_mtu
> IEEE1394MTU
)
744 else if ((error
= ifioctl_common(ifp
, cmd
, data
)) == ENETRESET
)
749 error
= ifioctl_common(ifp
, cmd
, data
);