if_ieee1394subr.c revision 1.1 1 /* $NetBSD: if_ieee1394subr.c,v 1.1 2000/11/05 17:17:15 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
81 static int
82 ieee1394_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
83 struct rtentry *rt0)
84 {
85 u_int16_t etype = 0;
86 int s, hdrlen, maxrec, len, off, tlen, error = 0;
87 struct mbuf *m = m0, **mp;
88 struct rtentry *rt;
89 struct mbuf *mcopy = NULL;
90 struct ieee1394com *ic = (struct ieee1394com *)ifp;
91 #ifdef INET
92 struct ieee1394_arphdr *ah;
93 #endif /* INET */
94 struct ieee1394_unfraghdr *iuh;
95 struct ieee1394_fraghdr *ifh;
96 struct ieee1394_hwaddr hwdst;
97
98 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
99 senderr(ENETDOWN);
100 ifp->if_lastchange = time;
101 if ((rt = rt0) != NULL) {
102 if ((rt->rt_flags & RTF_UP) == 0) {
103 if ((rt0 = rt = rtalloc1(dst, 1)) != NULL) {
104 rt->rt_refcnt--;
105 if (rt->rt_ifp != ifp)
106 return (*rt->rt_ifp->if_output)
107 (ifp, m0, dst, rt);
108 } else
109 senderr(EHOSTUNREACH);
110 }
111 if (rt->rt_flags & RTF_GATEWAY) {
112 if (rt->rt_gwroute == 0)
113 goto lookup;
114 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
115 rtfree(rt);
116 rt = rt0;
117 lookup:
118 rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1);
119 if ((rt = rt->rt_gwroute) == 0)
120 senderr(EHOSTUNREACH);
121 /* the "G" test below also prevents rt == rt0 */
122 if ((rt->rt_flags & RTF_GATEWAY) ||
123 (rt->rt_ifp != ifp)) {
124 rt->rt_refcnt--;
125 rt0->rt_gwroute = 0;
126 senderr(EHOSTUNREACH);
127 }
128 }
129 }
130 if (rt->rt_flags & RTF_REJECT)
131 if (rt->rt_rmx.rmx_expire == 0 ||
132 time.tv_sec < rt->rt_rmx.rmx_expire)
133 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
134 }
135 switch (dst->sa_family) {
136 #ifdef INET
137 case AF_INET:
138 if (m->m_flags & (M_BCAST|M_MCAST))
139 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
140 else if (!ieee1394arpresolve(ifp, rt, m, dst, &hwdst))
141 return 0; /* if not yet resolved */
142 /* if broadcasting on a simplex interface, loopback a copy */
143 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
144 mcopy = m_copy(m, 0, (int)M_COPYALL);
145 etype = htons(ETHERTYPE_IP);
146 break;
147
148 case AF_ARP:
149 ah = mtod(m, struct ieee1394_arphdr *);
150 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
151 etype = htons(ETHERTYPE_ARP);
152 break;
153 #endif /* INET */
154 #ifdef INET6
155 case AF_INET6:
156 if (m->m_flags & M_MCAST)
157 memcpy(&hwdst, ifp->if_broadcastaddr, sizeof(hwdst));
158 else if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)&hwdst)) {
159 /* this must be impossible, so we bark */
160 printf("ieee1394_output: nd6_storelladdr failed\n");
161 return 0;
162 }
163 etype = htons(ETHERTYPE_IPV6);
164 break;
165 #endif /* INET6 */
166
167 case pseudo_AF_HDRCMPLT:
168 case AF_UNSPEC:
169 /* TODO? */
170 default:
171 printf("%s: can't handle af%d\n", ifp->if_xname,
172 dst->sa_family);
173 senderr(EAFNOSUPPORT);
174 break;
175 }
176
177 if (mcopy)
178 looutput(ifp, mcopy, dst, rt);
179 #if NBPFILTER > 0
180 if (ifp->if_bpf) {
181 struct mbuf mb;
182
183 mb.m_next = m;
184 mb.m_len = 14;
185 mb.m_data = mb.m_dat;
186 ((u_int32_t *)mb.m_data)[0] = 0;
187 ((u_int32_t *)mb.m_data)[1] = 0;
188 ((u_int32_t *)mb.m_data)[2] = 0;
189 ((u_int16_t *)mb.m_data)[6] = etype;
190 bpf_mtap(ifp->if_bpf, &mb);
191 }
192 #endif
193
194 /* determine fragmented or not */
195 maxrec = 1 << (hwdst.iha_maxrec + 1);
196 if (m->m_flags & (M_BCAST|M_MCAST))
197 hdrlen = IEEE1394_STRHDRLEN + sizeof(*iuh);
198 else
199 hdrlen = IEEE1394_AWBHDRLEN + sizeof(*iuh);
200 if (m->m_pkthdr.len < maxrec - hdrlen) {
201 M_PREPEND(m, sizeof(hwdst) + sizeof(*iuh), M_DONTWAIT);
202 if (m == 0)
203 senderr(ENOBUFS);
204 memcpy(mtod(m, caddr_t), &hwdst, sizeof(hwdst));
205 iuh = (struct ieee1394_unfraghdr *)
206 (mtod(m, caddr_t) + sizeof(hwdst));
207 iuh->iuh_ft = 0;
208 iuh->iuh_etype = etype;
209
210 s = splimp();
211 if (IF_QFULL(&ifp->if_snd)) {
212 IF_DROP(&ifp->if_snd);
213 splx(s);
214 senderr(ENOBUFS);
215 }
216 IF_ENQUEUE(&ifp->if_snd, m);
217 ifp->if_obytes += m0->m_pkthdr.len;
218 goto done;
219 }
220 printf("ieee1304_output: fragment packet\n");
221 hdrlen += sizeof(*ifh) - sizeof(*iuh);
222 len = maxrec - hdrlen;
223 off = len;
224 mp = &m0->m_nextpkt;
225 while (off < m0->m_pkthdr.len) {
226 MGETHDR(m, M_DONTWAIT, MT_HEADER);
227 if (m == NULL)
228 senderr(ENOBUFS);
229 m->m_flags |= m0->m_flags & (M_BCAST|M_MCAST);
230 tlen = len;
231 if (tlen > m0->m_pkthdr.len - off)
232 tlen = m0->m_pkthdr.len - off;
233 m->m_data += hdrlen - sizeof(hwdst);
234 m->m_len = sizeof(hwdst) + sizeof(*ifh);
235 memcpy(mtod(m, caddr_t), &hwdst, sizeof(hwdst));
236 ifh = (struct ieee1394_fraghdr *)
237 (mtod(m, caddr_t) + sizeof(hwdst));
238 ifh->ifh_ft_size = htons(0xc000 | tlen);
239 ifh->ifh_etype_off = htons(off);
240 ifh->ifh_dgl = htons(ic->ic_dgl);
241 ifh->ifh_reserved = 0;
242 m->m_next = m_copy(m0, off, tlen);
243 if (m->m_next == NULL)
244 senderr(ENOBUFS);
245 off += tlen;
246 *mp = m;
247 mp = &m->m_nextpkt;
248 }
249 ifh->ifh_ft_size &= ~htons(0x4000); /* note last fragment */
250
251 /* first fragment */
252 m = m0;
253 M_PREPEND(m, sizeof(hwdst) + sizeof(*ifh), M_DONTWAIT);
254 memcpy(mtod(m, caddr_t), &hwdst, sizeof(hwdst));
255 ifh = (struct ieee1394_fraghdr *)(mtod(m, caddr_t) + sizeof(hwdst));
256 ifh->ifh_ft_size = htons(0x4000 | (maxrec - hdrlen));
257 ifh->ifh_etype_off = etype;
258 ifh->ifh_dgl = htons(ic->ic_dgl++);
259 ifh->ifh_reserved = 0;
260
261 /* send off */
262
263 s = splimp();
264 if (IF_QFULL(&ifp->if_snd)) {
265 IF_DROP(&ifp->if_snd);
266 splx(s);
267 senderr(ENOBUFS);
268 }
269 while (m0 != NULL) {
270 m = m0->m_nextpkt;
271 m0->m_nextpkt = NULL;
272 IF_ENQUEUE(&ifp->if_snd, m0);
273 ifp->if_obytes += m0->m_pkthdr.len;
274 m0 = m;
275 }
276
277 done:
278 if (m0->m_flags & M_MCAST)
279 ifp->if_omcasts++;
280 if ((ifp->if_flags & IFF_OACTIVE) == 0)
281 (*ifp->if_start)(ifp);
282 splx(s);
283 return error;
284
285 bad:
286 while (m0 != NULL) {
287 m = m0->m_nextpkt;
288 m_freem(m0);
289 m0 = m;
290 }
291
292 return error;
293 }
294
295 static void
296 ieee1394_input(struct ifnet *ifp, struct mbuf *m)
297 {
298 struct ifqueue *inq;
299 u_int16_t etype;
300 int s;
301 struct ieee1394_unfraghdr *iuh;
302
303 if ((ifp->if_flags & IFF_UP) == 0) {
304 m_freem(m);
305 return;
306 }
307
308 iuh = mtod(m, struct ieee1394_unfraghdr *);
309 if (iuh->iuh_ft != 0) {
310 printf("%s: ieee1394_input: fragment not implemented yet\n",
311 ifp->if_xname);
312 m_freem(m);
313 return;
314 }
315 etype = ntohs(iuh->iuh_etype);
316
317 /* strip off the ieee1394 header */
318 m_adj(m, sizeof(struct ieee1394_unfraghdr));
319 #if NBPFILTER > 0
320 if (ifp->if_bpf) {
321 struct mbuf mb;
322
323 mb.m_next = m;
324 mb.m_len = 14;
325 mb.m_data = mb.m_dat;
326 ((u_int32_t *)mb.m_data)[0] = 0;
327 ((u_int32_t *)mb.m_data)[1] = 0;
328 ((u_int32_t *)mb.m_data)[2] = 0;
329 ((u_int16_t *)mb.m_data)[6] = iuh->iuh_etype;
330 bpf_mtap(ifp->if_bpf, &mb);
331 }
332 #endif
333
334 switch (etype) {
335 #ifdef INET
336 case ETHERTYPE_IP:
337 schednetisr(NETISR_IP);
338 inq = &ipintrq;
339 break;
340
341 case ETHERTYPE_ARP:
342 in_ieee1394arpinput(m);
343 return;
344 #endif /* INET */
345
346 #ifdef INET6
347 case ETHERTYPE_IPV6:
348 schednetisr(NETISR_IPV6);
349 inq = &ip6intrq;
350 break;
351 #endif /* INET6 */
352
353 default:
354 m_freem(m);
355 return;
356 }
357
358 s = splimp();
359 if (IF_QFULL(inq)) {
360 IF_DROP(inq);
361 m_freem(m);
362 } else
363 IF_ENQUEUE(inq, m);
364 splx(s);
365 }
366
367 const char *
368 ieee1394_sprintf(const u_int8_t *laddr)
369 {
370 static char buf[3*8];
371
372 snprintf(buf, sizeof(buf), "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x",
373 laddr[0], laddr[1], laddr[2], laddr[3],
374 laddr[4], laddr[5], laddr[6], laddr[7]);
375 return buf;
376 }
377
378 void
379 ieee1394_ifattach(struct ifnet *ifp, const struct ieee1394_hwaddr *hwaddr)
380 {
381 struct sockaddr_dl *sdl;
382
383 ifp->if_type = IFT_IEEE1394;
384 ifp->if_addrlen = sizeof(struct ieee1394_hwaddr);
385 ifp->if_hdrlen = sizeof(struct ieee1394_header);
386 ifp->if_mtu = IEEE1394MTU;
387 ifp->if_output = ieee1394_output;
388 ifp->if_input = ieee1394_input;
389 if (ifp->if_baudrate == 0)
390 ifp->if_baudrate = IF_Mbps(100);
391 if ((sdl = ifp->if_sadl) && sdl->sdl_family == AF_LINK) {
392 sdl->sdl_type = ifp->if_type;
393 sdl->sdl_alen = ifp->if_addrlen;
394 memcpy(LLADDR(sdl), hwaddr, ifp->if_addrlen);
395 }
396 ifp->if_broadcastaddr = malloc(ifp->if_addrlen, M_DEVBUF, M_WAITOK);
397 memcpy(ifp->if_broadcastaddr, hwaddr, ifp->if_addrlen);
398 memset(ifp->if_broadcastaddr, 0xff, IEEE1394_ADDR_LEN);
399 }
400
401 void
402 ieee1394_ifdetach(struct ifnet *ifp)
403 {
404 struct sockaddr_dl *sdl = ifp->if_sadl;
405
406 free(ifp->if_broadcastaddr, M_DEVBUF);
407 ifp->if_broadcastaddr = NULL;
408 memset(LLADDR(sdl), 0, sizeof(struct ieee1394_hwaddr));
409 sdl->sdl_alen = 0;
410 sdl->sdl_type = 0;
411 }
412
413 int
414 ieee1394_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
415 {
416 struct ifreq *ifr = (struct ifreq *)data;
417 struct ifaddr *ifa = (struct ifaddr *)data;
418 int error = 0;
419 #if __NetBSD_Version < 105080000
420 int fw_init(struct ifnet *);
421 void fw_stop(struct ifnet *, int);
422 #endif
423
424 switch (cmd) {
425 case SIOCSIFADDR:
426 ifp->if_flags |= IFF_UP;
427 switch (ifa->ifa_addr->sa_family) {
428 #ifdef INET
429 case AF_INET:
430 #if __NetBSD_Version >= 105080000
431 if ((error = (*ifp->if_init)(ifp)) != 0)
432 #else
433 if ((error = fw_init(ifp)) != 0)
434 #endif
435 break;
436 ieee1394arp_ifinit(ifp, ifa);
437 break;
438 #endif /* INET */
439 default:
440 #if __NetBSD_Version >= 105080000
441 error = (*ifp->if_init)(ifp);
442 #else
443 error = fw_init(ifp);
444 #endif
445 break;
446 }
447 break;
448
449 case SIOCGIFADDR:
450 memcpy(((struct sockaddr *)&ifr->ifr_data)->sa_data,
451 LLADDR(ifp->if_sadl), IEEE1394_ADDR_LEN);
452 break;
453
454 case SIOCSIFMTU:
455 if (ifr->ifr_mtu > IEEE1394MTU)
456 error = EINVAL;
457 else
458 ifp->if_mtu = ifr->ifr_mtu;
459 break;
460
461 case SIOCSIFFLAGS:
462 #if __NetBSD_Version >= 105080000
463 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
464 (*ifp->if_stop)(ifp, 1);
465 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
466 error = (*ifp->if_init)(ifp);
467 else if ((ifp->if_flags & IFF_UP) != 0)
468 error = (*ifp->if_init)(ifp);
469 #else
470 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_RUNNING)
471 fw_stop(ifp, 1);
472 else if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) == IFF_UP)
473 error = fw_init(ifp);
474 else if ((ifp->if_flags & IFF_UP) != 0)
475 error = fw_init(ifp);
476 #endif
477 break;
478
479 case SIOCADDMULTI:
480 case SIOCDELMULTI:
481 /* nothing to do */
482 break;
483
484 default:
485 error = ENOTTY;
486 break;
487 }
488
489 return error;
490 }
491