if_atm.c revision 97074
1212795Sdim/*      $NetBSD: if_atm.c,v 1.6 1996/10/13 02:03:01 christos Exp $       */
2212795Sdim
3212795Sdim/*
4212795Sdim *
5212795Sdim * Copyright (c) 1996 Charles D. Cranor and Washington University.
6212795Sdim * All rights reserved.
7212795Sdim *
8212795Sdim * Redistribution and use in source and binary forms, with or without
9212795Sdim * modification, are permitted provided that the following conditions
10212795Sdim * are met:
11212795Sdim * 1. Redistributions of source code must retain the above copyright
12212795Sdim *    notice, this list of conditions and the following disclaimer.
13212795Sdim * 2. Redistributions in binary form must reproduce the above copyright
14212795Sdim *    notice, this list of conditions and the following disclaimer in the
15212795Sdim *    documentation and/or other materials provided with the distribution.
16212795Sdim * 3. All advertising materials mentioning features or use of this software
17212795Sdim *    must display the following acknowledgement:
18212795Sdim *      This product includes software developed by Charles D. Cranor and
19212795Sdim *	Washington University.
20212795Sdim * 4. The name of the author may not be used to endorse or promote products
21212795Sdim *    derived from this software without specific prior written permission.
22212795Sdim *
23212795Sdim * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
24212795Sdim * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
25212795Sdim * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
26243830Sdim * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
27243830Sdim * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
28212795Sdim * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
29212795Sdim * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
30212795Sdim * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
31212795Sdim * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
32212795Sdim * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33212795Sdim *
34212795Sdim * $FreeBSD: head/sys/netinet/if_atm.c 97074 2002-05-21 18:52:24Z arr $
35212795Sdim */
36212795Sdim
37212795Sdim/*
38212795Sdim * IP <=> ATM address resolution.
39212795Sdim */
40212795Sdim
41212795Sdim#include "opt_inet.h"
42212795Sdim#include "opt_inet6.h"
43212795Sdim#include "opt_natm.h"
44212795Sdim
45212795Sdim#if defined(INET) || defined(INET6)
46212795Sdim
47212795Sdim#include <sys/param.h>
48212795Sdim#include <sys/systm.h>
49212795Sdim#include <sys/queue.h>
50212795Sdim#include <sys/mbuf.h>
51212795Sdim#include <sys/socket.h>
52263508Sdim#include <sys/sockio.h>
53212795Sdim#include <sys/syslog.h>
54212795Sdim
55212795Sdim#include <net/if.h>
56212795Sdim#include <net/if_dl.h>
57212795Sdim#include <net/route.h>
58212795Sdim#include <net/if_atm.h>
59212795Sdim
60212795Sdim#include <netinet/in.h>
61212795Sdim#include <netinet/if_atm.h>
62212795Sdim
63212795Sdim#ifdef NATM
64212795Sdim#include <netnatm/natm.h>
65212795Sdim#endif
66212795Sdim
67212795Sdim
68212795Sdim#define SDL(s) ((struct sockaddr_dl *)s)
69212795Sdim
70212795Sdim/*
71234353Sdim * atm_rtrequest: handle ATM rt request (in support of generic code)
72234353Sdim *   inputs: "req" = request code
73212795Sdim *           "rt" = route entry
74212795Sdim *           "info" = rt_addrinfo
75212795Sdim */
76263508Sdim
77263508Sdimvoid
78263508Sdimatm_rtrequest(req, rt, info)
79212795Sdim	int req;
80234353Sdim	register struct rtentry *rt;
81234353Sdim	struct rt_addrinfo *info;
82212795Sdim{
83212795Sdim	register struct sockaddr *gate = rt->rt_gateway;
84212795Sdim	struct atm_pseudoioctl api;
85212795Sdim#ifdef NATM
86212795Sdim	struct sockaddr_in *sin;
87212795Sdim	struct natmpcb *npcb = NULL;
88212795Sdim	struct atm_pseudohdr *aph;
89212795Sdim#endif
90212795Sdim	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
91212795Sdim
92212795Sdim	if (rt->rt_flags & RTF_GATEWAY)   /* link level requests only */
93212795Sdim		return;
94212795Sdim
95212795Sdim	switch (req) {
96212795Sdim
97212795Sdim	case RTM_RESOLVE: /* resolve: only happens when cloning */
98212795Sdim		printf("atm_rtrequest: RTM_RESOLVE request detected?\n");
99212795Sdim		break;
100212795Sdim
101263508Sdim	case RTM_ADD:
102263508Sdim
103263508Sdim		/*
104212795Sdim		 * route added by a command (e.g. ifconfig, route, arp...).
105212795Sdim		 *
106212795Sdim		 * first check to see if this is not a host route, in which
107212795Sdim		 * case we are being called via "ifconfig" to set the address.
108212795Sdim		 */
109212795Sdim
110212795Sdim		if ((rt->rt_flags & RTF_HOST) == 0) {
111212795Sdim			rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl);
112212795Sdim			gate = rt->rt_gateway;
113212795Sdim			SDL(gate)->sdl_type = rt->rt_ifp->if_type;
114212795Sdim			SDL(gate)->sdl_index = rt->rt_ifp->if_index;
115212795Sdim			break;
116212795Sdim		}
117212795Sdim
118234353Sdim		if ((rt->rt_flags & RTF_CLONING) != 0) {
119212795Sdim			printf("atm_rtrequest: cloning route detected?\n");
120212795Sdim			break;
121212795Sdim		}
122212795Sdim		if (gate->sa_family != AF_LINK ||
123212795Sdim		    gate->sa_len < sizeof(null_sdl)) {
124212795Sdim			log(LOG_DEBUG, "atm_rtrequest: bad gateway value");
125212795Sdim			break;
126243830Sdim		}
127212795Sdim
128243830Sdim		KASSERT(rt->rt_ifp->if_ioctl != NULL,
129234353Sdim		    ("atm_rtrequest: null ioctl"));
130212795Sdim#ifdef NATM
131243830Sdim		/*
132212795Sdim		 * let native ATM know we are using this VCI/VPI
133243830Sdim		 * (i.e. reserve it)
134212795Sdim		 */
135212795Sdim		sin = (struct sockaddr_in *) rt_key(rt);
136212795Sdim		if (sin->sin_family != AF_INET)
137234353Sdim			goto failed;
138212795Sdim		aph = (struct atm_pseudohdr *) LLADDR(SDL(gate));
139212795Sdim		npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph),
140212795Sdim						ATM_PH_VPI(aph));
141212795Sdim		if (npcb == NULL)
142212795Sdim			goto failed;
143212795Sdim		npcb->npcb_flags |= NPCB_IP;
144212795Sdim		npcb->ipaddr.s_addr = sin->sin_addr.s_addr;
145212795Sdim		/* XXX: move npcb to llinfo when ATM ARP is ready */
146212795Sdim		rt->rt_llinfo = (caddr_t) npcb;
147234353Sdim		rt->rt_flags |= RTF_LLINFO;
148212795Sdim#endif
149212795Sdim		/*
150212795Sdim		 * let the lower level know this circuit is active
151212795Sdim		 */
152212795Sdim		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
153212795Sdim		api.rxhand = NULL;
154234353Sdim		if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA,
155212795Sdim							(caddr_t)&api) != 0) {
156234353Sdim			printf("atm: couldn't add VC\n");
157212795Sdim			goto failed;
158212795Sdim		}
159212795Sdim
160234353Sdim		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
161212904Sdim		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
162243830Sdim
163243830Sdim		break;
164243830Sdim
165234353Sdimfailed:
166212795Sdim#ifdef NATM
167212795Sdim		if (npcb) {
168234353Sdim			npcb_free(npcb, NPCB_DESTROY);
169212795Sdim			rt->rt_llinfo = NULL;
170234353Sdim			rt->rt_flags &= ~RTF_LLINFO;
171234353Sdim		}
172212795Sdim#endif
173212795Sdim		rtrequest(RTM_DELETE, rt_key(rt), (struct sockaddr *)0,
174212795Sdim			rt_mask(rt), 0, (struct rtentry **) 0);
175234353Sdim		break;
176243830Sdim
177212795Sdim	case RTM_DELETE:
178234353Sdim
179212795Sdim#ifdef NATM
180212795Sdim		/*
181234353Sdim		 * tell native ATM we are done with this VC
182212795Sdim		 */
183212795Sdim
184212795Sdim		if (rt->rt_flags & RTF_LLINFO) {
185234353Sdim			npcb_free((struct natmpcb *)rt->rt_llinfo,
186226633Sdim								NPCB_DESTROY);
187226633Sdim			rt->rt_llinfo = NULL;
188212795Sdim			rt->rt_flags &= ~RTF_LLINFO;
189234353Sdim		}
190212795Sdim#endif
191212795Sdim		/*
192212795Sdim		 * tell the lower layer to disable this circuit
193212795Sdim		 */
194239462Sdim
195212795Sdim		bcopy(LLADDR(SDL(gate)), &api.aph, sizeof(api.aph));
196212795Sdim		api.rxhand = NULL;
197212795Sdim		(void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS,
198212795Sdim							(caddr_t)&api);
199212795Sdim
200212795Sdim		break;
201234353Sdim	}
202212795Sdim}
203212795Sdim
204212795Sdim/*
205212795Sdim * atmresolve:
206212795Sdim *   inputs:
207234353Sdim *     [1] "rt" = the link level route to use (or null if need to look one up)
208243830Sdim *     [2] "m" = mbuf containing the data to be sent
209234353Sdim *     [3] "dst" = sockaddr_in (IP) address of dest.
210243830Sdim *   output:
211212795Sdim *     [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info
212234353Sdim *   return:
213212795Sdim *     0 == resolve FAILED; note that "m" gets m_freem'd in this case
214243830Sdim *     1 == resolve OK; desten contains result
215249423Sdim *
216212795Sdim *   XXX: will need more work if we wish to support ATMARP in the kernel,
217212795Sdim *   but this is enough for PVCs entered via the "route" command.
218212795Sdim */
219212795Sdim
220212795Sdimint
221212795Sdimatmresolve(rt, m, dst, desten)
222212795Sdim
223212795Sdimregister struct rtentry *rt;
224239462Sdimstruct mbuf *m;
225212795Sdimregister struct sockaddr *dst;
226212795Sdimregister struct atm_pseudohdr *desten;	/* OUT */
227234353Sdim
228212795Sdim{
229212795Sdim	struct sockaddr_dl *sdl;
230212795Sdim
231234353Sdim	if (m->m_flags & (M_BCAST|M_MCAST)) {
232239462Sdim		log(LOG_INFO, "atmresolve: BCAST/MCAST packet detected/dumped");
233212795Sdim		goto bad;
234239462Sdim	}
235239462Sdim
236239462Sdim	if (rt == NULL) {
237239462Sdim		rt = RTALLOC1(dst, 0);
238212795Sdim		if (rt == NULL) goto bad; /* failed */
239239462Sdim		rt->rt_refcnt--;	/* don't keep LL references */
240212795Sdim		if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
241212795Sdim			(rt->rt_flags & RTF_LLINFO) == 0 ||
242239462Sdim			/* XXX: are we using LLINFO? */
243239462Sdim			rt->rt_gateway->sa_family != AF_LINK) {
244239462Sdim				goto bad;
245239462Sdim		}
246239462Sdim	}
247239462Sdim
248212795Sdim	/*
249212795Sdim	 * note that rt_gateway is a sockaddr_dl which contains the
250212795Sdim	 * atm_pseudohdr data structure for this route.   we currently
251212795Sdim	 * don't need any rt_llinfo info (but will if we want to support
252212795Sdim	 * ATM ARP [c.f. if_ether.c]).
253234353Sdim	 */
254234353Sdim
255212795Sdim	sdl = SDL(rt->rt_gateway);
256212795Sdim
257212795Sdim	/*
258212795Sdim	 * Check the address family and length is valid, the address
259212795Sdim	 * is resolved; otherwise, try to resolve.
260212795Sdim	 */
261212795Sdim
262212795Sdim
263212795Sdim	if (sdl->sdl_family == AF_LINK && sdl->sdl_alen == sizeof(*desten)) {
264212795Sdim		bcopy(LLADDR(sdl), desten, sdl->sdl_alen);
265212795Sdim		return(1);	/* ok, go for it! */
266212795Sdim	}
267212795Sdim
268212795Sdim	/*
269212795Sdim	 * we got an entry, but it doesn't have valid link address
270212795Sdim	 * info in it (it is prob. the interface route, which has
271212795Sdim	 * sdl_alen == 0).    dump packet.  (fall through to "bad").
272212795Sdim	 */
273212795Sdim
274212795Sdimbad:
275212795Sdim	m_freem(m);
276212795Sdim	return(0);
277212795Sdim}
278212795Sdim#endif /* INET */
279212795Sdim