if_fddisubr.c revision 93368
1/*
2 * Copyright (c) 1995, 1996
3 *	Matt Thomas <matt@3am-software.com>.  All rights reserved.
4 * Copyright (c) 1982, 1989, 1993
5 *	The Regents of the University of California.  All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 *    must display the following acknowledgement:
17 *	This product includes software developed by the University of
18 *	California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 *    may be used to endorse or promote products derived from this software
21 *    without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 *
35 *	from: if_ethersubr.c,v 1.5 1994/12/13 22:31:45 wollman Exp
36 * $FreeBSD: head/sys/net/if_fddisubr.c 93368 2002-03-29 07:30:22Z mdodd $
37 */
38
39#include "opt_atalk.h"
40#include "opt_inet.h"
41#include "opt_inet6.h"
42#include "opt_ipx.h"
43
44#include <sys/param.h>
45#include <sys/systm.h>
46#include <sys/mbuf.h>
47#include <sys/socket.h>
48#include <sys/malloc.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#if defined(INET) || defined(INET6)
58#include <netinet/in.h>
59#include <netinet/in_var.h>
60#include <netinet/if_ether.h>
61#endif
62#ifdef INET6
63#include <netinet6/nd6.h>
64#endif
65#include <netinet/if_fddi.h>
66
67#ifdef IPX
68#include <netipx/ipx.h>
69#include <netipx/ipx_if.h>
70#endif
71
72#ifdef NS
73#include <netns/ns.h>
74#include <netns/ns_if.h>
75#endif
76
77#ifdef DECNET
78#include <netdnet/dn.h>
79#endif
80
81#ifdef NETATALK
82#include <netatalk/at.h>
83#include <netatalk/at_var.h>
84#include <netatalk/at_extern.h>
85
86#define llc_snap_org_code llc_un.type_snap.org_code
87#define llc_snap_ether_type llc_un.type_snap.ether_type
88
89extern u_char	at_org_code[ 3 ];
90extern u_char	aarp_org_code[ 3 ];
91#endif /* NETATALK */
92
93static	int fddi_resolvemulti(struct ifnet *, struct sockaddr **,
94			      struct sockaddr *);
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#define	RTALLOC1(a, b)			rtalloc1(a, b, 0UL)
106#define	ARPRESOLVE(a, b, c, d, e, f)	arpresolve(a, b, c, d, e, f)
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, m, dst, rt0)
116	struct ifnet *ifp;
117	struct mbuf *m;
118	struct sockaddr *dst;
119	struct rtentry *rt0;
120{
121	u_int16_t type;
122	int loop_copy = 0, error = 0, hdrcmplt = 0;
123 	u_char esrc[6], edst[6];
124	struct rtentry *rt;
125	struct fddi_header *fh;
126	struct arpcom *ac = (struct arpcom *)ifp;
127
128	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
129		senderr(ENETDOWN);
130	getmicrotime(&ifp->if_lastchange);
131	if ((rt = rt0) != NULL) {
132		if ((rt->rt_flags & RTF_UP) == 0) {
133			if ((rt0 = rt = RTALLOC1(dst, 1)) != NULL)
134				rt->rt_refcnt--;
135			else
136				senderr(EHOSTUNREACH);
137		}
138		if (rt->rt_flags & RTF_GATEWAY) {
139			if (rt->rt_gwroute == 0)
140				goto lookup;
141			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
142				rtfree(rt); rt = rt0;
143			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 1);
144				if ((rt = rt->rt_gwroute) == 0)
145					senderr(EHOSTUNREACH);
146			}
147		}
148		if (rt->rt_flags & RTF_REJECT)
149			if (rt->rt_rmx.rmx_expire == 0 ||
150			    time_second < rt->rt_rmx.rmx_expire)
151				senderr(rt == rt0 ? EHOSTDOWN : EHOSTUNREACH);
152	}
153	switch (dst->sa_family) {
154
155#ifdef INET
156	case AF_INET: {
157		if (!ARPRESOLVE(ifp, rt, m, dst, edst, rt0))
158			return (0);	/* if not yet resolved */
159		type = htons(ETHERTYPE_IP);
160		break;
161	}
162#endif
163#ifdef INET6
164	case AF_INET6:
165		if (!nd6_storelladdr(&ac->ac_if, rt, m, dst, (u_char *)edst)) {
166			/* Something bad happened */
167			return(0);
168		}
169		type = htons(ETHERTYPE_IPV6);
170		break;
171#endif
172#ifdef IPX
173	case AF_IPX:
174		type = htons(ETHERTYPE_IPX);
175 		bcopy((caddr_t)&(((struct sockaddr_ipx *)dst)->sipx_addr.x_host),
176		    (caddr_t)edst, sizeof (edst));
177		break;
178#endif
179#ifdef NETATALK
180	case AF_APPLETALK: {
181	    struct at_ifaddr *aa;
182            if (!aarpresolve(ac, m, (struct sockaddr_at *)dst, edst))
183                return (0);
184	    /*
185	     * ifaddr is the first thing in at_ifaddr
186	     */
187	    if ((aa = at_ifawithnet( (struct sockaddr_at *)dst)) == 0)
188		goto bad;
189
190	    /*
191	     * In the phase 2 case, we need to prepend an mbuf for the llc header.
192	     * Since we must preserve the value of m, which is passed to us by
193	     * value, we m_copy() the first mbuf, and use it for our llc header.
194	     */
195	    if (aa->aa_flags & AFA_PHASE2) {
196		struct llc llc;
197
198		M_PREPEND(m, sizeof(struct llc), M_TRYWAIT);
199		if (m == 0)
200			senderr(ENOBUFS);
201		llc.llc_dsap = llc.llc_ssap = LLC_SNAP_LSAP;
202		llc.llc_control = LLC_UI;
203		bcopy(at_org_code, llc.llc_snap_org_code, sizeof(at_org_code));
204		llc.llc_snap_ether_type = htons(ETHERTYPE_AT);
205		bcopy(&llc, mtod(m, caddr_t), sizeof(struct llc));
206		type = 0;
207	    } else {
208		type = htons(ETHERTYPE_AT);
209	    }
210	    break;
211	}
212#endif /* NETATALK */
213#ifdef NS
214	case AF_NS:
215		type = htons(ETHERTYPE_NS);
216 		bcopy((caddr_t)&(((struct sockaddr_ns *)dst)->sns_addr.x_host),
217		    (caddr_t)edst, sizeof (edst));
218		break;
219#endif
220
221	case pseudo_AF_HDRCMPLT:
222	{
223		struct ether_header *eh;
224		hdrcmplt = 1;
225		eh = (struct ether_header *)dst->sa_data;
226 		(void)memcpy((caddr_t)esrc, (caddr_t)eh->ether_shost, sizeof (esrc));
227		/* FALLTHROUGH */
228	}
229
230	case AF_UNSPEC:
231	{
232		struct ether_header *eh;
233		loop_copy = -1;
234		eh = (struct ether_header *)dst->sa_data;
235 		(void)memcpy((caddr_t)edst, (caddr_t)eh->ether_dhost, sizeof (edst));
236		if (*edst & 1)
237			m->m_flags |= (M_BCAST|M_MCAST);
238		type = eh->ether_type;
239		break;
240	}
241
242	case AF_IMPLINK:
243	{
244		fh = mtod(m, struct fddi_header *);
245		error = EPROTONOSUPPORT;
246		switch (fh->fddi_fc & (FDDIFC_C|FDDIFC_L|FDDIFC_F)) {
247			case FDDIFC_LLC_ASYNC: {
248				/* legal priorities are 0 through 7 */
249				if ((fh->fddi_fc & FDDIFC_Z) > 7)
250			        	goto bad;
251				break;
252			}
253			case FDDIFC_LLC_SYNC: {
254				/* FDDIFC_Z bits reserved, must be zero */
255				if (fh->fddi_fc & FDDIFC_Z)
256					goto bad;
257				break;
258			}
259			case FDDIFC_SMT: {
260				/* FDDIFC_Z bits must be non zero */
261				if ((fh->fddi_fc & FDDIFC_Z) == 0)
262					goto bad;
263				break;
264			}
265			default: {
266				/* anything else is too dangerous */
267               	 		goto bad;
268			}
269		}
270		error = 0;
271		if (fh->fddi_dhost[0] & 1)
272			m->m_flags |= (M_BCAST|M_MCAST);
273		goto queue_it;
274	}
275	default:
276		printf("%s%d: can't handle af%d\n", ifp->if_name, ifp->if_unit,
277			dst->sa_family);
278		senderr(EAFNOSUPPORT);
279	}
280
281	if (type != 0) {
282		struct llc *l;
283		M_PREPEND(m, sizeof (struct llc), M_DONTWAIT);
284		if (m == 0)
285			senderr(ENOBUFS);
286		l = mtod(m, struct llc *);
287		l->llc_control = LLC_UI;
288		l->llc_dsap = l->llc_ssap = LLC_SNAP_LSAP;
289		l->llc_snap.org_code[0] = l->llc_snap.org_code[1] = l->llc_snap.org_code[2] = 0;
290		(void)memcpy((caddr_t) &l->llc_snap.ether_type, (caddr_t) &type,
291			sizeof(u_int16_t));
292	}
293
294	/*
295	 * Add local net header.  If no space in first mbuf,
296	 * allocate another.
297	 */
298	M_PREPEND(m, sizeof (struct fddi_header), M_DONTWAIT);
299	if (m == 0)
300		senderr(ENOBUFS);
301	fh = mtod(m, struct fddi_header *);
302	fh->fddi_fc = FDDIFC_LLC_ASYNC|FDDIFC_LLC_PRIO4;
303 	(void)memcpy((caddr_t)fh->fddi_dhost, (caddr_t)edst, sizeof (edst));
304  queue_it:
305	if (hdrcmplt)
306		(void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)esrc,
307			sizeof(fh->fddi_shost));
308	else
309		(void)memcpy((caddr_t)fh->fddi_shost, (caddr_t)ac->ac_enaddr,
310			sizeof(fh->fddi_shost));
311	/*
312	 * If a simplex interface, and the packet is being sent to our
313	 * Ethernet address or a broadcast address, loopback a copy.
314	 * XXX To make a simplex device behave exactly like a duplex
315	 * device, we should copy in the case of sending to our own
316	 * ethernet address (thus letting the original actually appear
317	 * on the wire). However, we don't do that here for security
318	 * reasons and compatibility with the original behavior.
319	 */
320	if ((ifp->if_flags & IFF_SIMPLEX) &&
321	   (loop_copy != -1)) {
322		if ((m->m_flags & M_BCAST) || loop_copy) {
323			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
324
325			(void) if_simloop(ifp,
326				n, dst->sa_family, sizeof(struct fddi_header));
327	     	} else if (bcmp(fh->fddi_dhost,
328		    fh->fddi_shost, sizeof(fh->fddi_shost)) == 0) {
329			(void) if_simloop(ifp,
330				m, dst->sa_family, sizeof(struct fddi_header));
331			return(0);	/* XXX */
332		}
333	}
334
335	if (! IF_HANDOFF(&ifp->if_snd, m, ifp))
336		senderr(ENOBUFS);
337	return (error);
338
339bad:
340	if (m)
341		m_freem(m);
342	return (error);
343}
344
345/*
346 * Process a received FDDI packet;
347 * the packet is in the mbuf chain m without
348 * the fddi header, which is provided separately.
349 */
350void
351fddi_input(ifp, fh, m)
352	struct ifnet *ifp;
353	struct fddi_header *fh;
354	struct mbuf *m;
355{
356	struct ifqueue *inq;
357	struct llc *l;
358
359	if ((ifp->if_flags & IFF_UP) == 0) {
360		m_freem(m);
361		return;
362	}
363	getmicrotime(&ifp->if_lastchange);
364	ifp->if_ibytes += m->m_pkthdr.len + sizeof (*fh);
365	if (fh->fddi_dhost[0] & 1) {
366		if (bcmp((caddr_t)fddibroadcastaddr, (caddr_t)fh->fddi_dhost,
367		    sizeof(fddibroadcastaddr)) == 0)
368			m->m_flags |= M_BCAST;
369		else
370			m->m_flags |= M_MCAST;
371		ifp->if_imcasts++;
372	} else if ((ifp->if_flags & IFF_PROMISC)
373	    && bcmp(((struct arpcom *)ifp)->ac_enaddr, (caddr_t)fh->fddi_dhost,
374		    sizeof(fh->fddi_dhost)) != 0) {
375		m_freem(m);
376		return;
377	}
378
379#ifdef M_LINK0
380	/*
381	 * If this has a LLC priority of 0, then mark it so upper
382	 * layers have a hint that it really came via a FDDI/Ethernet
383	 * bridge.
384	 */
385	if ((fh->fddi_fc & FDDIFC_LLC_PRIO7) == FDDIFC_LLC_PRIO0)
386		m->m_flags |= M_LINK0;
387#endif
388
389	l = mtod(m, struct llc *);
390	switch (l->llc_dsap) {
391#if defined(INET) || defined(INET6) || defined(NS) || defined(DECNET) || defined(IPX) || defined(NETATALK)
392	case LLC_SNAP_LSAP:
393	{
394		u_int16_t type;
395		if (l->llc_control != LLC_UI || l->llc_ssap != LLC_SNAP_LSAP)
396			goto dropanyway;
397#ifdef NETATALK
398		if (Bcmp(&(l->llc_snap_org_code)[0], at_org_code,
399			 sizeof(at_org_code)) == 0 &&
400		 	ntohs(l->llc_snap_ether_type) == ETHERTYPE_AT) {
401		    inq = &atintrq2;
402		    m_adj( m, sizeof( struct llc ));
403		    schednetisr(NETISR_ATALK);
404		    break;
405		}
406
407		if (Bcmp(&(l->llc_snap_org_code)[0], aarp_org_code,
408			 sizeof(aarp_org_code)) == 0 &&
409			ntohs(l->llc_snap_ether_type) == ETHERTYPE_AARP) {
410		    m_adj( m, sizeof( struct llc ));
411		    aarpinput((struct arpcom *)ifp, m); /* XXX */
412		    return;
413		}
414#endif /* NETATALK */
415		if (l->llc_snap.org_code[0] != 0 || l->llc_snap.org_code[1] != 0|| l->llc_snap.org_code[2] != 0)
416			goto dropanyway;
417		type = ntohs(l->llc_snap.ether_type);
418		m_adj(m, 8);
419		switch (type) {
420#ifdef INET
421		case ETHERTYPE_IP:
422			if (ipflow_fastforward(m))
423				return;
424			schednetisr(NETISR_IP);
425			inq = &ipintrq;
426			break;
427
428		case ETHERTYPE_ARP:
429			if (ifp->if_flags & IFF_NOARP)
430				goto dropanyway;
431			schednetisr(NETISR_ARP);
432			inq = &arpintrq;
433			break;
434#endif
435#ifdef INET6
436		case ETHERTYPE_IPV6:
437			schednetisr(NETISR_IPV6);
438			inq = &ip6intrq;
439			break;
440#endif
441#ifdef IPX
442		case ETHERTYPE_IPX:
443			schednetisr(NETISR_IPX);
444			inq = &ipxintrq;
445			break;
446#endif
447#ifdef NS
448		case ETHERTYPE_NS:
449			schednetisr(NETISR_NS);
450			inq = &nsintrq;
451			break;
452#endif
453#ifdef DECNET
454		case ETHERTYPE_DECNET:
455			schednetisr(NETISR_DECNET);
456			inq = &decnetintrq;
457			break;
458#endif
459#ifdef NETATALK
460		case ETHERTYPE_AT:
461	                schednetisr(NETISR_ATALK);
462			inq = &atintrq1;
463			break;
464	        case ETHERTYPE_AARP:
465			/* probably this should be done with a NETISR as well */
466			aarpinput((struct arpcom *)ifp, m); /* XXX */
467			return;
468#endif /* NETATALK */
469		default:
470			/* printf("fddi_input: unknown protocol 0x%x\n", type); */
471			ifp->if_noproto++;
472			goto dropanyway;
473		}
474		break;
475	}
476#endif /* INET || NS */
477
478	default:
479		/* printf("fddi_input: unknown dsap 0x%x\n", l->llc_dsap); */
480		ifp->if_noproto++;
481	dropanyway:
482		m_freem(m);
483		return;
484	}
485
486	(void) IF_HANDOFF(inq, m, NULL);
487}
488/*
489 * Perform common duties while attaching to interface list
490 */
491
492void
493fddi_ifattach(ifp)
494	struct ifnet *ifp;
495{
496	struct ifaddr *ifa;
497	struct sockaddr_dl *sdl;
498
499	ifp->if_type = IFT_FDDI;
500	ifp->if_addrlen = 6;
501	ifp->if_hdrlen = 21;
502	ifp->if_mtu = FDDIMTU;
503	ifp->if_resolvemulti = fddi_resolvemulti;
504	ifp->if_baudrate = 100000000;
505#ifdef IFF_NOTRAILERS
506	ifp->if_flags |= IFF_NOTRAILERS;
507#endif
508	ifp->if_broadcastaddr = fddibroadcastaddr;
509	ifa = ifaddr_byindex(ifp->if_index);
510	sdl = (struct sockaddr_dl *)ifa->ifa_addr;
511	sdl->sdl_type = IFT_FDDI;
512	sdl->sdl_alen = ifp->if_addrlen;
513	bcopy(((struct arpcom *)ifp)->ac_enaddr, LLADDR(sdl), ifp->if_addrlen);
514}
515
516static int
517fddi_resolvemulti(ifp, llsa, sa)
518	struct ifnet *ifp;
519	struct sockaddr **llsa;
520	struct sockaddr *sa;
521{
522	struct sockaddr_dl *sdl;
523	struct sockaddr_in *sin;
524#ifdef INET6
525	struct sockaddr_in6 *sin6;
526#endif
527	u_char *e_addr;
528
529	switch(sa->sa_family) {
530	case AF_LINK:
531		/*
532		 * No mapping needed. Just check that it's a valid MC address.
533		 */
534		sdl = (struct sockaddr_dl *)sa;
535		e_addr = LLADDR(sdl);
536		if ((e_addr[0] & 1) != 1)
537			return EADDRNOTAVAIL;
538		*llsa = 0;
539		return 0;
540
541#ifdef INET
542	case AF_INET:
543		sin = (struct sockaddr_in *)sa;
544		if (!IN_MULTICAST(ntohl(sin->sin_addr.s_addr)))
545			return EADDRNOTAVAIL;
546		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
547		       M_WAITOK);
548		sdl->sdl_len = sizeof *sdl;
549		sdl->sdl_family = AF_LINK;
550		sdl->sdl_index = ifp->if_index;
551		sdl->sdl_type = IFT_FDDI;
552		sdl->sdl_nlen = 0;
553		sdl->sdl_alen = ETHER_ADDR_LEN;	/* XXX */
554		sdl->sdl_slen = 0;
555		e_addr = LLADDR(sdl);
556		ETHER_MAP_IP_MULTICAST(&sin->sin_addr, e_addr);
557		*llsa = (struct sockaddr *)sdl;
558		return 0;
559#endif
560#ifdef INET6
561	case AF_INET6:
562		sin6 = (struct sockaddr_in6 *)sa;
563		if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) {
564			/*
565			 * An IP6 address of 0 means listen to all
566			 * of the Ethernet multicast address used for IP6.
567			 * (This is used for multicast routers.)
568			 */
569			ifp->if_flags |= IFF_ALLMULTI;
570			*llsa = 0;
571			return 0;
572		}
573		if (!IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr))
574			return EADDRNOTAVAIL;
575		MALLOC(sdl, struct sockaddr_dl *, sizeof *sdl, M_IFMADDR,
576		       M_WAITOK);
577		sdl->sdl_len = sizeof *sdl;
578		sdl->sdl_family = AF_LINK;
579		sdl->sdl_index = ifp->if_index;
580		sdl->sdl_type = IFT_FDDI;
581		sdl->sdl_nlen = 0;
582		sdl->sdl_alen = ETHER_ADDR_LEN;	/* XXX */
583		sdl->sdl_slen = 0;
584		e_addr = LLADDR(sdl);
585		ETHER_MAP_IPV6_MULTICAST(&sin6->sin6_addr, e_addr);
586		*llsa = (struct sockaddr *)sdl;
587		return 0;
588#endif
589
590	default:
591		/*
592		 * Well, the text isn't quite right, but it's the name
593		 * that counts...
594		 */
595		return EAFNOSUPPORT;
596	}
597}
598