if_atmsubr.c revision 46695
1/*      $NetBSD: if_atmsubr.c,v 1.10 1997/03/11 23:19:51 chuck Exp $       */
2
3/*
4 *
5 * Copyright (c) 1996 Charles D. Cranor and Washington University.
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *      This product includes software developed by Charles D. Cranor and
19 *	Washington University.
20 * 4. The name of the author may not be used to endorse or promote products
21 *    derived from this software without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 */
34
35/*
36 * if_atmsubr.c
37 */
38
39#include "opt_inet.h"
40#include "opt_natm.h"
41
42#include <sys/param.h>
43#include <sys/systm.h>
44#include <sys/mbuf.h>
45#include <sys/socket.h>
46#include <sys/sockio.h>
47#include <sys/malloc.h>
48#include <sys/errno.h>
49
50#include <net/if.h>
51#include <net/netisr.h>
52#include <net/route.h>
53#include <net/if_dl.h>
54#include <net/if_types.h>
55#include <net/if_atm.h>
56
57#include <netinet/in.h>
58#include <netinet/if_atm.h>
59#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
60#if defined(INET) || defined(INET6)
61#include <netinet/in_var.h>
62#endif
63#ifdef NATM
64#include <netnatm/natm.h>
65#endif
66
67#ifndef ETHERTYPE_IPV6
68#define ETHERTYPE_IPV6	0x86dd
69#endif
70
71#define senderr(e) { error = (e); goto bad;}
72
73/*
74 * atm_output: ATM output routine
75 *   inputs:
76 *     "ifp" = ATM interface to output to
77 *     "m0" = the packet to output
78 *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
79 *     "rt0" = the route to use
80 *   returns: error code   [0 == ok]
81 *
82 *   note: special semantic: if (dst == NULL) then we assume "m" already
83 *		has an atm_pseudohdr on it and just send it directly.
84 *		[for native mode ATM output]   if dst is null, then
85 *		rt0 must also be NULL.
86 */
87
88int
89atm_output(ifp, m0, dst, rt0)
90	register struct ifnet *ifp;
91	struct mbuf *m0;
92	struct sockaddr *dst;
93	struct rtentry *rt0;
94{
95	u_int16_t etype = 0;			/* if using LLC/SNAP */
96	int s, error = 0, sz;
97	struct atm_pseudohdr atmdst, *ad;
98	register struct mbuf *m = m0;
99	register struct rtentry *rt;
100	struct atmllc *atmllc;
101	struct atmllc *llc_hdr = NULL;
102	u_int32_t atm_flags;
103
104	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
105		senderr(ENETDOWN);
106
107	/*
108	 * check route
109	 */
110	if ((rt = rt0) != NULL) {
111
112		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
113			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
114				rt->rt_refcnt--;
115			else
116				senderr(EHOSTUNREACH);
117		}
118
119		if (rt->rt_flags & RTF_GATEWAY) {
120			if (rt->rt_gwroute == 0)
121				goto lookup;
122			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
123				rtfree(rt); rt = rt0;
124			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
125				if ((rt = rt->rt_gwroute) == 0)
126					senderr(EHOSTUNREACH);
127			}
128		}
129
130		/* XXX: put RTF_REJECT code here if doing ATMARP */
131
132	}
133
134	/*
135	 * check for non-native ATM traffic   (dst != NULL)
136	 */
137	if (dst) {
138		switch (dst->sa_family) {
139#if defined(INET) || defined(INET6)
140		case AF_INET:
141		case AF_INET6:
142			if (dst->sa_family == AF_INET6)
143			        etype = htons(ETHERTYPE_IPV6);
144			else
145			        etype = htons(ETHERTYPE_IP);
146			if (!atmresolve(rt, m, dst, &atmdst)) {
147				m = NULL;
148				/* XXX: atmresolve already free'd it */
149				senderr(EHOSTUNREACH);
150				/* XXX: put ATMARP stuff here */
151				/* XXX: watch who frees m on failure */
152			}
153			break;
154#endif /* INET || INET6 */
155
156		case AF_UNSPEC:
157			/*
158			 * XXX: bpfwrite. assuming dst contains 12 bytes
159			 * (atm pseudo header (4) + LLC/SNAP (8))
160			 */
161			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
162			llc_hdr = (struct atmllc *)(dst->sa_data + sizeof(atmdst));
163			break;
164
165		default:
166#if defined(__NetBSD__) || defined(__OpenBSD__)
167			printf("%s: can't handle af%d\n", ifp->if_xname,
168			    dst->sa_family);
169#elif defined(__FreeBSD__) || defined(__bsdi__)
170			printf("%s%d: can't handle af%d\n", ifp->if_name,
171			    ifp->if_unit, dst->sa_family);
172#endif
173			senderr(EAFNOSUPPORT);
174		}
175
176		/*
177		 * must add atm_pseudohdr to data
178		 */
179		sz = sizeof(atmdst);
180		atm_flags = ATM_PH_FLAGS(&atmdst);
181		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
182		M_PREPEND(m, sz, M_DONTWAIT);
183		if (m == 0)
184			senderr(ENOBUFS);
185		ad = mtod(m, struct atm_pseudohdr *);
186		*ad = atmdst;
187		if (atm_flags & ATM_PH_LLCSNAP) {
188			atmllc = (struct atmllc *)(ad + 1);
189			if (llc_hdr == NULL) {
190			        bcopy(ATMLLC_HDR, atmllc->llchdr,
191				      sizeof(atmllc->llchdr));
192				ATM_LLC_SETTYPE(atmllc, etype);
193					/* note: already in network order */
194			}
195			else
196			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
197		}
198	}
199
200	/*
201	 * Queue message on interface, and start output if interface
202	 * not yet active.
203	 */
204	s = splimp();
205	if (IF_QFULL(&ifp->if_snd)) {
206		IF_DROP(&ifp->if_snd);
207		splx(s);
208		senderr(ENOBUFS);
209	}
210	ifp->if_obytes += m->m_pkthdr.len;
211	IF_ENQUEUE(&ifp->if_snd, m);
212	if ((ifp->if_flags & IFF_OACTIVE) == 0)
213		(*ifp->if_start)(ifp);
214	splx(s);
215	return (error);
216
217bad:
218	if (m)
219		m_freem(m);
220	return (error);
221}
222
223/*
224 * Process a received ATM packet;
225 * the packet is in the mbuf chain m.
226 */
227void
228atm_input(ifp, ah, m, rxhand)
229	struct ifnet *ifp;
230	register struct atm_pseudohdr *ah;
231	struct mbuf *m;
232	void *rxhand;
233{
234	register struct ifqueue *inq;
235	u_int16_t etype = ETHERTYPE_IP; /* default */
236	int s;
237
238	if ((ifp->if_flags & IFF_UP) == 0) {
239		m_freem(m);
240		return;
241	}
242	ifp->if_ibytes += m->m_pkthdr.len;
243
244	if (rxhand) {
245#ifdef NATM
246		struct natmpcb *npcb = rxhand;
247		s = splimp();		/* in case 2 atm cards @ diff lvls */
248		npcb->npcb_inq++;	/* count # in queue */
249		splx(s);
250		schednetisr(NETISR_NATM);
251		inq = &natmintrq;
252		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
253#else
254		printf("atm_input: NATM detected but not configured in kernel\n");
255		m_freem(m);
256		return;
257#endif
258	} else {
259		/*
260		 * handle LLC/SNAP header, if present
261		 */
262		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
263			struct atmllc *alc;
264			if (m->m_len < sizeof(*alc) &&
265			    (m = m_pullup(m, sizeof(*alc))) == 0)
266				return; /* failed */
267			alc = mtod(m, struct atmllc *);
268			if (bcmp(alc, ATMLLC_HDR, 6)) {
269#if defined(__NetBSD__) || defined(__OpenBSD__)
270				printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
271				       ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
272#elif defined(__FreeBSD__) || defined(__bsdi__)
273				printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
274				       ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
275#endif
276				m_freem(m);
277				return;
278			}
279			etype = ATM_LLC_TYPE(alc);
280			m_adj(m, sizeof(*alc));
281		}
282
283		switch (etype) {
284#ifdef INET
285		case ETHERTYPE_IP:
286			schednetisr(NETISR_IP);
287			inq = &ipintrq;
288			break;
289#endif
290#ifdef INET6
291		case ETHERTYPE_IPV6:
292			schednetisr(NETISR_IPV6);
293			inq = &ip6intrq;
294			break;
295#endif
296		default:
297			m_freem(m);
298			return;
299		}
300	}
301
302	s = splimp();
303	if (IF_QFULL(inq)) {
304		IF_DROP(inq);
305		m_freem(m);
306	} else
307		IF_ENQUEUE(inq, m);
308	splx(s);
309}
310
311/*
312 * Perform common duties while attaching to interface list
313 */
314void
315atm_ifattach(ifp)
316	register struct ifnet *ifp;
317{
318	register struct ifaddr *ifa;
319	register struct sockaddr_dl *sdl;
320
321	ifp->if_type = IFT_ATM;
322	ifp->if_addrlen = 0;
323	ifp->if_hdrlen = 0;
324	ifp->if_mtu = ATMMTU;
325	ifp->if_output = atm_output;
326	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
327
328#if defined(__NetBSD__) || defined(__OpenBSD__)
329	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
330	    ifa = ifa->ifa_list.tqe_next)
331#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
332	for (ifa = ifp->if_addrhead.tqh_first; ifa;
333	    ifa = ifa->ifa_link.tqe_next)
334#elif defined(__FreeBSD__) || defined(__bsdi__)
335	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
336#endif
337		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
338		    sdl->sdl_family == AF_LINK) {
339			sdl->sdl_type = IFT_ATM;
340			sdl->sdl_alen = ifp->if_addrlen;
341#ifdef notyet /* if using ATMARP, store hardware address using the next line */
342			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
343#endif
344			break;
345		}
346
347}
348