if_ieee1394subr.c revision 1.2 1 /* $NetBSD: if_ieee1394subr.c,v 1.2 2000/11/14 11:14:56 onoe Exp $ */
2
3 /*
4 * Copyright (c) 2000 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Atsushi Onoe.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
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.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 #include "opt_inet.h"
40 #include "bpfilter.h"
41
42 #include <sys/param.h>
43 #include <sys/systm.h>
44 #include <sys/types.h>
45 #include <sys/socket.h>
46 #include <sys/sockio.h>
47 #include <sys/kernel.h>
48 #include <sys/mbuf.h>
49 #include <sys/device.h>
50
51 #include <net/if.h>
52 #include <net/if_dl.h>
53 #include <net/if_ieee1394.h>
54 #include <net/if_types.h>
55 #include <net/if_media.h>
56 #include <net/ethertypes.h>
57 #include <net/netisr.h>
58 #include <net/route.h>
59
60 #if NBPFILTER > 0
61 #include <net/bpf.h>
62 #endif
63
64 #ifdef INET
65 #include <netinet/in.h>
66 #include <netinet/in_var.h>
67 #include <netinet/if_ieee1394arp.h>
68 #endif /* INET */
69 #ifdef INET6
70 #include <netinet/in.h>
71 #include <netinet6/in6_var.h>
72 #include <netinet6/nd6.h>
73 #endif /* INET6 */
74
75 #define senderr(e) do { error = (e); goto bad; } while(0/*CONSTCOND*/)
76
77 static int ieee1394_output(struct ifnet *, struct mbuf *, struct sockaddr *,
78 struct rtentry *);
79 static void ieee1394_input(struct ifnet *, struct mbuf *);
80 static struct mbuf *ieee1394_reass(struct ifnet *, struct mbuf *);
81
82 static int
83 ieee1394_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
84 struct rtentry *rt0)
85 {
86 u_int16_t etype = 0;
87 struct mbuf *m;
88 int s, hdrlen, error = 0;
89 struct rtentry *rt;
90 struct mbuf *mcopy = NULL;
91 struct ieee1394_hwaddr hwdst, *myaddr;
92 #ifdef INET
93 struct ieee1394_arphdr *ah;
94 #endif /* INET */
95
96 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
97 senderr(ENETDOWN);
98 ifp->if_lastchange = time;
99 if ((rt = rt0) != NULL) {
100 if ((rt->rt_flags & RTF_UP) == 0) {
101 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
102 rt->rt_refcnt--;
103 if (rt->rt_ifp != ifp)
104 return (*rt->rt_ifp->if_output)
105 (ifp, m0, dst, rt);
106 } else
107 senderr(EHOSTUNREACH);
108 }
109 if (rt->rt_flags & RTF_GATEWAY) {
110 if (rt->rt_gwroute == 0)
111 goto lookup;
112 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
113 rtfree(rt);
114 rt = rt0;
115 lookup:
116 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
117 if ((rt = rt->rt_gwroute) == 0)
118 senderr(EHOSTUNREACH);
119 /* the "G" test below also prevents rt == rt0 */
120 if ((rt->rt_flags & RTF_GATEWAY) ||
121 (rt->rt_ifp != ifp)) {
122 rt->rt_refcnt--;
123 rt0->rt_gwroute = 0;
124 senderr(EHOSTUNREACH);
125 }
126 }
127 }
128 if (rt->rt_flags & RTF_REJECT)
129 if (rt->rt_rmx.rmx_expire == 0 ||
130 time.tv_sec < rt->rt_rmx.rmx_expire)
131 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
132 }
133 switch (dst->sa_family) {
134 #ifdef INET
135 case AF_INET:
136 if (m0->m_flags & (M_BCAST | M_MCAST))
137 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
138 else if (!ieee1394arpresolve(ifp, rt, m0, dst, &hwdst))
139 return 0; /* if not yet resolved */
140 /* if broadcasting on a simplex interface, loopback a copy */
141 if ((m0->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
142 mcopy = m_copy(m0, 0, M_COPYALL);
143 etype = htons(ETHERTYPE_IP);
144 break;
145 case AF_ARP:
146 ah = mtod(m0, struct ieee1394_arphdr *);
147 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
148 etype = htons(ETHERTYPE_ARP);
149 break;
150 #endif /* INET */
151 #ifdef INET6
152 case AF_INET6:
153 if (m0->m_flags & M_MCAST)
154 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
155 else if (!nd6_storelladdr(ifp, rt, m0, dst, (u_char *)&hwdst)) {
156 /* this must be impossible, so we bark */
157 printf("ieee1394_output: nd6_storelladdr failed\n");
158 return 0;
159 }
160 etype = htons(ETHERTYPE_IPV6);
161 break;
162 #endif /* INET6 */
163
164 case pseudo_AF_HDRCMPLT:
165 case AF_UNSPEC:
166 /* TODO? */
167 default:
168 printf("%s: can't handle af%d\n", ifp->if_xname,
169 dst->sa_family);
170 senderr(EAFNOSUPPORT);
171 break;
172 }
173
174 if (mcopy)
175 looutput(ifp, mcopy, dst, rt);
176 #if NBPFILTER > 0
177 /* XXX: emulate DLT_EN10MB */
178 if (ifp->if_bpf) {
179 struct mbuf mb;
180
181 mb.m_next = m0;
182 mb.m_len = 14;
183 mb.m_data = mb.m_dat;
184 ((u_int32_t *)mb.m_data)[0] = 0;
185 ((u_int32_t *)mb.m_data)[1] = 0;
186 ((u_int32_t *)mb.m_data)[2] = 0;
187 ((u_int16_t *)mb.m_data)[6] = etype;
188 bpf_mtap(ifp->if_bpf, &mb);
189 }
190 #endif
191 myaddr = (struct ieee1394_hwaddr *)LLADDR(ifp->if_sadl);
192 if ((ifp->if_flags & IFF_SIMPLEX) &&
193 memcmp(&hwdst, myaddr, IEEE1394_ADDR_LEN) == 0)
194 return looutput(ifp, m0, dst, rt);
195
196 if (m0->m_flags & (M_BCAST | M_MCAST)) {
197 hdrlen = IEEE1394_GASP_LEN;
198 /*
199 * XXX: There should be sophisticated way to determine
200 * maximum available rate for all IP capable nodes.
201 */
202 hwdst.iha_speed = 0;
203 } else
204 hdrlen = 0;
205
206 /*
207 * XXX: The maximum possible rate depends on the topology.
208 */
209 if (hwdst.iha_speed > myaddr->iha_speed)
210 hwdst.iha_speed = myaddr->iha_speed;
211 if (hwdst.iha_maxrec > myaddr->iha_maxrec)
212 hwdst.iha_maxrec = myaddr->iha_maxrec;
213 if (hwdst.iha_maxrec > (8 + hwdst.iha_speed))
214 hwdst.iha_maxrec = 8 + hwdst.iha_speed;
215 if (hwdst.iha_maxrec < 8)
216 hwdst.iha_maxrec = 8;
217
218 m0 = ieee1394_fragment(ifp, m0, (2<<hwdst.iha_maxrec) - hdrlen, etype);
219 if (m0 == NULL)
220 senderr(ENOBUFS);
221 s = splimp();
222 if (IF_QFULL(&ifp->if_snd)) {
223 IF_DROP(&ifp->if_snd);
224 splx(s);
225 senderr(ENOBUFS);
226 }
227 ifp->if_obytes += m0->m_pkthdr.len;
228 if (m0->m_flags & M_MCAST)
229 ifp->if_omcasts++;
230 while ((m = m0) != NULL) {
231 m0 = m->m_nextpkt;
232 M_PREPEND(m, sizeof(struct ieee1394_header), M_DONTWAIT);
233 if (m == NULL) {
234 splx(s);
235 senderr(ENOBUFS);
236 }
237 memcpy(mtod(m, caddr_t), &hwdst, sizeof(hwdst));
238 IF_ENQUEUE(&ifp->if_snd, m);
239 }
240 if ((ifp->if_flags & IFF_OACTIVE) == 0)
241 (*ifp->if_start)(ifp);
242 splx(s);
243 return 0;
244
245 bad:
246 while (m0 != NULL) {
247 m = m0->m_nextpkt;
248 m_freem(m0);
249 m0 = m;
250 }
251
252 return error;
253 }
254
255 struct mbuf *
256 ieee1394_fragment(struct ifnet *ifp, struct mbuf *m0, int maxsize,
257 u_int16_t etype)
258 {
259 struct ieee1394com *ic = (struct ieee1394com *)ifp;
260 int totlen, fraglen, off;
261 struct mbuf *m, **mp;
262 struct ieee1394_fraghdr *ifh;
263 struct ieee1394_unfraghdr *iuh;
264
265 totlen = m0->m_pkthdr.len;
266 if (totlen + sizeof(struct ieee1394_unfraghdr) <= maxsize) {
267 M_PREPEND(m0, sizeof(struct ieee1394_unfraghdr), M_DONTWAIT);
268 if (m0 == NULL)
269 goto bad;
270 iuh = mtod(m0, struct ieee1394_unfraghdr *);
271 iuh->iuh_ft = 0;
272 iuh->iuh_etype = etype;
273 return m0;
274 }
275
276 fraglen = maxsize - sizeof(struct ieee1394_fraghdr);
277
278 M_PREPEND(m0, sizeof(struct ieee1394_fraghdr), M_DONTWAIT);
279 if (m0 == NULL)
280 goto bad;
281 ifh = mtod(m0, struct ieee1394_fraghdr *);
282 ifh->ifh_ft_size = htons(IEEE1394_FT_MORE | (totlen - 1));
283 ifh->ifh_etype_off = etype;
284 ifh->ifh_dgl = htons(ic->ic_dgl);
285 ifh->ifh_reserved = 0;
286 off = fraglen;
287 mp = &m0->m_nextpkt;
288 while (off < totlen) {
289 if (off + fraglen > totlen)
290 fraglen = totlen - off;
291 MGETHDR(m, M_DONTWAIT, MT_HEADER);
292 if (m == NULL)
293 goto bad;
294 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST); /* copy bcast */
295 MH_ALIGN(m, sizeof(struct ieee1394_fraghdr));
296 m->m_len = sizeof(struct ieee1394_fraghdr);
297 ifh = mtod(m, struct ieee1394_fraghdr *);
298 ifh->ifh_ft_size =
299 htons(IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE | (totlen - 1));
300 ifh->ifh_etype_off = htons(off);
301 ifh->ifh_dgl = htons(ic->ic_dgl);
302 ifh->ifh_reserved = 0;
303 m->m_next = m_copy(m0, off + sizeof(struct ieee1394_fraghdr),
304 fraglen);
305 if (m->m_next == NULL)
306 goto bad;
307 m->m_pkthdr.len = sizeof(struct ieee1394_fraghdr) + fraglen;
308 off += fraglen;
309 *mp = m;
310 mp = &m->m_nextpkt;
311 }
312 ifh->ifh_ft_size &= ~htons(IEEE1394_FT_MORE); /* last fragment */
313 m_adj(m0, -(m0->m_pkthdr.len - maxsize));
314
315 ic->ic_dgl++;
316 return m0;
317
318 bad:
319 while ((m = m0) != NULL) {
320 m0 = m->m_nextpkt;
321 m->m_nextpkt = NULL;
322 m_freem(m);
323 }
324 return NULL;
325 }
326
327 static void
328 ieee1394_input(struct ifnet *ifp, struct mbuf *m)
329 {
330 struct ifqueue *inq;
331 u_int16_t etype;
332 int s;
333 struct ieee1394_header *ih;
334 struct ieee1394_unfraghdr *iuh;
335
336 if ((ifp->if_flags & IFF_UP) == 0) {
337 m_freem(m);
338 return;
339 }
340 if (m->m_len < sizeof(*ih) + sizeof(*iuh)) {
341 m = m_pullup(m, sizeof(*ih) + sizeof(*iuh));
342 if (m == NULL)
343 return;
344 }
345
346 ih = mtod(m, struct ieee1394_header *);
347 iuh = (struct ieee1394_unfraghdr *)&ih[1];
348
349 if (ntohs(iuh->iuh_ft) & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE)) {
350 m = ieee1394_reass(ifp, m);
351 if (m == NULL)
352 return;
353 ih = mtod(m, struct ieee1394_header *);
354 iuh = (struct ieee1394_unfraghdr *)&ih[1];
355 }
356 etype = ntohs(iuh->iuh_etype);
357
358 /* strip off the ieee1394 header */
359 m_adj(m, sizeof(struct ieee1394_header) +
360 sizeof(struct ieee1394_unfraghdr));
361 #if NBPFILTER > 0
362 /* XXX: emulate DLT_EN10MB */
363 if (ifp->if_bpf) {
364 struct mbuf mb;
365
366 mb.m_next = m;
367 mb.m_len = 14;
368 mb.m_data = mb.m_dat;
369 ((u_int32_t *)mb.m_data)[0] = 0;
370 ((u_int32_t *)mb.m_data)[1] = 0;
371 ((u_int32_t *)mb.m_data)[2] = 0;
372 ((u_int16_t *)mb.m_data)[6] = iuh->iuh_etype;
373 bpf_mtap(ifp->if_bpf, &mb);
374 }
375 #endif
376
377 switch (etype) {
378 #ifdef INET
379 case ETHERTYPE_IP:
380 schednetisr(NETISR_IP);
381 inq = &ipintrq;
382 break;
383
384 case ETHERTYPE_ARP:
385 in_ieee1394arpinput(m);
386 return;
387 #endif /* INET */
388
389 #ifdef INET6
390 case ETHERTYPE_IPV6:
391 schednetisr(NETISR_IPV6);
392 inq = &ip6intrq;
393 break;
394 #endif /* INET6 */
395
396 default:
397 m_freem(m);
398 return;
399 }
400
401 s = splimp();
402 if (IF_QFULL(inq)) {
403 IF_DROP(inq);
404 m_freem(m);
405 } else
406 IF_ENQUEUE(inq, m);
407 splx(s);
408 }
409
410 static struct mbuf *
411 ieee1394_reass(struct ifnet *ifp, struct mbuf *m0)
412 {
413 struct ieee1394com *ic = (struct ieee1394com *)ifp;
414 struct ieee1394_header *ih;
415 struct ieee1394_fraghdr *ifh;
416 struct ieee1394_unfraghdr *iuh;
417 struct ieee1394_reassq *rq;
418 struct ieee1394_reass_pkt *rp, *trp, *nrp;
419 int len;
420 u_int16_t off, ftype, size, dgl;
421
422 if (m0->m_len < sizeof(*ih) + sizeof(*ifh)) {
423 m0 = m_pullup(m0, sizeof(*ih) + sizeof(*ifh));
424 if (m0 == NULL)
425 return NULL;
426 }
427 ih = mtod(m0, struct ieee1394_header *);
428 ifh = (struct ieee1394_fraghdr *)&ih[1];
429 m_adj(m0, sizeof(*ih) + sizeof(*ifh));
430 size = ntohs(ifh->ifh_ft_size);
431 ftype = size & (IEEE1394_FT_SUBSEQ | IEEE1394_FT_MORE);
432 size = (size & ~ftype) + 1;
433 dgl = ifh->ifh_dgl;
434 len = m0->m_pkthdr.len;
435 if (ftype & IEEE1394_FT_SUBSEQ) {
436 m0->m_flags &= ~M_PKTHDR;
437 off = ntohs(ifh->ifh_etype_off);
438 } else
439 off = 0;
440
441 for (rq = LIST_FIRST(&ic->ic_reassq); ; rq = LIST_NEXT(rq, rq_node)) {
442 if (rq == NULL) {
443 /*
444 * Create a new reassemble queue head for the node.
445 */
446 rq = malloc(sizeof(*rq), M_FTABLE, M_NOWAIT);
447 if (rq == NULL) {
448 m_freem(m0);
449 return NULL;
450 }
451 memcpy(rq->rq_uid, ih->ih_uid, IEEE1394_ADDR_LEN);
452 LIST_INIT(&rq->rq_pkt);
453 LIST_INSERT_HEAD(&ic->ic_reassq, rq, rq_node);
454 break;
455 }
456 if (memcmp(rq->rq_uid, ih->ih_uid, IEEE1394_ADDR_LEN) == 0)
457 break;
458 }
459 for (rp = LIST_FIRST(&rq->rq_pkt); rp != NULL; rp = nrp) {
460 nrp = LIST_NEXT(rp, rp_next);
461 if (rp->rp_dgl != dgl)
462 continue;
463 /* sanity check: datagram size must be same for all fragments */
464 if (rp->rp_size != size) {
465 /*
466 * This is possibly by wrapping dgl value.
467 * Destroy previous received fragment.
468 */
469 LIST_REMOVE(rp, rp_next);
470 m_freem(rp->rp_m);
471 free(rp, M_FTABLE);
472 continue;
473 }
474 if (rp->rp_off + rp->rp_len == off) {
475 /*
476 * All the subsequent fragments received in sequence
477 * come here.
478 * Concatinate mbuf to previous one instead of
479 * allocating new reassemble queue structure,
480 * and try to merge more with the subsequent fragment
481 * in the queue.
482 */
483 m_cat(rp->rp_m, m0);
484 rp->rp_len += len;
485 while (rp->rp_off + rp->rp_len < size &&
486 nrp != NULL && nrp->rp_dgl == dgl &&
487 nrp->rp_off == rp->rp_off + rp->rp_len) {
488 LIST_REMOVE(nrp, rp_next);
489 m_cat(rp->rp_m, nrp->rp_m);
490 rp->rp_len += nrp->rp_len;
491 nrp = LIST_NEXT(rp, rp_next);
492 }
493 m0 = NULL; /* mark merged */
494 break;
495 }
496 if (off + m0->m_pkthdr.len == rp->rp_off) {
497 m_cat(m0, rp->rp_m);
498 rp->rp_m = m0;
499 rp->rp_off = off;
500 rp->rp_len += len;
501 m0 = NULL; /* mark merged */
502 break;
503 }
504 if (rp->rp_off > off) {
505 /* insert before rp */
506 nrp = rp;
507 break;
508 }
509 if (nrp == NULL || nrp->rp_dgl != dgl) {
510 /* insert after rp */
511 nrp = NULL;
512 break;
513 }
514 }
515 if (m0 == NULL) {
516 if (rp->rp_off != 0 || rp->rp_len != size)
517 return NULL;
518 /* fragment done */
519 LIST_REMOVE(rp, rp_next);
520 m0 = rp->rp_m;
521 m0->m_pkthdr.len = rp->rp_len;
522 M_PREPEND(m0, sizeof(*ih) + sizeof(*iuh), M_DONTWAIT);
523 if (m0 != NULL) {
524 ih = mtod(m0, struct ieee1394_header *);
525 iuh = (struct ieee1394_unfraghdr *)&ih[1];
526 memcpy(ih, &rp->rp_hdr, sizeof(*ih));
527 iuh->iuh_ft = 0;
528 iuh->iuh_etype = rp->rp_etype;
529 }
530 free(rp, M_FTABLE);
531 return m0;
532 }
533
534 /*
535 * New fragment received. Allocate reassemble queue structure.
536 */
537 trp = malloc(sizeof(*trp), M_FTABLE, M_NOWAIT);
538 if (trp == NULL) {
539 m_freem(m0);
540 return NULL;
541 }
542 trp->rp_m = m0;
543 memcpy(&trp->rp_hdr, ih, sizeof(*ih));
544 trp->rp_size = size;
545 trp->rp_etype = ifh->ifh_etype_off; /* valid only if off==0 */
546 trp->rp_off = off;
547 trp->rp_dgl = dgl;
548 trp->rp_len = len;
549
550 if (rp == NULL) {
551 /* first fragment for the dgl */
552 LIST_INSERT_HEAD(&rq->rq_pkt, trp, rp_next);
553 } else if (nrp == NULL) {
554 /* no next fragment for the dgl */
555 LIST_INSERT_AFTER(rp, trp, rp_next);
556 } else {
557 /* there is a hole */
558 LIST_INSERT_BEFORE(nrp, trp, rp_next);
559 }
560 return NULL;
561 }
562
563 const char *
564 ieee1394_sprintf(const u_int8_t *laddr)
565 {
566 static char buf[3*8];
567
568 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
569 laddr[0], laddr[1], laddr[2], laddr[3],
570 laddr[4], laddr[5], laddr[6], laddr[7]);
571 return buf;
572 }
573
574 void
575 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr)
576 {
577 struct sockaddr_dl *sdl;
578 struct ieee1394_hwaddr *baddr;
579 struct ieee1394com *ic = (struct ieee1394com *)ifp;
580
581 ifp->if_type = IFT_IEEE1394;
582 ifp->if_addrlen = sizeof(struct ieee1394_hwaddr);
583 ifp->if_hdrlen = sizeof(struct ieee1394_header);
584 ifp->if_mtu = IEEE1394MTU;
585 ifp->if_output = ieee1394_output;
586 ifp->if_input = ieee1394_input;
587 if (ifp->if_baudrate == 0)
588 ifp->if_baudrate = IF_Mbps(100);
589 if ((sdl = ifp->if_sadl) && sdl->sdl_family == AF_LINK) {
590 sdl->sdl_type = ifp->if_type;
591 sdl->sdl_alen = ifp->if_addrlen;
592 memcpy(LLADDR(sdl), hwaddr, ifp->if_addrlen);
593 }
594 ifp->if_broadcastaddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK);
595 baddr = (struct ieee1394_hwaddr *)ifp->if_broadcastaddr;
596 memset(baddr->iha_uid, 0xff, IEEE1394_ADDR_LEN);
597 baddr->iha_speed = 0; /*XXX*/
598 baddr->iha_maxrec = 512 << baddr->iha_speed;
599 memset(baddr->iha_offset, 0, sizeof(baddr->iha_offset));
600 LIST_INIT(&ic->ic_reassq);
601 }
602
603 void
604 ieee1394_ifdetach(struct ifnet *ifp)
605 {
606 struct sockaddr_dl *sdl = ifp->if_sadl;
607
608 free(ifp->if_broadcastaddr, M_DEVBUF);
609 ifp->if_broadcastaddr = NULL;
610 memset(LLADDR(sdl), 0, sizeof(struct ieee1394_hwaddr));
611 sdl->sdl_alen = 0;
612 sdl->sdl_type = 0;
613 }
614
615 int
616 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
617 {
618 struct ifreq *ifr = (struct ifreq *)data;
619 struct ifaddr *ifa = (struct ifaddr *)data;
620 int error = 0;
621 #if __NetBSD_Version < 105080000
622 int fw_init(struct ifnet *);
623 void fw_stop(struct ifnet *, int);
624 #endif
625
626 switch (cmd) {
627 case SIOCSIFADDR:
628 ifp->if_flags |= IFF_UP;
629 switch (ifa->ifa_addr->sa_family) {
630 #ifdef INET
631 case AF_INET:
632 #if __NetBSD_Version >= 105080000
633 if ((error = (*ifp->if_init)(ifp)) != 0)
634 #else
635 if ((error = fw_init(ifp)) != 0)
636 #endif
637 break;
638 ieee1394arp_ifinit(ifp, ifa);
639 break;
640 #endif /* INET */
641 default:
642 #if __NetBSD_Version >= 105080000
643 error = (*ifp->if_init)(ifp);
644 #else
645 error = fw_init(ifp);
646 #endif
647 break;
648 }
649 break;
650
651 case SIOCGIFADDR:
652 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data,
653 LLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN);
654 break;
655
656 case SIOCSIFMTU:
657 if (ifr->ifr_mtu > IEEE1394MTU)
658 error = EINVAL;
659 else
660 ifp->if_mtu = ifr->ifr_mtu;
661 break;
662
663 case SIOCSIFFLAGS:
664 #if __NetBSD_Version >= 105080000
665 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
666 (*ifp->if_stop)(ifp, 1);
667 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
668 error = (*ifp->if_init)(ifp);
669 else if ((ifp->if_flags & IFF_UP) != 0)
670 error = (*ifp->if_init)(ifp);
671 #else
672 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
673 fw_stop(ifp, 1);
674 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
675 error = fw_init(ifp);
676 else if ((ifp->if_flags & IFF_UP) != 0)
677 error = fw_init(ifp);
678 #endif
679 break;
680
681 case SIOCADDMULTI:
682 case SIOCDELMULTI:
683 /* nothing to do */
684 break;
685
686 default:
687 error = ENOTTY;
688 break;
689 }
690
691 return error;
692 }
693