1/*      $NetBSD$       */
2
3/*
4 * Copyright (c) 1996 Charles D. Cranor and Washington University.
5 * 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 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * if_atmsubr.c
30 */
31
32#include <sys/cdefs.h>
33__KERNEL_RCSID(0, "$NetBSD$");
34
35#include "opt_inet.h"
36#include "opt_gateway.h"
37#include "opt_natm.h"
38
39
40#include <sys/param.h>
41#include <sys/systm.h>
42#include <sys/kernel.h>
43#include <sys/malloc.h>
44#include <sys/mbuf.h>
45#include <sys/protosw.h>
46#include <sys/socket.h>
47#include <sys/ioctl.h>
48#include <sys/errno.h>
49#include <sys/syslog.h>
50
51#include <sys/cpu.h>
52
53#include <net/if.h>
54#include <net/netisr.h>
55#include <net/route.h>
56#include <net/if_dl.h>
57#include <net/if_types.h>
58#include <net/if_atm.h>
59#include <net/ethertypes.h> /* XXX: for ETHERTYPE_* */
60
61#include <net/bpf.h>
62
63#include <netinet/in.h>
64#include <netinet/if_atm.h>
65
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#define senderr(e) { error = (e); goto bad;}
74
75/*
76 * atm_output: ATM output routine
77 *   inputs:
78 *     "ifp" = ATM interface to output to
79 *     "m0" = the packet to output
80 *     "dst" = the sockaddr to send to (either IP addr, or raw VPI/VCI)
81 *     "rt0" = the route to use
82 *   returns: error code   [0 == ok]
83 *
84 *   note: special semantic: if (dst == NULL) then we assume "m" already
85 *		has an atm_pseudohdr on it and just send it directly.
86 *		[for native mode ATM output]   if dst is null, then
87 *		rt0 must also be NULL.
88 */
89
90int
91atm_output(struct ifnet *ifp, struct mbuf *m0, const struct sockaddr *dst,
92    struct rtentry *rt0)
93{
94	uint16_t etype = 0;			/* if using LLC/SNAP */
95	int error = 0, sz;
96	struct atm_pseudohdr atmdst, *ad;
97	struct mbuf *m = m0;
98	struct rtentry *rt;
99	struct atmllc *atmllc;
100	uint32_t atm_flags;
101	ALTQ_DECL(struct altq_pktattr pktattr;)
102
103	if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
104		senderr(ENETDOWN);
105
106	/*
107	 * If the queueing discipline needs packet classification,
108	 * do it before prepending link headers.
109	 */
110	IFQ_CLASSIFY(&ifp->if_snd, m,
111	     (dst != NULL ? dst->sa_family : AF_UNSPEC), &pktattr);
112
113	/*
114	 * check route
115	 */
116	if ((rt = rt0) != NULL) {
117
118		if ((rt->rt_flags & RTF_UP) == 0) { /* route went down! */
119			if ((rt0 = rt = RTALLOC1(dst, 0)) != NULL)
120				rt->rt_refcnt--;
121			else
122				senderr(EHOSTUNREACH);
123		}
124
125		if (rt->rt_flags & RTF_GATEWAY) {
126			if (rt->rt_gwroute == 0)
127				goto lookup;
128			if (((rt = rt->rt_gwroute)->rt_flags & RTF_UP) == 0) {
129				rtfree(rt); rt = rt0;
130			lookup: rt->rt_gwroute = RTALLOC1(rt->rt_gateway, 0);
131				if ((rt = rt->rt_gwroute) == 0)
132					senderr(EHOSTUNREACH);
133			}
134		}
135
136		/* XXX: put RTF_REJECT code here if doing ATMARP */
137
138	}
139
140	/*
141	 * check for non-native ATM traffic   (dst != NULL)
142	 */
143	if (dst) {
144		switch (dst->sa_family) {
145#ifdef INET
146		case AF_INET:
147#endif
148#ifdef INET6
149		case AF_INET6:
150#endif
151#if defined(INET) || defined(INET6)
152			if (dst->sa_family == AF_INET)
153				etype = ETHERTYPE_IP;
154			else
155				etype = ETHERTYPE_IPV6;
156# ifdef ATM_PVCEXT
157			if (ifp->if_flags & IFF_POINTOPOINT) {
158				/* pvc subinterface */
159				struct pvcsif *pvcsif = (struct pvcsif *)ifp;
160				atmdst = pvcsif->sif_aph;
161				break;
162			}
163# endif
164			if (!atmresolve(rt, m, dst, &atmdst)) {
165				m = NULL;
166				/* XXX: atmresolve already free'd it */
167				senderr(EHOSTUNREACH);
168				/* XXX: put ATMARP stuff here */
169				/* XXX: watch who frees m on failure */
170			}
171			break;
172#endif
173
174		case AF_UNSPEC:
175			/*
176			 * XXX: bpfwrite or output from a pvc shadow if.
177			 * assuming dst contains 12 bytes (atm pseudo
178			 * header (4) + LLC/SNAP (8))
179			 */
180			memcpy(&atmdst, dst->sa_data, sizeof(atmdst));
181			break;
182
183		default:
184#if defined(__NetBSD__) || defined(__OpenBSD__)
185			printf("%s: can't handle af%d\n", ifp->if_xname,
186			    dst->sa_family);
187#elif defined(__FreeBSD__) || defined(__bsdi__)
188			printf("%s%d: can't handle af%d\n", ifp->if_name,
189			    ifp->if_unit, dst->sa_family);
190#endif
191			senderr(EAFNOSUPPORT);
192		}
193
194		/*
195		 * must add atm_pseudohdr to data
196		 */
197		sz = sizeof(atmdst);
198		atm_flags = ATM_PH_FLAGS(&atmdst);
199		if (atm_flags & ATM_PH_LLCSNAP) sz += 8; /* sizeof snap == 8 */
200		M_PREPEND(m, sz, M_DONTWAIT);
201		if (m == 0)
202			senderr(ENOBUFS);
203		ad = mtod(m, struct atm_pseudohdr *);
204		*ad = atmdst;
205		if (atm_flags & ATM_PH_LLCSNAP) {
206			atmllc = (struct atmllc *)(ad + 1);
207			memcpy(atmllc->llchdr, ATMLLC_HDR,
208						sizeof(atmllc->llchdr));
209			ATM_LLC_SETTYPE(atmllc, etype);
210		}
211	}
212
213	return ifq_enqueue(ifp, m ALTQ_COMMA ALTQ_DECL(&pktattr));
214
215bad:
216	if (m)
217		m_freem(m);
218	return (error);
219}
220
221/*
222 * Process a received ATM packet;
223 * the packet is in the mbuf chain m.
224 */
225void
226atm_input(struct ifnet *ifp, struct atm_pseudohdr *ah, struct mbuf *m,
227    void *rxhand)
228{
229	struct ifqueue *inq;
230	uint16_t etype = ETHERTYPE_IP; /* default */
231	int s;
232
233	if ((ifp->if_flags & IFF_UP) == 0) {
234		m_freem(m);
235		return;
236	}
237	ifp->if_ibytes += m->m_pkthdr.len;
238
239	if (rxhand) {
240#ifdef NATM
241	  struct natmpcb *npcb = rxhand;
242	  s = splnet();			/* in case 2 atm cards @ diff lvls */
243	  npcb->npcb_inq++;			/* count # in queue */
244	  splx(s);
245	  schednetisr(NETISR_NATM);
246	  inq = &natmintrq;
247	  m->m_pkthdr.rcvif = rxhand; /* XXX: overload */
248#else
249	  printf("atm_input: NATM detected but not configured in kernel\n");
250	  m_freem(m);
251	  return;
252#endif
253	} else {
254	  /*
255	   * handle LLC/SNAP header, if present
256	   */
257	  if (ATM_PH_FLAGS(ah) & ATM_PH_LLCSNAP) {
258	    struct atmllc *alc;
259	    if (m->m_len < sizeof(*alc) && (m = m_pullup(m, sizeof(*alc))) == 0)
260		  return; /* failed */
261	    alc = mtod(m, struct atmllc *);
262	    if (memcmp(alc, ATMLLC_HDR, 6)) {
263#if defined(__NetBSD__) || defined(__OpenBSD__)
264	      printf("%s: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
265		  ifp->if_xname, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
266#elif defined(__FreeBSD__) || defined(__bsdi__)
267	      printf("%s%d: recv'd invalid LLC/SNAP frame [vp=%d,vc=%d]\n",
268		  ifp->if_name, ifp->if_unit, ATM_PH_VPI(ah), ATM_PH_VCI(ah));
269#endif
270	      m_freem(m);
271              return;
272	    }
273	    etype = ATM_LLC_TYPE(alc);
274	    m_adj(m, sizeof(*alc));
275	  }
276
277	  switch (etype) {
278#ifdef INET
279	  case ETHERTYPE_IP:
280#ifdef GATEWAY
281		  if (ipflow_fastforward(m))
282			return;
283#endif
284		  schednetisr(NETISR_IP);
285		  inq = &ipintrq;
286		  break;
287#endif /* INET */
288#ifdef INET6
289	  case ETHERTYPE_IPV6:
290#ifdef GATEWAY
291		if (ip6flow_fastforward(&m))
292			return;
293#endif
294		  schednetisr(NETISR_IPV6);
295		  inq = &ip6intrq;
296		  break;
297#endif
298	  default:
299	      m_freem(m);
300	      return;
301	  }
302	}
303
304	s = splnet();
305	if (IF_QFULL(inq)) {
306		IF_DROP(inq);
307		m_freem(m);
308	} else
309		IF_ENQUEUE(inq, m);
310	splx(s);
311}
312
313/*
314 * Perform common duties while attaching to interface list
315 */
316void
317atm_ifattach(struct ifnet *ifp)
318{
319
320	ifp->if_type = IFT_ATM;
321	ifp->if_addrlen = 0;
322	ifp->if_hdrlen = 0;
323	ifp->if_dlt = DLT_ATM_RFC1483;
324	ifp->if_mtu = ATMMTU;
325	ifp->if_output = atm_output;
326#if 0 /* XXX XXX XXX */
327	ifp->if_input = atm_input;
328#endif
329
330	if_alloc_sadl(ifp);
331	/* XXX Store LLADDR for ATMARP. */
332
333	bpf_attach(ifp, DLT_ATM_RFC1483, sizeof(struct atmllc));
334}
335
336#ifdef ATM_PVCEXT
337
338static int pvc_max_number = 16;	/* max number of PVCs */
339static int pvc_number = 0;	/* pvc unit number */
340
341struct ifnet *
342pvcsif_alloc(void)
343{
344	struct pvcsif *pvcsif;
345
346	if (pvc_number >= pvc_max_number)
347		return (NULL);
348	pvcsif = malloc(sizeof(struct pvcsif),
349	       M_DEVBUF, M_WAITOK|M_ZERO);
350	if (pvcsif == NULL)
351		return (NULL);
352
353#ifdef __NetBSD__
354	snprintf(pvcsif->sif_if.if_xname, sizeof(pvcsif->sif_if.if_xname),
355	    "pvc%d", pvc_number++);
356#else
357	pvcsif->sif_if.if_name = "pvc";
358	pvcsif->sif_if.if_unit = pvc_number++;
359#endif
360	return (&pvcsif->sif_if);
361}
362#endif /* ATM_PVCEXT */
363