1/*
2 * Copyright (c) 1982, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
34 * $Id: if_fddisubr.c,v 1.7 1996/04/07 17:39:04 bde Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/ioctl.h>
45#include <sys/errno.h>
46#include <sys/syslog.h>
47
48#include <net/if.h>
49#include <net/netisr.h>
50#include <net/route.h>
51#include <net/if_llc.h>
52#include <net/if_dl.h>
53#include <net/if_types.h>
54
55#ifdef INET
56#include <netinet/in.h>
57#include <netinet/in_var.h>
58#endif
59#include <netinet/if_ether.h>
60#include <netinet/if_fddi.h>
61
62#ifdef IPX
63#include <netipx/ipx.h>
64#include <netipx/ipx_if.h>
65#endif
66
67#ifdef NS
68#include <netns/ns.h>
69#include <netns/ns_if.h>
70#endif
71
72#ifdef DECNET
73#include <netdnet/dn.h>
74#endif
75
76#ifdef ISO
77#include <netiso/argo_debug.h>
78#include <netiso/iso.h>
79#include <netiso/iso_var.h>
80#include <netiso/iso_snpac.h>
81#endif
82
83#include "bpfilter.h"
84
85#ifdef LLC
86#include <netccitt/dll.h>
87#include <netccitt/llc_var.h>
88#endif
89
90#if defined(LLC) && defined(CCITT)
91extern struct ifqueue pkintrq;
92#endif
93
94#define senderr(e) { error = (e); goto bad;}
95
96/*
97 * This really should be defined in if_llc.h but in case it isn't.
98 */
99#ifndef llc_snap
100#define llc_snap llc_un.type_snap
101#endif
102
103#ifdef __bsdi__
104#define RTALLOC1(a, b) rtalloc1(a, b)
105#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e)
106#else
107#define RTALLOC1(a, b) rtalloc1(a, b, 0UL)
108#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f)
109#endif
110/*
111 * FDDI output routine.
112 * Encapsulate a packet of type family for the local net.
113 * Use trailer local net encapsulation if enough data in first
114 * packet leaves a multiple of 512 bytes of data in remainder.
115 * Assumes that ifp is actually pointer to arpcom structure.
116 */
117int
118fddi_output(ifp, m0, dst, rt0)
119 register struct ifnet *ifp;
120 struct mbuf *m0;
121 struct sockaddr *dst;
122 struct rtentry *rt0;
123{
124 short type;
125 int s, error = 0;
126 u_char edst[6];
127 register struct mbuf *m = m0;
128 register struct rtentry *rt;
129 struct mbuf *mcopy = (struct mbuf *)0;
130 register struct fddi_header *fh;
131 struct arpcom *ac = (struct arpcom *)ifp;
132
133 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
134 senderr(ENETDOWN);
135 ifp->if_lastchange = time;
136 if (rt = rt0) {
137 if ((rt->rt_flags & RTF_UP) == 0) {
138 if (rt0 = rt = RTALLOC1(dst, 1))
139 rt->rt_refcnt--;
140 else
141 senderr(EHOSTUNREACH);
142 }
143 if (rt->rt_flags & RTF_GATEWAY) {
144 if (rt->rt_gwroute == 0)
145 goto lookup;
146 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
147 rtfree(rt); rt = rt0;
148 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1);
149 if ((rt = rt->rt_gwroute) == 0)
150 senderr(EHOSTUNREACH);
151 }
152 }
153 if (rt->rt_flags & RTF_REJECT)
154 if (rt->rt_rmx.rmx_expire == 0 ||
155 time.tv_sec < rt->rt_rmx.rmx_expire)
156 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
157 }
158 switch (dst->sa_family) {
159
160#ifdef INET
161 case AF_INET:
162 if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0))
163 return (0); /* if not yet resolved */
164 /* If broadcasting on a simplex interface, loopback a copy */
165 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
166 mcopy = m_copy(m, 0, (int)M_COPYALL);
167 type = ETHERTYPE_IP;
168 break;
169#endif
170#ifdef IPX
171 case AF_IPX:
172 type = ETHERTYPE_IPX;
173 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
174 (caddr_t)edst, sizeof (edst));
175 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
176 return (looutput(ifp, m, dst, rt));
177 /* If broadcasting on a simplex interface, loopback a copy */
178 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
179 mcopy = m_copy(m, 0, (int)M_COPYALL);
180 break;
181#endif
182#ifdef NS
183 case AF_NS:
184 type = ETHERTYPE_NS;
185 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
186 (caddr_t)edst, sizeof (edst));
187 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
188 return (looutput(ifp, m, dst, rt));
189 /* If broadcasting on a simplex interface, loopback a copy */
190 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
191 mcopy = m_copy(m, 0, (int)M_COPYALL);
192 break;
193#endif
194#ifdef ISO
195 case AF_ISO: {
196 int snpalen;
197 struct llc *l;
198 register struct sockaddr_dl *sdl;
199
200 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
201 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
202 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
203 } else if (error =
204 iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
205 (char *)edst, &snpalen))
206 goto bad; /* Not Resolved */
207 /* If broadcasting on a simplex interface, loopback a copy */
208 if (*edst & 1)
209 m->m_flags |= (M_BCAST|M_MCAST);
210 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
211 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
212 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT);
213 if (mcopy) {
214 fh = mtod(mcopy, struct fddi_header *);
215 bcopy((caddr_t)edst,
216 (caddr_t)fh->fddi_dhost, sizeof (edst));
217 bcopy((caddr_t)ac->ac_enaddr,
218 (caddr_t)fh->fddi_shost, sizeof (edst));
219 }
220 }
221 M_PREPEND(m, 3, M_DONTWAIT);
222 if (m == NULL)
223 return (0);
224 type = 0;
225 l = mtod(m, struct llc *);
226 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
227 l->llc_control = LLC_UI;
228 IFDEBUG(D_ETHER)
229 int i;
230 printf("unoutput: sending pkt to: ");
231 for (i=0; i<6; i++)
232 printf("%x ", edst[i] & 0xff);
233 printf("\n");
234 ENDDEBUG
235 } break;
236#endif /* ISO */
237#ifdef LLC
238/* case AF_NSAP: */
239 case AF_CCITT: {
240 register struct sockaddr_dl *sdl =
241 (struct sockaddr_dl *) rt -> rt_gateway;
242
243 if (sdl && sdl->sdl_family == AF_LINK
244 && sdl->sdl_alen > 0) {
245 bcopy(LLADDR(sdl), (char *)edst,
246 sizeof(edst));
247 } else goto bad; /* Not a link interface ? Funny ... */
248 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
249 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
250 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT);
251 if (mcopy) {
252 fh = mtod(mcopy, struct fddi_header *);
253 bcopy((caddr_t)edst,
254 (caddr_t)fh->fddi_dhost, sizeof (edst));
255 bcopy((caddr_t)ac->ac_enaddr,
256 (caddr_t)fh->fddi_shost, sizeof (edst));
257 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
258 }
259 }
260 type = 0;
261#ifdef LLC_DEBUG
262 {
263 int i;
264 register struct llc *l = mtod(m, struct llc *);
265
266 printf("fddi_output: sending LLC2 pkt to: ");
267 for (i=0; i<6; i++)
268 printf("%x ", edst[i] & 0xff);
269 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
270 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff,
271 l->llc_control & 0xff);
272
273 }
274#endif /* LLC_DEBUG */
275 } break;
276#endif /* LLC */
277
278 case AF_UNSPEC:
279 {
280 struct ether_header *eh;
281 eh = (struct ether_header *)dst->sa_data;
282 (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
283 if (*edst & 1)
284 m->m_flags |= (M_BCAST|M_MCAST);
285 type = eh->ether_type;
286 break;
287 }
288
289#if NBPFILTER > 0
290 case AF_IMPLINK:
291 {
292 fh = mtod(m, struct fddi_header *);
293 error = EPROTONOSUPPORT;
294 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
295 case FDDIFC_LLC_ASYNC: {
296 /* legal priorities are 0 through 7 */
297 if ((fh->fddi_fc & FDDIFC_Z) > 7)
298 goto bad;
299 break;
300 }
301 case FDDIFC_LLC_SYNC: {
302 /* FDDIFC_Z bits reserved, must be zero */
303 if (fh->fddi_fc & FDDIFC_Z)
304 goto bad;
305 break;
306 }
307 case FDDIFC_SMT: {
308 /* FDDIFC_Z bits must be non zero */
309 if ((fh->fddi_fc & FDDIFC_Z) == 0)
310 goto bad;
311 break;
312 }
313 default: {
314 /* anything else is too dangerous */
315 goto bad;
316 }
317 }
318 error = 0;
319 if (fh->fddi_dhost[0] & 1)
320 m->m_flags |= (M_BCAST|M_MCAST);
321 goto queue_it;
322 }
323#endif
324 default:
325 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
326 dst->sa_family);
327 senderr(EAFNOSUPPORT);
328 }
329
330
331 if (mcopy)
332 (void) looutput(ifp, mcopy, dst, rt);
333 if (type != 0) {
334 register struct llc *l;
335 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
336 if (m == 0)
337 senderr(ENOBUFS);
338 l = mtod(m, struct llc *);
339 l->llc_control = LLC_UI;
340 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
341 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
342 type = ntohs(type);
343 (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type,
344 sizeof(u_short));
345 }
346 /*
347 * Add local net header. If no space in first mbuf,
348 * allocate another.
349 */
350 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT);
351 if (m == 0)
352 senderr(ENOBUFS);
353 fh = mtod(m, struct fddi_header *);
354 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
355 (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst));
356 queue_it:
357 (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr,
358 sizeof(fh->fddi_shost));
359 s = splimp();
360 /*
361 * Queue message on interface, and start output if interface
362 * not yet active.
363 */
364 if (IF_QFULL(&ifp->if_snd)) {
365 IF_DROP(&ifp->if_snd);
366 splx(s);
367 senderr(ENOBUFS);
368 }
369 ifp->if_obytes += m->m_pkthdr.len;
370 IF_ENQUEUE(&ifp->if_snd, m);
371 if ((ifp->if_flags & IFF_OACTIVE) == 0)
372 (*ifp->if_start)(ifp);
373 splx(s);
374 if (m->m_flags & M_MCAST)
375 ifp->if_omcasts++;
376 return (error);
377
378bad:
379 if (m)
380 m_freem(m);
381 return (error);
382}
383
384/*
385 * Process a received FDDI packet;
386 * the packet is in the mbuf chain m without
387 * the fddi header, which is provided separately.
388 */
389void
390fddi_input(ifp, fh, m)
391 struct ifnet *ifp;
392 register struct fddi_header *fh;
393 struct mbuf *m;
394{
395 register struct ifqueue *inq;
396 register struct llc *l;
397 int s;
398
399 if ((ifp->if_flags & IFF_UP) == 0) {
400 m_freem(m);
401 return;
402 }
403 ifp->if_lastchange = time;
404 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh);
405 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost,
406 sizeof(fddibroadcastaddr)) == 0)
407 m->m_flags |= M_BCAST;
408 else if (fh->fddi_dhost[0] & 1)
409 m->m_flags |= M_MCAST;
410 if (m->m_flags & (M_BCAST|M_MCAST))
411 ifp->if_imcasts++;
412
413 l = mtod(m, struct llc *);
414 switch (l->llc_dsap) {
415#if defined(INET) || defined(NS) || defined(DECNET)
416 case LLC_SNAP_LSAP:
417 {
418 unsigned fddi_type;
419 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP)
420 goto dropanyway;
421 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0)
422 goto dropanyway;
423 fddi_type = ntohs(l->llc_snap.ether_type);
424 m_adj(m, 8);
425 switch (fddi_type) {
426#ifdef INET
427 case ETHERTYPE_IP:
428 schednetisr(NETISR_IP);
429 inq = &ipintrq;
430 break;
431
432 case ETHERTYPE_ARP:
433 schednetisr(NETISR_ARP);
434 inq = &arpintrq;
435 break;
436#endif
437#ifdef NS
438 case ETHERTYPE_NS:
439 schednetisr(NETISR_NS);
440 inq = &nsintrq;
441 break;
442#endif
443#ifdef DECNET
444 case ETHERTYPE_DECENT:
445 schednetisr(NETISR_DECNET);
446 inq = &decnetintrq;
447 break;
448#endif
449 default:
450 printf("fddi_input: unknown protocol 0x%x\n", fddi_type);
451 ifp->if_noproto++;
452 goto dropanyway;
453 }
454 break;
455 }
456#endif /* INET || NS */
457#ifdef ISO
458 case LLC_ISO_LSAP:
459 switch (l->llc_control) {
460 case LLC_UI:
461 /* LLC_UI_P forbidden in class 1 service */
462 if ((l->llc_dsap == LLC_ISO_LSAP) &&
463 (l->llc_ssap == LLC_ISO_LSAP)) {
464 /* LSAP for ISO */
465 m->m_data += 3; /* XXX */
466 m->m_len -= 3; /* XXX */
467 m->m_pkthdr.len -= 3; /* XXX */
468 M_PREPEND(m, sizeof *fh, M_DONTWAIT);
469 if (m == 0)
470 return;
471 *mtod(m, struct fddi_header *) = *fh;
472 IFDEBUG(D_ETHER)
473 printf("clnp packet");
474 ENDDEBUG
475 schednetisr(NETISR_ISO);
476 inq = &clnlintrq;
477 break;
478 }
479 goto dropanyway;
480
481 case LLC_XID:
482 case LLC_XID_P:
483 if(m->m_len < 6)
484 goto dropanyway;
485 l->llc_window = 0;
486 l->llc_fid = 9;
487 l->llc_class = 1;
488 l->llc_dsap = l->llc_ssap = 0;
489 /* Fall through to */
490 case LLC_TEST:
491 case LLC_TEST_P:
492 {
493 struct sockaddr sa;
494 register struct ether_header *eh2;
495 int i;
496 u_char c = l->llc_dsap;
497
498 l->llc_dsap = l->llc_ssap;
499 l->llc_ssap = c;
500 if (m->m_flags & (M_BCAST | M_MCAST))
501 bcopy((caddr_t)ac->ac_enaddr,
502 (caddr_t)eh->ether_dhost, 6);
503 sa.sa_family = AF_UNSPEC;
504 sa.sa_len = sizeof(sa);
505 eh2 = (struct ether_header *)sa.sa_data;
506 for (i = 0; i < 6; i++) {
507 eh2->ether_shost[i] = c = eh->fddi_dhost[i];
508 eh2->ether_dhost[i] =
509 eh->ether_dhost[i] = eh->fddi_shost[i];
510 eh2->ether_shost[i] = c;
511 }
512 eh2->ether_type = 0;
513 ifp->if_output(ifp, m, &sa, NULL);
514 return;
515 }
516 default:
517 m_freem(m);
518 return;
519 }
520 break;
521#endif /* ISO */
522#ifdef LLC
523 case LLC_X25_LSAP:
524 {
525 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
526 if (m == 0)
527 return;
528 if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP,
529 fh->fddi_dhost, LLC_X25_LSAP, 6,
530 mtod(m, struct sdl_hdr *)))
531 panic("ETHER cons addr failure");
532 mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr);
533#ifdef LLC_DEBUG
534 printf("llc packet\n");
535#endif /* LLC_DEBUG */
536 schednetisr(NETISR_CCITT);
537 inq = &llcintrq;
538 break;
539 }
540#endif /* LLC */
541
542 default:
543 printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap);
544 ifp->if_noproto++;
545 dropanyway:
546 m_freem(m);
547 return;
548 }
549
550 s = splimp();
551 if (IF_QFULL(inq)) {
552 IF_DROP(inq);
553 m_freem(m);
554 } else
555 IF_ENQUEUE(inq, m);
556 splx(s);
557}
558/*
559 * Perform common duties while attaching to interface list
560 */
561void
562fddi_ifattach(ifp)
563 register struct ifnet *ifp;
564{
565 register struct ifaddr *ifa;
566 register struct sockaddr_dl *sdl;
567
568 ifp->if_type = IFT_FDDI;
569 ifp->if_addrlen = 6;
570 ifp->if_hdrlen = 21;
571 ifp->if_mtu = FDDIMTU;
572 ifp->if_baudrate = 100000000;
573 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
574 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
575 sdl->sdl_family == AF_LINK) {
576 sdl->sdl_type = IFT_FDDI;
577 sdl->sdl_alen = ifp->if_addrlen;
578 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
579 LLADDR(sdl), ifp->if_addrlen);
580 break;
581 }
582}
2 * Copyright (c) 1982, 1989, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 *
33 * from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
34 * $Id: if_fddisubr.c,v 1.7 1996/04/07 17:39:04 bde Exp $
35 */
36
37#include <sys/param.h>
38#include <sys/systm.h>
39#include <sys/kernel.h>
40#include <sys/malloc.h>
41#include <sys/mbuf.h>
42#include <sys/protosw.h>
43#include <sys/socket.h>
44#include <sys/ioctl.h>
45#include <sys/errno.h>
46#include <sys/syslog.h>
47
48#include <net/if.h>
49#include <net/netisr.h>
50#include <net/route.h>
51#include <net/if_llc.h>
52#include <net/if_dl.h>
53#include <net/if_types.h>
54
55#ifdef INET
56#include <netinet/in.h>
57#include <netinet/in_var.h>
58#endif
59#include <netinet/if_ether.h>
60#include <netinet/if_fddi.h>
61
62#ifdef IPX
63#include <netipx/ipx.h>
64#include <netipx/ipx_if.h>
65#endif
66
67#ifdef NS
68#include <netns/ns.h>
69#include <netns/ns_if.h>
70#endif
71
72#ifdef DECNET
73#include <netdnet/dn.h>
74#endif
75
76#ifdef ISO
77#include <netiso/argo_debug.h>
78#include <netiso/iso.h>
79#include <netiso/iso_var.h>
80#include <netiso/iso_snpac.h>
81#endif
82
83#include "bpfilter.h"
84
85#ifdef LLC
86#include <netccitt/dll.h>
87#include <netccitt/llc_var.h>
88#endif
89
90#if defined(LLC) && defined(CCITT)
91extern struct ifqueue pkintrq;
92#endif
93
94#define senderr(e) { error = (e); goto bad;}
95
96/*
97 * This really should be defined in if_llc.h but in case it isn't.
98 */
99#ifndef llc_snap
100#define llc_snap llc_un.type_snap
101#endif
102
103#ifdef __bsdi__
104#define RTALLOC1(a, b) rtalloc1(a, b)
105#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e)
106#else
107#define RTALLOC1(a, b) rtalloc1(a, b, 0UL)
108#define ARPRESOLVE(a, b, c, d, e, f) arpresolve(a, b, c, d, e, f)
109#endif
110/*
111 * FDDI output routine.
112 * Encapsulate a packet of type family for the local net.
113 * Use trailer local net encapsulation if enough data in first
114 * packet leaves a multiple of 512 bytes of data in remainder.
115 * Assumes that ifp is actually pointer to arpcom structure.
116 */
117int
118fddi_output(ifp, m0, dst, rt0)
119 register struct ifnet *ifp;
120 struct mbuf *m0;
121 struct sockaddr *dst;
122 struct rtentry *rt0;
123{
124 short type;
125 int s, error = 0;
126 u_char edst[6];
127 register struct mbuf *m = m0;
128 register struct rtentry *rt;
129 struct mbuf *mcopy = (struct mbuf *)0;
130 register struct fddi_header *fh;
131 struct arpcom *ac = (struct arpcom *)ifp;
132
133 if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
134 senderr(ENETDOWN);
135 ifp->if_lastchange = time;
136 if (rt = rt0) {
137 if ((rt->rt_flags & RTF_UP) == 0) {
138 if (rt0 = rt = RTALLOC1(dst, 1))
139 rt->rt_refcnt--;
140 else
141 senderr(EHOSTUNREACH);
142 }
143 if (rt->rt_flags & RTF_GATEWAY) {
144 if (rt->rt_gwroute == 0)
145 goto lookup;
146 if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
147 rtfree(rt); rt = rt0;
148 lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1);
149 if ((rt = rt->rt_gwroute) == 0)
150 senderr(EHOSTUNREACH);
151 }
152 }
153 if (rt->rt_flags & RTF_REJECT)
154 if (rt->rt_rmx.rmx_expire == 0 ||
155 time.tv_sec < rt->rt_rmx.rmx_expire)
156 senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
157 }
158 switch (dst->sa_family) {
159
160#ifdef INET
161 case AF_INET:
162 if (!ARPRESOLVE(ac, rt, m, dst, edst, rt0))
163 return (0); /* if not yet resolved */
164 /* If broadcasting on a simplex interface, loopback a copy */
165 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
166 mcopy = m_copy(m, 0, (int)M_COPYALL);
167 type = ETHERTYPE_IP;
168 break;
169#endif
170#ifdef IPX
171 case AF_IPX:
172 type = ETHERTYPE_IPX;
173 bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
174 (caddr_t)edst, sizeof (edst));
175 if (!bcmp((caddr_t)edst, (caddr_t)&ipx_thishost, sizeof(edst)))
176 return (looutput(ifp, m, dst, rt));
177 /* If broadcasting on a simplex interface, loopback a copy */
178 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
179 mcopy = m_copy(m, 0, (int)M_COPYALL);
180 break;
181#endif
182#ifdef NS
183 case AF_NS:
184 type = ETHERTYPE_NS;
185 bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
186 (caddr_t)edst, sizeof (edst));
187 if (!bcmp((caddr_t)edst, (caddr_t)&ns_thishost, sizeof(edst)))
188 return (looutput(ifp, m, dst, rt));
189 /* If broadcasting on a simplex interface, loopback a copy */
190 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX))
191 mcopy = m_copy(m, 0, (int)M_COPYALL);
192 break;
193#endif
194#ifdef ISO
195 case AF_ISO: {
196 int snpalen;
197 struct llc *l;
198 register struct sockaddr_dl *sdl;
199
200 if (rt && (sdl = (struct sockaddr_dl *)rt->rt_gateway) &&
201 sdl->sdl_family == AF_LINK && sdl->sdl_alen > 0) {
202 bcopy(LLADDR(sdl), (caddr_t)edst, sizeof(edst));
203 } else if (error =
204 iso_snparesolve(ifp, (struct sockaddr_iso *)dst,
205 (char *)edst, &snpalen))
206 goto bad; /* Not Resolved */
207 /* If broadcasting on a simplex interface, loopback a copy */
208 if (*edst & 1)
209 m->m_flags |= (M_BCAST|M_MCAST);
210 if ((m->m_flags & M_BCAST) && (ifp->if_flags & IFF_SIMPLEX) &&
211 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
212 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT);
213 if (mcopy) {
214 fh = mtod(mcopy, struct fddi_header *);
215 bcopy((caddr_t)edst,
216 (caddr_t)fh->fddi_dhost, sizeof (edst));
217 bcopy((caddr_t)ac->ac_enaddr,
218 (caddr_t)fh->fddi_shost, sizeof (edst));
219 }
220 }
221 M_PREPEND(m, 3, M_DONTWAIT);
222 if (m == NULL)
223 return (0);
224 type = 0;
225 l = mtod(m, struct llc *);
226 l->llc_dsap = l->llc_ssap = LLC_ISO_LSAP;
227 l->llc_control = LLC_UI;
228 IFDEBUG(D_ETHER)
229 int i;
230 printf("unoutput: sending pkt to: ");
231 for (i=0; i<6; i++)
232 printf("%x ", edst[i] & 0xff);
233 printf("\n");
234 ENDDEBUG
235 } break;
236#endif /* ISO */
237#ifdef LLC
238/* case AF_NSAP: */
239 case AF_CCITT: {
240 register struct sockaddr_dl *sdl =
241 (struct sockaddr_dl *) rt -> rt_gateway;
242
243 if (sdl && sdl->sdl_family == AF_LINK
244 && sdl->sdl_alen > 0) {
245 bcopy(LLADDR(sdl), (char *)edst,
246 sizeof(edst));
247 } else goto bad; /* Not a link interface ? Funny ... */
248 if ((ifp->if_flags & IFF_SIMPLEX) && (*edst & 1) &&
249 (mcopy = m_copy(m, 0, (int)M_COPYALL))) {
250 M_PREPEND(mcopy, sizeof (*fh), M_DONTWAIT);
251 if (mcopy) {
252 fh = mtod(mcopy, struct fddi_header *);
253 bcopy((caddr_t)edst,
254 (caddr_t)fh->fddi_dhost, sizeof (edst));
255 bcopy((caddr_t)ac->ac_enaddr,
256 (caddr_t)fh->fddi_shost, sizeof (edst));
257 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
258 }
259 }
260 type = 0;
261#ifdef LLC_DEBUG
262 {
263 int i;
264 register struct llc *l = mtod(m, struct llc *);
265
266 printf("fddi_output: sending LLC2 pkt to: ");
267 for (i=0; i<6; i++)
268 printf("%x ", edst[i] & 0xff);
269 printf(" len 0x%x dsap 0x%x ssap 0x%x control 0x%x\n",
270 type & 0xff, l->llc_dsap & 0xff, l->llc_ssap &0xff,
271 l->llc_control & 0xff);
272
273 }
274#endif /* LLC_DEBUG */
275 } break;
276#endif /* LLC */
277
278 case AF_UNSPEC:
279 {
280 struct ether_header *eh;
281 eh = (struct ether_header *)dst->sa_data;
282 (void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
283 if (*edst & 1)
284 m->m_flags |= (M_BCAST|M_MCAST);
285 type = eh->ether_type;
286 break;
287 }
288
289#if NBPFILTER > 0
290 case AF_IMPLINK:
291 {
292 fh = mtod(m, struct fddi_header *);
293 error = EPROTONOSUPPORT;
294 switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
295 case FDDIFC_LLC_ASYNC: {
296 /* legal priorities are 0 through 7 */
297 if ((fh->fddi_fc & FDDIFC_Z) > 7)
298 goto bad;
299 break;
300 }
301 case FDDIFC_LLC_SYNC: {
302 /* FDDIFC_Z bits reserved, must be zero */
303 if (fh->fddi_fc & FDDIFC_Z)
304 goto bad;
305 break;
306 }
307 case FDDIFC_SMT: {
308 /* FDDIFC_Z bits must be non zero */
309 if ((fh->fddi_fc & FDDIFC_Z) == 0)
310 goto bad;
311 break;
312 }
313 default: {
314 /* anything else is too dangerous */
315 goto bad;
316 }
317 }
318 error = 0;
319 if (fh->fddi_dhost[0] & 1)
320 m->m_flags |= (M_BCAST|M_MCAST);
321 goto queue_it;
322 }
323#endif
324 default:
325 printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
326 dst->sa_family);
327 senderr(EAFNOSUPPORT);
328 }
329
330
331 if (mcopy)
332 (void) looutput(ifp, mcopy, dst, rt);
333 if (type != 0) {
334 register struct llc *l;
335 M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
336 if (m == 0)
337 senderr(ENOBUFS);
338 l = mtod(m, struct llc *);
339 l->llc_control = LLC_UI;
340 l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
341 l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
342 type = ntohs(type);
343 (void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type,
344 sizeof(u_short));
345 }
346 /*
347 * Add local net header. If no space in first mbuf,
348 * allocate another.
349 */
350 M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT);
351 if (m == 0)
352 senderr(ENOBUFS);
353 fh = mtod(m, struct fddi_header *);
354 fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
355 (void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst));
356 queue_it:
357 (void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr,
358 sizeof(fh->fddi_shost));
359 s = splimp();
360 /*
361 * Queue message on interface, and start output if interface
362 * not yet active.
363 */
364 if (IF_QFULL(&ifp->if_snd)) {
365 IF_DROP(&ifp->if_snd);
366 splx(s);
367 senderr(ENOBUFS);
368 }
369 ifp->if_obytes += m->m_pkthdr.len;
370 IF_ENQUEUE(&ifp->if_snd, m);
371 if ((ifp->if_flags & IFF_OACTIVE) == 0)
372 (*ifp->if_start)(ifp);
373 splx(s);
374 if (m->m_flags & M_MCAST)
375 ifp->if_omcasts++;
376 return (error);
377
378bad:
379 if (m)
380 m_freem(m);
381 return (error);
382}
383
384/*
385 * Process a received FDDI packet;
386 * the packet is in the mbuf chain m without
387 * the fddi header, which is provided separately.
388 */
389void
390fddi_input(ifp, fh, m)
391 struct ifnet *ifp;
392 register struct fddi_header *fh;
393 struct mbuf *m;
394{
395 register struct ifqueue *inq;
396 register struct llc *l;
397 int s;
398
399 if ((ifp->if_flags & IFF_UP) == 0) {
400 m_freem(m);
401 return;
402 }
403 ifp->if_lastchange = time;
404 ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh);
405 if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost,
406 sizeof(fddibroadcastaddr)) == 0)
407 m->m_flags |= M_BCAST;
408 else if (fh->fddi_dhost[0] & 1)
409 m->m_flags |= M_MCAST;
410 if (m->m_flags & (M_BCAST|M_MCAST))
411 ifp->if_imcasts++;
412
413 l = mtod(m, struct llc *);
414 switch (l->llc_dsap) {
415#if defined(INET) || defined(NS) || defined(DECNET)
416 case LLC_SNAP_LSAP:
417 {
418 unsigned fddi_type;
419 if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP)
420 goto dropanyway;
421 if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0)
422 goto dropanyway;
423 fddi_type = ntohs(l->llc_snap.ether_type);
424 m_adj(m, 8);
425 switch (fddi_type) {
426#ifdef INET
427 case ETHERTYPE_IP:
428 schednetisr(NETISR_IP);
429 inq = &ipintrq;
430 break;
431
432 case ETHERTYPE_ARP:
433 schednetisr(NETISR_ARP);
434 inq = &arpintrq;
435 break;
436#endif
437#ifdef NS
438 case ETHERTYPE_NS:
439 schednetisr(NETISR_NS);
440 inq = &nsintrq;
441 break;
442#endif
443#ifdef DECNET
444 case ETHERTYPE_DECENT:
445 schednetisr(NETISR_DECNET);
446 inq = &decnetintrq;
447 break;
448#endif
449 default:
450 printf("fddi_input: unknown protocol 0x%x\n", fddi_type);
451 ifp->if_noproto++;
452 goto dropanyway;
453 }
454 break;
455 }
456#endif /* INET || NS */
457#ifdef ISO
458 case LLC_ISO_LSAP:
459 switch (l->llc_control) {
460 case LLC_UI:
461 /* LLC_UI_P forbidden in class 1 service */
462 if ((l->llc_dsap == LLC_ISO_LSAP) &&
463 (l->llc_ssap == LLC_ISO_LSAP)) {
464 /* LSAP for ISO */
465 m->m_data += 3; /* XXX */
466 m->m_len -= 3; /* XXX */
467 m->m_pkthdr.len -= 3; /* XXX */
468 M_PREPEND(m, sizeof *fh, M_DONTWAIT);
469 if (m == 0)
470 return;
471 *mtod(m, struct fddi_header *) = *fh;
472 IFDEBUG(D_ETHER)
473 printf("clnp packet");
474 ENDDEBUG
475 schednetisr(NETISR_ISO);
476 inq = &clnlintrq;
477 break;
478 }
479 goto dropanyway;
480
481 case LLC_XID:
482 case LLC_XID_P:
483 if(m->m_len < 6)
484 goto dropanyway;
485 l->llc_window = 0;
486 l->llc_fid = 9;
487 l->llc_class = 1;
488 l->llc_dsap = l->llc_ssap = 0;
489 /* Fall through to */
490 case LLC_TEST:
491 case LLC_TEST_P:
492 {
493 struct sockaddr sa;
494 register struct ether_header *eh2;
495 int i;
496 u_char c = l->llc_dsap;
497
498 l->llc_dsap = l->llc_ssap;
499 l->llc_ssap = c;
500 if (m->m_flags & (M_BCAST | M_MCAST))
501 bcopy((caddr_t)ac->ac_enaddr,
502 (caddr_t)eh->ether_dhost, 6);
503 sa.sa_family = AF_UNSPEC;
504 sa.sa_len = sizeof(sa);
505 eh2 = (struct ether_header *)sa.sa_data;
506 for (i = 0; i < 6; i++) {
507 eh2->ether_shost[i] = c = eh->fddi_dhost[i];
508 eh2->ether_dhost[i] =
509 eh->ether_dhost[i] = eh->fddi_shost[i];
510 eh2->ether_shost[i] = c;
511 }
512 eh2->ether_type = 0;
513 ifp->if_output(ifp, m, &sa, NULL);
514 return;
515 }
516 default:
517 m_freem(m);
518 return;
519 }
520 break;
521#endif /* ISO */
522#ifdef LLC
523 case LLC_X25_LSAP:
524 {
525 M_PREPEND(m, sizeof(struct sdl_hdr) , M_DONTWAIT);
526 if (m == 0)
527 return;
528 if ( !sdl_sethdrif(ifp, fh->fddi_shost, LLC_X25_LSAP,
529 fh->fddi_dhost, LLC_X25_LSAP, 6,
530 mtod(m, struct sdl_hdr *)))
531 panic("ETHER cons addr failure");
532 mtod(m, struct sdl_hdr *)->sdlhdr_len = m->m_pkthdr.len - sizeof(struct sdl_hdr);
533#ifdef LLC_DEBUG
534 printf("llc packet\n");
535#endif /* LLC_DEBUG */
536 schednetisr(NETISR_CCITT);
537 inq = &llcintrq;
538 break;
539 }
540#endif /* LLC */
541
542 default:
543 printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap);
544 ifp->if_noproto++;
545 dropanyway:
546 m_freem(m);
547 return;
548 }
549
550 s = splimp();
551 if (IF_QFULL(inq)) {
552 IF_DROP(inq);
553 m_freem(m);
554 } else
555 IF_ENQUEUE(inq, m);
556 splx(s);
557}
558/*
559 * Perform common duties while attaching to interface list
560 */
561void
562fddi_ifattach(ifp)
563 register struct ifnet *ifp;
564{
565 register struct ifaddr *ifa;
566 register struct sockaddr_dl *sdl;
567
568 ifp->if_type = IFT_FDDI;
569 ifp->if_addrlen = 6;
570 ifp->if_hdrlen = 21;
571 ifp->if_mtu = FDDIMTU;
572 ifp->if_baudrate = 100000000;
573 for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
574 if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
575 sdl->sdl_family == AF_LINK) {
576 sdl->sdl_type = IFT_FDDI;
577 sdl->sdl_alen = ifp->if_addrlen;
578 bcopy((caddr_t)((struct arpcom *)ifp)->ac_enaddr,
579 LLADDR(sdl), ifp->if_addrlen);
580 break;
581 }
582}