1 /* $OpenBSD: if_fddisubr.c,v 1.52 2007/06/06 10:04:36 henning Exp $ */
2 /* $NetBSD: if_fddisubr.c,v 1.5 1996/05/07 23:20:21 christos Exp $ */
3
4 /*
5 * Copyright (c) 1995
6 * Matt Thomas. All rights reserved.
7 * Copyright (c) 1982, 1989, 1993
8 * The Regents of the University of California. All rights reserved.
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. Neither the name of the University nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
33 *
34 * @(#)if_fddisubr.c 8.1 (Berkeley) 6/10/93
35 */
36
37 /*
38 * @(#)COPYRIGHT 1.1 (NRL) January 1997
39 *
40 * NRL grants permission for redistribution and use in source and binary
41 * forms, with or without modification, of the software and documentation
42 * created at NRL provided that the following conditions are met:
43 *
44 * 1. Redistributions of source code must retain the above copyright
45 * notice, this list of conditions and the following disclaimer.
46 * 2. Redistributions in binary form must reproduce the above copyright
47 * notice, this list of conditions and the following disclaimer in the
48 * documentation and/or other materials provided with the distribution.
49 * 3. All advertising materials mentioning features or use of this software
50 * must display the following acknowledgements:
51 * This product includes software developed by the University of
52 * California, Berkeley and its contributors.
53 * This product includes software developed at the Information
54 * Technology Division, US Naval Research Laboratory.
55 * 4. Neither the name of the NRL nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THE SOFTWARE PROVIDED BY NRL IS PROVIDED BY NRL AND CONTRIBUTORS ``AS
60 * IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
61 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
62 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL NRL OR
63 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
64 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
65 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
66 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
67 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
68 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
69 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
70 *
71 * The views and conclusions contained in the software and documentation
72 * are those of the authors and should not be interpreted as representing
73 * official policies, either expressed or implied, of the US Naval
74 * Research Laboratory (NRL).
75 */
76
77 #include <sys/param.h>
78 #include <sys/systm.h>
79 #include <sys/kernel.h>
80 #include <sys/malloc.h>
81 #include <sys/mbuf.h>
82 #include <sys/protosw.h>
83 #include <sys/socket.h>
84 #include <sys/ioctl.h>
85 #include <sys/errno.h>
86 #include <sys/syslog.h>
87
88 #include <machine/cpu.h>
89
90 #include <net/if.h>
91 #include <net/netisr.h>
92 #include <net/route.h>
93 #include <net/if_llc.h>
94 #include <net/if_dl.h>
95 #include <net/if_types.h>
96
97 #ifdef INET
98 #include <netinet/in.h>
99 #include <netinet/in_var.h>
100 #endif
101 #include <netinet/if_ether.h>
102 #include <net/if_fddi.h>
103
104 #ifdef INET6
105 #ifndef INET
106 #include <netinet/in.h>
107 #include <netinet/in_var.h>
108 #endif
109 #include <netinet6/nd6.h>
110 #endif
111
112 #include "bpfilter.h"
113
114 #include "carp.h"
115 #if NCARP > 0
116 #include <netinet/ip_carp.h>
117 #endif
118
119 #define senderr(e) { error = (e); goto bad;}
120
121 /*
122 * This really should be defined in if_llc.h but in case it isn't.
123 */
124 #ifndef llc_snap
125 #define llc_snap llc_un.type_snap
126 #endif
127
128 /*
129 * FDDI output routine.
130 * Encapsulate a packet of type family for the local net.
131 * Assumes that ifp is actually pointer to arpcom structure.
132 */
133 int
134 fddi_output(ifp0, m0, dst, rt0)
135 struct ifnet *ifp0;
136 struct mbuf *m0;
137 struct sockaddr *dst;
138 struct rtentry *rt0;
139 {
140 u_int16_t type;
141 int s, len, error = 0, hdrcmplt = 0;
142 u_char edst[6], esrc[6];
143 struct mbuf *m = m0;
144 struct rtentry *rt;
145 struct mbuf *mcopy = (struct mbuf *)0;
146 struct fddi_header *fh;
147 struct arpcom *ac = (struct arpcom *)ifp0;
148 short mflags;
149 struct ifnet *ifp = ifp0;
150
151 #if NCARP > 0
152 if (ifp->if_type == IFT_CARP) {
153 struct ifaddr *ifa;
154
155 /* loop back if this is going to the carp interface */
156 if (dst != NULL && LINK_STATE_IS_UP(ifp0->if_link_state) &&
157 (ifa = ifa_ifwithaddr(dst)) != NULL &&
158 ifa->ifa_ifp == ifp0)
159 return (looutput(ifp0, m, dst, rt0));
160
161 ifp = ifp->if_carpdev;
162 ac = (struct arpcom *)ifp;
163
164 if ((ifp0->if_flags & (IFF_UP|IFF_RUNNING)) !=
165 (IFF_UP|IFF_RUNNING))
166 senderr(ENETDOWN);
167 }
168 #endif /* NCARP > 0 */
169 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
170 senderr(ENETDOWN);
171 if ((rt = rt0) != NULL) {
172 if ((rt->rt_flags & RTF_UP) == 0) {
173 if ((rt0 = rt = rtalloc1(dst, 1, 0)) != NULL)
174 rt->rt_refcnt--;
175 else
176 senderr(EHOSTUNREACH);
177 }
178 if (rt->rt_flags & RTF_GATEWAY) {
179 if (rt->rt_gwroute == 0)
180 goto lookup;
181 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
182 rtfree(rt); rt = rt0;
183 lookup: rt->rt_gwroute = rtalloc1(rt->rt_gateway, 1, 0);
184 if ((rt = rt->rt_gwroute) == 0)
185 senderr(EHOSTUNREACH);
186 }
187 }
188 if (rt->rt_flags & RTF_REJECT)
189 if (rt->rt_rmx.rmx_expire == 0 ||
190 time_second < rt->rt_rmx.rmx_expire)
191 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
192 }
193
194 switch (dst->sa_family) {
195
196 #ifdef INET
197 case AF_INET:
198 if (!arpresolve(ac, rt, m, dst, edst))
199 return (0); /* if not yet resolved */
200 /* If broadcasting on a simplex interface, loopback a copy */
201 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
202 !m->m_pkthdr.pf.routed)
203 mcopy = m_copy(m, 0, (int)M_COPYALL);
204 type = htons(ETHERTYPE_IP);
205 break;
206 #endif
207 #ifdef INET6
208 case AF_INET6:
209 if (!nd6_storelladdr(ifp, rt, m, dst, (u_char *)edst))
210 return (0); /* if not yet resolved */
211 type = htons(ETHERTYPE_IPV6);
212 break;
213 #endif
214 #if 0 /*NRL IPv6*/
215 #ifdef INET6
216 case AF_INET6:
217 /*
218 * The bottom line here is to either queue the outgoing packet
219 * in the discovery engine, or fill in edst with something
220 * that'll work.
221 */
222 if (m->m_flags & M_MCAST) {
223 /*
224 * If multicast dest., then use IPv6 -> Ethernet mcast
225 * mapping. Really simple.
226 */
227 ETHER_MAP_IN6_MULTICAST(((struct sockaddr_in6 *)dst)->sin6_addr,
228 edst);
229 } else {
230 /* Do unicast neighbor discovery stuff. */
231 if (!ipv6_discov_resolve(ifp, rt, m, dst, edst))
232 return 0;
233 }
234 type = htons(ETHERTYPE_IPV6);
235 break;
236 #endif /* INET6 */
237 #endif
238
239 case pseudo_AF_HDRCMPLT:
240 {
241 struct fddi_header *fh = (struct fddi_header *)dst->sa_data;
242 hdrcmplt = 1;
243 bcopy((caddr_t)fh->fddi_shost, (caddr_t)esrc, sizeof (esrc));
244 /* FALLTHROUGH */
245 }
246
247 case AF_UNSPEC:
248 {
249 struct ether_header *eh;
250 eh = (struct ether_header *)dst->sa_data;
251 bcopy((caddr_t)eh->ether_dhost, (caddr_t)edst, sizeof (edst));
252 if (*edst & 1)
253 m->m_flags |= (M_BCAST|M_MCAST);
254 type = eh->ether_type;
255 break;
256 }
257
258 #if NBPFILTER > 0
259 case AF_IMPLINK:
260 {
261 fh = mtod(m, struct fddi_header *);
262 error = EPROTONOSUPPORT;
263 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
264 case FDDIFC_LLC_ASYNC: {
265 /* legal priorities are 0 through 7 */
266 if ((fh->fddi_fc & FDDIFC_Z) > 7)
267 goto bad;
268 break;
269 }
270 case FDDIFC_LLC_SYNC: {
271 /* FDDIFC_Z bits reserved, must be zero */
272 if (fh->fddi_fc & FDDIFC_Z)
273 goto bad;
274 break;
275 }
276 case FDDIFC_SMT: {
277 /* FDDIFC_Z bits must be non zero */
278 if ((fh->fddi_fc & FDDIFC_Z) == 0)
279 goto bad;
280 break;
281 }
282 default: {
283 /* anything else is too dangerous */
284 goto bad;
285 }
286 }
287 error = 0;
288 if (fh->fddi_dhost[0] & 1)
289 m->m_flags |= (M_BCAST|M_MCAST);
290 goto queue_it;
291 }
292 #endif
293 default:
294 printf("%s: can't handle af%d\n", ifp->if_xname,
295 dst->sa_family);
296 senderr(EAFNOSUPPORT);
297 }
298
299 if (mcopy)
300 (void) looutput(ifp, mcopy, dst, rt);
301
302 if (type != 0) {
303 struct llc *l;
304 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
305 if (m == 0)
306 senderr(ENOBUFS);
307 l = mtod(m, struct llc *);
308 l->llc_control = LLC_UI;
309 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
310 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
311 bcopy((caddr_t) &type, (caddr_t) &l->llc_snap.ether_type,
312 sizeof(u_short));
313 }
314 /*
315 * Add local net header. If no space in first mbuf,
316 * allocate another.
317 */
318 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT);
319 if (m == 0)
320 senderr(ENOBUFS);
321 fh = mtod(m, struct fddi_header *);
322 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
323 bcopy((caddr_t)edst, (caddr_t)fh->fddi_dhost, sizeof (edst));
324 #if NBPFILTER > 0
325 queue_it:
326 #endif
327 if (hdrcmplt)
328 bcopy((caddr_t)esrc, (caddr_t)fh->fddi_shost,
329 sizeof(fh->fddi_shost));
330 else
331 bcopy((caddr_t)ac->ac_enaddr, (caddr_t)fh->fddi_shost,
332 sizeof(fh->fddi_shost));
333 #if NCARP > 0
334 if (ifp0 != ifp && ifp0->if_type == IFT_CARP) {
335 bcopy((caddr_t)((struct arpcom *)ifp0)->ac_enaddr,
336 (caddr_t)fh->fddi_shost, sizeof(fh->fddi_shost));
337 }
338 #endif
339 mflags = m->m_flags;
340 len = m->m_pkthdr.len;
341 s = splnet();
342 /*
343 * Queue message on interface, and start output if interface
344 * not yet active.
345 */
346 IFQ_ENQUEUE(&ifp->if_snd, m, NULL, error);
347 if (error) {
348 /* mbuf is already freed */
349 splx(s);
350 return (error);
351 }
352 ifp->if_obytes += len;
353 #if NCARP > 0
354 if (ifp != ifp0)
355 ifp0->if_obytes += len;
356 #endif /* NCARP > 0 */
357 if (mflags & M_MCAST)
358 ifp->if_omcasts++;
359 if ((ifp->if_flags & IFF_OACTIVE) == 0)
360 (*ifp->if_start)(ifp);
361 splx(s);
362 return (error);
363
364 bad:
365 if (m)
366 m_freem(m);
367 return (error);
368 }
369
370 /*
371 * Process a received FDDI packet;
372 * the packet is in the mbuf chain m without
373 * the fddi header, which is provided separately.
374 */
375 void
376 fddi_input(ifp, fh, m)
377 struct ifnet *ifp;
378 struct fddi_header *fh;
379 struct mbuf *m;
380 {
381 struct ifqueue *inq;
382 struct llc *l;
383 int s;
384
385 if ((ifp->if_flags & IFF_UP) == 0) {
386 m_freem(m);
387 return;
388 }
389 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh);
390 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost,
391 sizeof(fddibroadcastaddr)) == 0)
392 m->m_flags |= M_BCAST;
393 else if (fh->fddi_dhost[0] & 1)
394 m->m_flags |= M_MCAST;
395 if (m->m_flags & (M_BCAST|M_MCAST))
396 ifp->if_imcasts++;
397
398 l = mtod(m, struct llc *);
399 switch (l->llc_dsap) {
400 #if defined(INET) || defined(INET6)
401 case LLC_SNAP_LSAP:
402 {
403 u_int16_t etype;
404 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP)
405 goto dropanyway;
406 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0)
407 goto dropanyway;
408 etype = ntohs(l->llc_snap.ether_type);
409 m_adj(m, LLC_SNAPFRAMELEN);
410
411 #if NCARP > 0
412 if (ifp->if_carp && ifp->if_type != IFT_CARP &&
413 (carp_input(m, (u_int8_t *)&fh->fddi_shost,
414 (u_int8_t *)&fh->fddi_dhost, l->llc_snap.ether_type) == 0))
415 return;
416 #endif
417
418 switch (etype) {
419 #ifdef INET
420 case ETHERTYPE_IP:
421 schednetisr(NETISR_IP);
422 inq = &ipintrq;
423 break;
424
425 case ETHERTYPE_ARP:
426 if (ifp->if_flags & IFF_NOARP)
427 goto dropanyway;
428 schednetisr(NETISR_ARP);
429 inq = &arpintrq;
430 break;
431 #endif
432 #ifdef INET6
433 case ETHERTYPE_IPV6:
434 schednetisr(NETISR_IPV6);
435 inq = &ip6intrq;
436 break;
437 #endif /* INET6 */
438 default:
439 /* printf("fddi_input: unknown protocol 0x%x\n", etype); */
440 ifp->if_noproto++;
441 goto dropanyway;
442 }
443 break;
444 }
445 #endif /* INET || INET6 */
446
447 default:
448 /* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
449 ifp->if_noproto++;
450 dropanyway:
451 m_freem(m);
452 return;
453 }
454
455 s = splnet();
456 IF_INPUT_ENQUEUE(inq, m);
457 splx(s);
458 }
459 /*
460 * Perform common duties while attaching to interface list
461 */
462 void
463 fddi_ifattach(ifp)
464 struct ifnet *ifp;
465 {
466
467 ifp->if_type = IFT_FDDI;
468 ifp->if_addrlen = 6;
469 ifp->if_hdrlen = 21;
470 ifp->if_mtu = FDDIMTU;
471 ifp->if_output = fddi_output;
472 if_alloc_sadl(ifp);
473 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
474 LLADDR(ifp->if_sadl), ifp->if_addrlen);
475 }