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