if_atmsubr.c revision 32350
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
41#include <sys/param.h>
42#include <sys/systm.h>
43#include <sys/mbuf.h>
44#include <sys/socket.h>
45
46#include <net/if.h>
47#include <net/netisr.h>
48#include <net/route.h>
49#include <net/if_dl.h>
50#include <net/if_types.h>
51#include <net/if_atm.h>
52
53#include <netinet/in.h>
54#include <netinet/if_atm.h>
55#include <netinet/if_ether.h> /* XXX: for ETHERTYPE_* */
56#ifdef INET
57#include <netinet/in_var.h>
58#endif
59#ifdef NATM
60#include <netnatm/natm.h>
61#endif
62
63#include "bpfilter.h"
64#if NBPFILTER > 0
65/*
66 * bpf support.
67 * the code is derived from if_loop.c.
68 * bpf support should belong to the driver but it's easier to implement
69 * it here since we can call bpf_mtap before atm_output adds a pseudo
70 * header to the mbuf.
71 *			--kjc
72 */
73#include <net/bpf.h>
74#endif /* NBPFILTER > 0 */
75
76#define senderr(e) { error = (e); goto bad;}
77
78/*
79 * atm_output: ATM output routine
80 *   inputs:
81 *     "ifp" = ATM interface to output to
82 *     "m0" = the packet to output
83 *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
84 *     "rt0" = the route to use
85 *   returns: error code   [0 == ok]
86 *
87 *   note: special semantic: if (dst == NULL) then we assume "m" already
88 *		has an atm_pseudohdr on it and just send it directly.
89 *		[for native mode ATM output]   if dst is null, then
90 *		rt0 must also be NULL.
91 */
92
93int
94atm_output(ifp, m0, dst, rt0)
95	register struct ifnet *ifp;
96	struct mbuf *m0;
97	struct sockaddr *dst;
98	struct rtentry *rt0;
99{
100	u_int16_t etype = 0;			/* if using LLC/SNAP */
101	int s, error = 0, sz;
102	struct atm_pseudohdr atmdst, *ad;
103	register struct mbuf *m = m0;
104	register struct rtentry *rt;
105	struct atmllc *atmllc;
106	u_int32_t atm_flags;
107
108	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
109		senderr(ENETDOWN);
110	gettime(&ifp->if_lastchange);
111
112	/*
113	 * check route
114	 */
115	if ((rt = rt0) != NULL) {
116
117		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
118			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
119				rt->rt_refcnt--;
120			else
121				senderr(EHOSTUNREACH);
122		}
123
124		if (rt->rt_flags & RTF_GATEWAY) {
125			if (rt->rt_gwroute == 0)
126				goto lookup;
127			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
128				rtfree(rt); rt = rt0;
129			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
130				if ((rt = rt->rt_gwroute) == 0)
131					senderr(EHOSTUNREACH);
132			}
133		}
134
135		/* XXX: put RTF_REJECT code here if doing ATMARP */
136
137	}
138
139	/*
140	 * check for non-native ATM traffic   (dst != NULL)
141	 */
142	if (dst) {
143		switch (dst->sa_family) {
144#ifdef INET
145		case AF_INET:
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			etype = htons(ETHERTYPE_IP);
154			break;
155#endif
156
157		default:
158#if defined(__NetBSD__) || defined(__OpenBSD__)
159			printf("%s: can't handle af%d\n", ifp->if_xname,
160			    dst->sa_family);
161#elif defined(__FreeBSD__) || defined(__bsdi__)
162			printf("%s%d: can't handle af%d\n", ifp->if_name,
163			    ifp->if_unit, dst->sa_family);
164#endif
165			senderr(EAFNOSUPPORT);
166		}
167
168#if NBPFILTER > 0
169		/* BPF write needs to be handled specially */
170		if (dst && dst->sa_family == AF_UNSPEC) {
171		    dst->sa_family = *(mtod(m, int *));
172		    m->m_len -= sizeof(int);
173		    m->m_pkthdr.len -= sizeof(int);
174		    m->m_data += sizeof(int);
175		}
176
177		if (ifp->if_bpf) {
178		    /*
179		     * We need to prepend the address family as
180		     * a four byte field.  Cons up a dummy header
181		     * to pacify bpf.  This is safe because bpf
182		     * will only read from the mbuf (i.e., it won't
183		     * try to free it or keep a pointer a to it).
184		     */
185		    struct mbuf m1;
186		    u_int af = dst->sa_family;
187
188		    m1.m_next = m;
189		    m1.m_len = 4;
190		    m1.m_data = (char *)&af;
191
192		    s = splimp();
193#if defined(__NetBSD__) || defined(__OpenBSD__)
194		bpf_mtap(&ifp->if_bpf, &m0);
195#elif defined(__FreeBSD__)
196		    bpf_mtap(ifp, &m1);
197#endif
198		    splx(s);
199		}
200#endif /* NBPFILTER > 0 */
201
202		/*
203		 * must add atm_pseudohdr to data
204		 */
205		sz = sizeof(atmdst);
206		atm_flags = ATM_PH_FLAGS(&atmdst);
207		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
208		M_PREPEND(m, sz, M_DONTWAIT);
209		if (m == 0)
210			senderr(ENOBUFS);
211		ad = mtod(m, struct atm_pseudohdr *);
212		*ad = atmdst;
213		if (atm_flags & ATM_PH_LLCSNAP) {
214			atmllc = (struct atmllc *)(ad + 1);
215			bcopy(ATMLLC_HDR, atmllc->llchdr,
216						sizeof(atmllc->llchdr));
217			ATM_LLC_SETTYPE(atmllc, etype);
218					/* note: already in network order */
219		}
220	}
221
222	/*
223	 * Queue message on interface, and start output if interface
224	 * not yet active.
225	 */
226
227	s = splimp();
228	if (IF_QFULL(&ifp->if_snd)) {
229		IF_DROP(&ifp->if_snd);
230		splx(s);
231		senderr(ENOBUFS);
232	}
233	ifp->if_obytes += m->m_pkthdr.len;
234	IF_ENQUEUE(&ifp->if_snd, m);
235	if ((ifp->if_flags & IFF_OACTIVE) == 0)
236		(*ifp->if_start)(ifp);
237	splx(s);
238	return (error);
239
240bad:
241	if (m)
242		m_freem(m);
243	return (error);
244}
245
246/*
247 * Process a received ATM packet;
248 * the packet is in the mbuf chain m.
249 */
250void
251atm_input(ifp, ah, m, rxhand)
252	struct ifnet *ifp;
253	register struct atm_pseudohdr *ah;
254	struct mbuf *m;
255	void *rxhand;
256{
257	register struct ifqueue *inq;
258	u_int16_t etype = ETHERTYPE_IP; /* default */
259	int s;
260
261	if ((ifp->if_flags & IFF_UP) == 0) {
262		m_freem(m);
263		return;
264	}
265	gettime(&ifp->if_lastchange);
266	ifp->if_ibytes += m->m_pkthdr.len;
267
268#if NBPFILTER > 0
269	if (ifp->if_bpf) {
270		/*
271		 * We need to prepend the address family as
272		 * a four byte field.  Cons up a dummy header
273		 * to pacify bpf.  This is safe because bpf
274		 * will only read from the mbuf (i.e., it won't
275		 * try to free it or keep a pointer to it).
276		 */
277		struct mbuf m0;
278		u_int af = AF_INET;
279
280		m0.m_next = m;
281		m0.m_len = 4;
282		m0.m_data = (char *)&af;
283
284#if defined(__NetBSD__) || defined(__OpenBSD__)
285		bpf_mtap(&ifp->if_bpf, &m0);
286#elif defined(__FreeBSD__)
287		bpf_mtap(ifp, &m0);
288#endif
289	}
290#endif /* NBPFILTER > 0 */
291
292	if (rxhand) {
293#ifdef NATM
294	  struct natmpcb *npcb = rxhand;
295	  s = splimp();			/* in case 2 atm cards @ diff lvls */
296	  npcb->npcb_inq++;			/* count # in queue */
297	  splx(s);
298	  schednetisr(NETISR_NATM);
299	  inq = &natmintrq;
300	  m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
301#else
302	  printf("atm_input: NATM detected but not configured in kernel\n");
303	  m_freem(m);
304	  return;
305#endif
306	} else {
307	  /*
308	   * handle LLC/SNAP header, if present
309	   */
310	  if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
311	    struct atmllc *alc;
312	    if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
313		  return; /* failed */
314	    alc = mtod(m, struct atmllc *);
315	    if (bcmp(alc, ATMLLC_HDR, 6)) {
316#if defined(__NetBSD__) || defined(__OpenBSD__)
317	      printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
318		  ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
319#elif defined(__FreeBSD__) || defined(__bsdi__)
320	      printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
321		  ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
322#endif
323	      m_freem(m);
324              return;
325	    }
326	    etype = ATM_LLC_TYPE(alc);
327	    m_adj(m, sizeof(*alc));
328	  }
329
330	  switch (etype) {
331#ifdef INET
332	  case ETHERTYPE_IP:
333		  schednetisr(NETISR_IP);
334		  inq = &ipintrq;
335		  break;
336#endif
337	  default:
338	      m_freem(m);
339	      return;
340	  }
341	}
342
343	s = splimp();
344	if (IF_QFULL(inq)) {
345		IF_DROP(inq);
346		m_freem(m);
347	} else
348		IF_ENQUEUE(inq, m);
349	splx(s);
350}
351
352/*
353 * Perform common duties while attaching to interface list
354 */
355void
356atm_ifattach(ifp)
357	register struct ifnet *ifp;
358{
359	register struct ifaddr *ifa;
360	register struct sockaddr_dl *sdl;
361
362	ifp->if_type = IFT_ATM;
363	ifp->if_addrlen = 0;
364	ifp->if_hdrlen = 0;
365	ifp->if_mtu = ATMMTU;
366	ifp->if_output = atm_output;
367
368#if defined(__NetBSD__) || defined(__OpenBSD__)
369	for (ifa = ifp->if_addrlist.tqh_first; ifa != 0;
370	    ifa = ifa->ifa_list.tqe_next)
371#elif defined(__FreeBSD__) && ((__FreeBSD__ > 2) || defined(_NET_IF_VAR_H_))
372/*
373 * for FreeBSD-3.0.  3.0-SNAP-970124 still sets -D__FreeBSD__=2!
374 * XXX -- for now, use newly-introduced "net/if_var.h" as an identifier.
375 * need a better way to identify 3.0.  -- kjc
376 */
377	for (ifa = ifp->if_addrhead.tqh_first; ifa;
378	    ifa = ifa->ifa_link.tqe_next)
379#elif defined(__FreeBSD__) || defined(__bsdi__)
380	for (ifa = ifp->if_addrlist; ifa; ifa = ifa->ifa_next)
381#endif
382
383		if ((sdl = (struct sockaddr_dl *)ifa->ifa_addr) &&
384		    sdl->sdl_family == AF_LINK) {
385			sdl->sdl_type = IFT_ATM;
386			sdl->sdl_alen = ifp->if_addrlen;
387#ifdef notyet /* if using ATMARP, store hardware address using the next line */
388			bcopy(ifp->hw_addr, LLADDR(sdl), ifp->if_addrlen);
389#endif
390			break;
391		}
392#if NBPFILTER > 0
393#if defined(__NetBSD__) || defined(__OpenBSD__)
394	bpfattach(&ifp->if_bpf, ifp, DLT_NULL, sizeof(u_int));
395#elif defined(__FreeBSD__)
396	bpfattach(ifp, DLT_NULL, sizeof(u_int));
397#endif
398#endif /* NBPFILTER > 0 */
399}
400