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