if_atmsubr.c revision 117629
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 * if_atmsubr.c
35 */
36
37#include <sys/cdefs.h>
38__FBSDID("$FreeBSD: head/sys/net/if_atmsubr.c 117629 2003-07-15 10:30:57Z harti $");
39
40#include "opt_inet.h"
41#include "opt_inet6.h"
42#include "opt_mac.h"
43#include "opt_natm.h"
44
45#include <sys/param.h>
46#include <sys/systm.h>
47#include <sys/kernel.h>
48#include <sys/module.h>
49#include <sys/mac.h>
50#include <sys/mbuf.h>
51#include <sys/socket.h>
52#include <sys/sockio.h>
53#include <sys/errno.h>
54#include <sys/sysctl.h>
55
56#include <net/if.h>
57#include <net/netisr.h>
58#include <net/route.h>
59#include <net/if_dl.h>
60#include <net/if_types.h>
61#include <net/if_atm.h>
62
63#include <netinet/in.h>
64#include <netinet/if_atm.h>
65#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
66#if defined(INET) || defined(INET6)
67#include <netinet/in_var.h>
68#endif
69#ifdef NATM
70#include <netnatm/natm.h>
71#endif
72
73/*
74 * Netgraph interface functions.
75 * These need not be protected by a lock, because ng_atm nodes are persitent.
76 * The ng_atm module can be unloaded only if all ATM interfaces have been
77 * unloaded, so nobody should be in the code paths accessing these function
78 * pointers.
79 */
80void	(*ng_atm_attach_p)(struct ifnet *);
81void	(*ng_atm_detach_p)(struct ifnet *);
82int	(*ng_atm_output_p)(struct ifnet *, struct mbuf **);
83void	(*ng_atm_input_p)(struct ifnet *, struct mbuf **,
84	    struct atm_pseudohdr *, void *);
85void	(*ng_atm_input_orphan_p)(struct ifnet *, struct mbuf *,
86	    struct atm_pseudohdr *, void *);
87void	(*ng_atm_message_p)(struct ifnet *, u_int32_t, u_int32_t);
88
89/*
90 * Harp pseudo interface hooks
91 */
92void	(*atm_harp_input_p)(struct ifnet *ifp, struct mbuf **m,
93	    struct atm_pseudohdr *ah, void *rxhand);
94void	(*atm_harp_attach_p)(struct ifnet *);
95void	(*atm_harp_detach_p)(struct ifnet *);
96
97SYSCTL_NODE(_hw, OID_AUTO, atm, CTLFLAG_RW, 0, "ATM hardware");
98
99#ifndef ETHERTYPE_IPV6
100#define	ETHERTYPE_IPV6	0x86dd
101#endif
102
103#define	senderr(e) do { error = (e); goto bad; } while (0)
104
105/*
106 * atm_output: ATM output routine
107 *   inputs:
108 *     "ifp" = ATM interface to output to
109 *     "m0" = the packet to output
110 *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
111 *     "rt0" = the route to use
112 *   returns: error code   [0 == ok]
113 *
114 *   note: special semantic: if (dst == NULL) then we assume "m" already
115 *		has an atm_pseudohdr on it and just send it directly.
116 *		[for native mode ATM output]   if dst is null, then
117 *		rt0 must also be NULL.
118 */
119int
120atm_output(struct ifnet *ifp, struct mbuf *m0, struct sockaddr *dst,
121    struct rtentry *rt0)
122{
123	u_int16_t etype = 0;			/* if using LLC/SNAP */
124	int error = 0, sz;
125	struct atm_pseudohdr atmdst, *ad;
126	struct mbuf *m = m0;
127	struct rtentry *rt;
128	struct atmllc *atmllc;
129	struct atmllc *llc_hdr = NULL;
130	u_int32_t atm_flags;
131
132#ifdef MAC
133	error = mac_check_ifnet_transmit(ifp, m);
134	if (error)
135		senderr(error);
136#endif
137
138	if ((ifp->if_flags & (IFF_UP | IFF_RUNNING)) != (IFF_UP | IFF_RUNNING))
139		senderr(ENETDOWN);
140
141	/*
142	 * check route
143	 */
144	error = rt_check(&rt, &rt0, dst);
145	if (error)
146		goto bad;
147
148	/*
149	 * check for non-native ATM traffic   (dst != NULL)
150	 */
151	if (dst) {
152		switch (dst->sa_family) {
153
154#if defined(INET) || defined(INET6)
155		case AF_INET:
156		case AF_INET6:
157			if (dst->sa_family == AF_INET6)
158			        etype = ETHERTYPE_IPV6;
159			else
160			        etype = ETHERTYPE_IP;
161			if (!atmresolve(rt, m, dst, &atmdst)) {
162				m = NULL;
163				/* XXX: atmresolve already free'd it */
164				senderr(EHOSTUNREACH);
165				/* XXX: put ATMARP stuff here */
166				/* XXX: watch who frees m on failure */
167			}
168			break;
169#endif /* INET || INET6 */
170
171		case AF_UNSPEC:
172			/*
173			 * XXX: bpfwrite. assuming dst contains 12 bytes
174			 * (atm pseudo header (4) + LLC/SNAP (8))
175			 */
176			bcopy(dst->sa_data, &atmdst, sizeof(atmdst));
177			llc_hdr = (struct atmllc *)(dst->sa_data +
178			    sizeof(atmdst));
179			break;
180
181		default:
182#if defined(__NetBSD__) || defined(__OpenBSD__)
183			printf("%s: can't handle af%d\n", ifp->if_xname,
184			    dst->sa_family);
185#elif defined(__FreeBSD__) || defined(__bsdi__)
186			printf("%s%d: can't handle af%d\n", ifp->if_name,
187			    ifp->if_unit, dst->sa_family);
188#endif
189			senderr(EAFNOSUPPORT);
190		}
191
192		/*
193		 * must add atm_pseudohdr to data
194		 */
195		sz = sizeof(atmdst);
196		atm_flags = ATM_PH_FLAGS(&atmdst);
197		if (atm_flags & ATM_PH_LLCSNAP)
198			sz += 8;	/* sizeof snap == 8 */
199		M_PREPEND(m, sz, M_DONTWAIT);
200		if (m == 0)
201			senderr(ENOBUFS);
202		ad = mtod(m, struct atm_pseudohdr *);
203		*ad = atmdst;
204		if (atm_flags & ATM_PH_LLCSNAP) {
205			atmllc = (struct atmllc *)(ad + 1);
206			if (llc_hdr == NULL) {
207			        bcopy(ATMLLC_HDR, atmllc->llchdr,
208				      sizeof(atmllc->llchdr));
209				/* note: in host order */
210				ATM_LLC_SETTYPE(atmllc, etype);
211			}
212			else
213			        bcopy(llc_hdr, atmllc, sizeof(struct atmllc));
214		}
215	}
216
217	if (ng_atm_output_p != NULL) {
218		if ((error = (*ng_atm_output_p)(ifp, &m)) != 0) {
219			if (m != NULL)
220				m_freem(m);
221			return (error);
222		}
223		if (m == NULL)
224			return (0);
225	}
226
227	/*
228	 * Queue message on interface, and start output if interface
229	 * not yet active.
230	 */
231	if (!IF_HANDOFF_ADJ(&ifp->if_snd, m, ifp,
232	    -(int)sizeof(struct atm_pseudohdr)))
233		return (ENOBUFS);
234	return (error);
235
236bad:
237	if (m)
238		m_freem(m);
239	return (error);
240}
241
242/*
243 * Process a received ATM packet;
244 * the packet is in the mbuf chain m.
245 */
246void
247atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
248    void *rxhand)
249{
250	int isr;
251	u_int16_t etype = ETHERTYPE_IP;		/* default */
252	int s;
253
254	if ((ifp->if_flags & IFF_UP) == 0) {
255		m_freem(m);
256		return;
257	}
258#ifdef MAC
259	mac_create_mbuf_from_ifnet(ifp, m);
260#endif
261	ifp->if_ibytes += m->m_pkthdr.len;
262
263	if (ng_atm_input_p != NULL) {
264		(*ng_atm_input_p)(ifp, &m, ah, rxhand);
265		if (m == NULL)
266			return;
267	}
268
269	/* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */
270	if (atm_harp_input_p != NULL) {
271		(*atm_harp_input_p)(ifp, &m, ah, rxhand);
272		if (m == NULL)
273			return;
274	}
275
276	if (rxhand) {
277#ifdef NATM
278		struct natmpcb *npcb = rxhand;
279
280		s = splimp();		/* in case 2 atm cards @ diff lvls */
281		npcb->npcb_inq++;	/* count # in queue */
282		splx(s);
283		isr = NETISR_NATM;
284		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
285#else
286		printf("atm_input: NATM detected but not "
287		    "configured in kernel\n");
288		goto dropit;
289#endif
290	} else {
291		/*
292		 * handle LLC/SNAP header, if present
293		 */
294		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
295			struct atmllc *alc;
296
297			if (m->m_len < sizeof(*alc) &&
298			    (m = m_pullup(m, sizeof(*alc))) == 0)
299				return; /* failed */
300			alc = mtod(m, struct atmllc *);
301			if (bcmp(alc, ATMLLC_HDR, 6)) {
302#if defined(__NetBSD__) || defined(__OpenBSD__)
303				printf("%s: recv'd invalid LLC/SNAP frame "
304				    "[vp=%d,vc=%d]\n", ifp->if_xname,
305				    ATM_PH_VPI(ah), ATM_PH_VCI(ah));
306#elif defined(__FreeBSD__) || defined(__bsdi__)
307				printf("%s%d: recv'd invalid LLC/SNAP frame "
308				    "[vp=%d,vc=%d]\n", ifp->if_name,
309				    ifp->if_unit, ATM_PH_VPI(ah),
310				    ATM_PH_VCI(ah));
311#endif
312				m_freem(m);
313				return;
314			}
315			etype = ATM_LLC_TYPE(alc);
316			m_adj(m, sizeof(*alc));
317		}
318
319		switch (etype) {
320
321#ifdef INET
322		case ETHERTYPE_IP:
323			isr = NETISR_IP;
324			break;
325#endif
326
327#ifdef INET6
328		case ETHERTYPE_IPV6:
329			isr = NETISR_IPV6;
330			break;
331#endif
332		default:
333#ifndef NATM
334  dropit:
335#endif
336			if (ng_atm_input_orphan_p != NULL)
337				(*ng_atm_input_orphan_p)(ifp, m, ah, rxhand);
338			else
339				m_freem(m);
340			return;
341		}
342	}
343	netisr_dispatch(isr, m);
344}
345
346/*
347 * Perform common duties while attaching to interface list.
348 */
349void
350atm_ifattach(struct ifnet *ifp)
351{
352	struct ifaddr *ifa;
353	struct sockaddr_dl *sdl;
354	struct ifatm *ifatm = ifp->if_softc;
355
356	ifp->if_type = IFT_ATM;
357	ifp->if_addrlen = 0;
358	ifp->if_hdrlen = 0;
359	if_attach(ifp);
360	ifp->if_mtu = ATMMTU;
361	ifp->if_output = atm_output;
362#if 0
363	ifp->if_input = atm_input;
364#endif
365	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
366
367#if defined(__NetBSD__) || defined(__OpenBSD__)
368	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
369#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
370	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
371	    ifa = TAILQ_NEXT(ifa, ifa_link))
372#elif defined(__FreeBSD__) || defined(__bsdi__)
373	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
374#endif
375		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
376		    sdl->sdl_family == AF_LINK) {
377			sdl->sdl_type = IFT_ATM;
378			sdl->sdl_alen = ifp->if_addrlen;
379#ifdef notyet /* if using ATMARP, store hardware address using the next line */
380			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
381#endif
382			break;
383		}
384
385	ifp->if_linkmib = &ifatm->mib;
386	ifp->if_linkmiblen = sizeof(ifatm->mib);
387
388	if(ng_atm_attach_p)
389		(*ng_atm_attach_p)(ifp);
390	if (atm_harp_attach_p)
391		(*atm_harp_attach_p)(ifp);
392}
393
394/*
395 * Common stuff for detaching an ATM interface
396 */
397void
398atm_ifdetach(struct ifnet *ifp)
399{
400	if (atm_harp_detach_p)
401		(*atm_harp_detach_p)(ifp);
402	if(ng_atm_detach_p)
403		(*ng_atm_detach_p)(ifp);
404	if_detach(ifp);
405}
406
407static moduledata_t atm_mod = {
408        "atm",
409        NULL,
410        0
411};
412
413DECLARE_MODULE(atm, atm_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
414MODULE_VERSION(atm, 1);
415