if_atmsubr.c revision 116741
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 116741 2003-06-23 16:53:28Z 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(&ifp->if_snd, m, ifp))
232		return (ENOBUFS);
233	return (error);
234
235bad:
236	if (m)
237		m_freem(m);
238	return (error);
239}
240
241/*
242 * Process a received ATM packet;
243 * the packet is in the mbuf chain m.
244 */
245void
246atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
247    void *rxhand)
248{
249	int isr;
250	u_int16_t etype = ETHERTYPE_IP;		/* default */
251	int s;
252
253	if ((ifp->if_flags & IFF_UP) == 0) {
254		m_freem(m);
255		return;
256	}
257#ifdef MAC
258	mac_create_mbuf_from_ifnet(ifp, m);
259#endif
260	ifp->if_ibytes += m->m_pkthdr.len;
261
262	if (ng_atm_input_p != NULL) {
263		(*ng_atm_input_p)(ifp, &m, ah, rxhand);
264		if (m == NULL)
265			return;
266	}
267
268	/* not eaten by ng_atm. Maybe it's a pseudo-harp PDU? */
269	if (atm_harp_input_p != NULL) {
270		(*atm_harp_input_p)(ifp, &m, ah, rxhand);
271		if (m == NULL)
272			return;
273	}
274
275	if (rxhand) {
276#ifdef NATM
277		struct natmpcb *npcb = rxhand;
278
279		s = splimp();		/* in case 2 atm cards @ diff lvls */
280		npcb->npcb_inq++;	/* count # in queue */
281		splx(s);
282		isr = NETISR_NATM;
283		m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
284#else
285		printf("atm_input: NATM detected but not "
286		    "configured in kernel\n");
287		goto dropit;
288#endif
289	} else {
290		/*
291		 * handle LLC/SNAP header, if present
292		 */
293		if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
294			struct atmllc *alc;
295
296			if (m->m_len < sizeof(*alc) &&
297			    (m = m_pullup(m, sizeof(*alc))) == 0)
298				return; /* failed */
299			alc = mtod(m, struct atmllc *);
300			if (bcmp(alc, ATMLLC_HDR, 6)) {
301#if defined(__NetBSD__) || defined(__OpenBSD__)
302				printf("%s: recv'd invalid LLC/SNAP frame "
303				    "[vp=%d,vc=%d]\n", ifp->if_xname,
304				    ATM_PH_VPI(ah), ATM_PH_VCI(ah));
305#elif defined(__FreeBSD__) || defined(__bsdi__)
306				printf("%s%d: recv'd invalid LLC/SNAP frame "
307				    "[vp=%d,vc=%d]\n", ifp->if_name,
308				    ifp->if_unit, ATM_PH_VPI(ah),
309				    ATM_PH_VCI(ah));
310#endif
311				m_freem(m);
312				return;
313			}
314			etype = ATM_LLC_TYPE(alc);
315			m_adj(m, sizeof(*alc));
316		}
317
318		switch (etype) {
319
320#ifdef INET
321		case ETHERTYPE_IP:
322			isr = NETISR_IP;
323			break;
324#endif
325
326#ifdef INET6
327		case ETHERTYPE_IPV6:
328			isr = NETISR_IPV6;
329			break;
330#endif
331		default:
332#ifndef NATM
333  dropit:
334#endif
335			if (ng_atm_input_orphan_p != NULL)
336				(*ng_atm_input_orphan_p)(ifp, m, ah, rxhand);
337			else
338				m_freem(m);
339			return;
340		}
341	}
342	netisr_dispatch(isr, m);
343}
344
345/*
346 * Perform common duties while attaching to interface list.
347 */
348void
349atm_ifattach(struct ifnet *ifp)
350{
351	struct ifaddr *ifa;
352	struct sockaddr_dl *sdl;
353	struct ifatm *ifatm = ifp->if_softc;
354
355	ifp->if_type = IFT_ATM;
356	ifp->if_addrlen = 0;
357	ifp->if_hdrlen = 0;
358	if_attach(ifp);
359	ifp->if_mtu = ATMMTU;
360	ifp->if_output = atm_output;
361#if 0
362	ifp->if_input = atm_input;
363#endif
364	ifp->if_snd.ifq_maxlen = 50;	/* dummy */
365
366#if defined(__NetBSD__) || defined(__OpenBSD__)
367	TAILQ_FOREACH(ifa, &ifp->if_addrlist, ifa_list)
368#elif defined(__FreeBSD__) && (__FreeBSD__ > 2)
369	for (ifa = TAILQ_FIRST(&ifp->if_addrhead); ifa;
370	    ifa = TAILQ_NEXT(ifa, ifa_link))
371#elif defined(__FreeBSD__) || defined(__bsdi__)
372	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
373#endif
374		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
375		    sdl->sdl_family == AF_LINK) {
376			sdl->sdl_type = IFT_ATM;
377			sdl->sdl_alen = ifp->if_addrlen;
378#ifdef notyet /* if using ATMARP, store hardware address using the next line */
379			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
380#endif
381			break;
382		}
383
384	ifp->if_linkmib = &ifatm->mib;
385	ifp->if_linkmiblen = sizeof(ifatm->mib);
386
387	if(ng_atm_attach_p)
388		(*ng_atm_attach_p)(ifp);
389	if (atm_harp_attach_p)
390		(*atm_harp_attach_p)(ifp);
391}
392
393/*
394 * Common stuff for detaching an ATM interface
395 */
396void
397atm_ifdetach(struct ifnet *ifp)
398{
399	if (atm_harp_detach_p)
400		(*atm_harp_detach_p)(ifp);
401	if(ng_atm_detach_p)
402		(*ng_atm_detach_p)(ifp);
403	if_detach(ifp);
404}
405
406static moduledata_t atm_mod = {
407        "atm",
408        NULL,
409        0
410};
411
412DECLARE_MODULE(atm, atm_mod, SI_SUB_PSEUDO, SI_ORDER_ANY);
413MODULE_VERSION(atm, 1);
414