125603Skjc/*      $NetBSD: if_atm.c,v 1.6 1996/10/13 02:03:01 christos Exp $       */
225603Skjc
3139823Simp/*-
425603Skjc *
525603Skjc * Copyright (c) 1996 Charles D. Cranor and Washington University.
625603Skjc * All rights reserved.
725603Skjc *
825603Skjc * Redistribution and use in source and binary forms, with or without
925603Skjc * modification, are permitted provided that the following conditions
1025603Skjc * are met:
1125603Skjc * 1. Redistributions of source code must retain the above copyright
1225603Skjc *    notice, this list of conditions and the following disclaimer.
1325603Skjc * 2. Redistributions in binary form must reproduce the above copyright
1425603Skjc *    notice, this list of conditions and the following disclaimer in the
1525603Skjc *    documentation and/or other materials provided with the distribution.
1625603Skjc * 3. All advertising materials mentioning features or use of this software
1725603Skjc *    must display the following acknowledgement:
18133874Srwatson *      This product includes software developed by Charles D. Cranor and
19133874Srwatson *      Washington University.
2025603Skjc * 4. The name of the author may not be used to endorse or promote products
2125603Skjc *    derived from this software without specific prior written permission.
2225603Skjc *
2325603Skjc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
2425603Skjc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
2525603Skjc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2625603Skjc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
2725603Skjc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
2825603Skjc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
2925603Skjc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3025603Skjc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3125603Skjc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
3225603Skjc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3325603Skjc */
34118497Sharti#include <sys/cdefs.h>
35118497Sharti__FBSDID("$FreeBSD$");
3625603Skjc
3725603Skjc/*
3825603Skjc * IP <=> ATM address resolution.
3925603Skjc */
4032350Seivind#include "opt_inet.h"
4154263Sshin#include "opt_inet6.h"
4232925Seivind#include "opt_natm.h"
4332350Seivind
4437939Skjc#if defined(INET) || defined(INET6)
4525603Skjc
4625603Skjc#include <sys/param.h>
4725603Skjc#include <sys/systm.h>
4837939Skjc#include <sys/queue.h>
4925603Skjc#include <sys/mbuf.h>
5025603Skjc#include <sys/socket.h>
5125603Skjc#include <sys/sockio.h>
5225603Skjc#include <sys/syslog.h>
5325603Skjc
5425603Skjc#include <net/if.h>
55257176Sglebius#include <net/if_var.h>
5625603Skjc#include <net/if_dl.h>
5725603Skjc#include <net/route.h>
5825603Skjc#include <net/if_atm.h>
5925603Skjc
6025603Skjc#include <netinet/in.h>
6125603Skjc#include <netinet/if_atm.h>
6225603Skjc
6325603Skjc#ifdef NATM
6425603Skjc#include <netnatm/natm.h>
6525603Skjc#endif
6625603Skjc
6725603Skjc#define SDL(s) ((struct sockaddr_dl *)s)
6825603Skjc
69118823Sharti#define	GET3BYTE(V, A, L)	do {				\
70118823Sharti	(V) = ((A)[0] << 16) | ((A)[1] << 8) | (A)[2];		\
71118823Sharti	(A) += 3;						\
72118823Sharti	(L) -= 3;						\
73118823Sharti    } while (0)
74118823Sharti
75118823Sharti#define GET2BYTE(V, A, L)	do {				\
76118823Sharti	(V) = ((A)[0] << 8) | (A)[1];				\
77118823Sharti	(A) += 2;						\
78118823Sharti	(L) -= 2;						\
79118823Sharti    } while (0)
80118823Sharti
81118823Sharti#define GET1BYTE(V, A, L)	do {				\
82118823Sharti	(V) = *(A)++;						\
83118823Sharti	(L)--;							\
84118823Sharti    } while (0)
85118823Sharti
86118823Sharti
8725603Skjc/*
8825603Skjc * atm_rtrequest: handle ATM rt request (in support of generic code)
8925603Skjc *   inputs: "req" = request code
9025603Skjc *           "rt" = route entry
9185074Sru *           "info" = rt_addrinfo
9225603Skjc */
9325603Skjcvoid
94118497Shartiatm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info)
9525603Skjc{
96118497Sharti	struct sockaddr *gate = rt->rt_gateway;
97118552Sharti	struct atmio_openvcc op;
98118552Sharti	struct atmio_closevcc cl;
99118552Sharti	u_char *addr;
100118552Sharti	u_int alen;
10125603Skjc#ifdef NATM
10225603Skjc	struct sockaddr_in *sin;
10325603Skjc	struct natmpcb *npcb = NULL;
10425603Skjc#endif
10525603Skjc	static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK};
10625603Skjc
10725603Skjc	if (rt->rt_flags & RTF_GATEWAY)   /* link level requests only */
10825603Skjc		return;
10925603Skjc
11025603Skjc	switch (req) {
11125603Skjc
11225603Skjc	case RTM_RESOLVE: /* resolve: only happens when cloning */
11325603Skjc		printf("atm_rtrequest: RTM_RESOLVE request detected?\n");
11425603Skjc		break;
11525603Skjc
11625603Skjc	case RTM_ADD:
11725603Skjc		/*
11825603Skjc		 * route added by a command (e.g. ifconfig, route, arp...).
11925603Skjc		 *
12025603Skjc		 * first check to see if this is not a host route, in which
12125603Skjc		 * case we are being called via "ifconfig" to set the address.
12225603Skjc		 */
123133874Srwatson		if ((rt->rt_flags & RTF_HOST) == 0) {
12425603Skjc			rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl);
12525603Skjc			gate = rt->rt_gateway;
12625603Skjc			SDL(gate)->sdl_type = rt->rt_ifp->if_type;
12725603Skjc			SDL(gate)->sdl_index = rt->rt_ifp->if_index;
12825603Skjc			break;
12925603Skjc		}
13025603Skjc
13125603Skjc		if (gate->sa_family != AF_LINK ||
13225603Skjc		    gate->sa_len < sizeof(null_sdl)) {
13325603Skjc			log(LOG_DEBUG, "atm_rtrequest: bad gateway value");
13425603Skjc			break;
13525603Skjc		}
13625603Skjc
13797074Sarr		KASSERT(rt->rt_ifp->if_ioctl != NULL,
13897074Sarr		    ("atm_rtrequest: null ioctl"));
139118552Sharti
140118552Sharti		/*
141118552Sharti		 * Parse and verify the link level address as
142118552Sharti		 * an open request
143118552Sharti		 */
144148980Srodrigc#ifdef NATM
145148980Srodrigc		NATM_LOCK();
146148980Srodrigc#endif
147118552Sharti		bzero(&op, sizeof(op));
148118552Sharti		addr = LLADDR(SDL(gate));
149118552Sharti		alen = SDL(gate)->sdl_alen;
150118552Sharti		if (alen < 4) {
151118552Sharti			printf("%s: bad link-level address\n", __func__);
152118552Sharti			goto failed;
153118552Sharti		}
154118552Sharti
155118552Sharti		if (alen == 4) {
156118552Sharti			/* old type address */
157118823Sharti			GET1BYTE(op.param.flags, addr, alen);
158118823Sharti			GET1BYTE(op.param.vpi, addr, alen);
159118823Sharti			GET2BYTE(op.param.vci, addr, alen);
160118552Sharti			op.param.traffic = ATMIO_TRAFFIC_UBR;
161118552Sharti			op.param.aal = (op.param.flags & ATM_PH_AAL5) ?
162118552Sharti			    ATMIO_AAL_5 : ATMIO_AAL_0;
163118552Sharti		} else {
164118552Sharti			/* new address */
165118552Sharti			op.param.aal = ATMIO_AAL_5;
166118823Sharti
167118823Sharti			GET1BYTE(op.param.flags, addr, alen);
168118823Sharti			op.param.flags &= ATM_PH_LLCSNAP;
169118823Sharti
170118823Sharti			GET1BYTE(op.param.vpi, addr, alen);
171118823Sharti			GET2BYTE(op.param.vci, addr, alen);
172118823Sharti
173118823Sharti			GET1BYTE(op.param.traffic, addr, alen);
174118823Sharti
175118552Sharti			switch (op.param.traffic) {
176118552Sharti
177118552Sharti			  case ATMIO_TRAFFIC_UBR:
178118823Sharti				if (alen >= 3)
179118823Sharti					GET3BYTE(op.param.tparam.pcr,
180118823Sharti					    addr, alen);
181118552Sharti				break;
182118552Sharti
183118552Sharti			  case ATMIO_TRAFFIC_CBR:
184118552Sharti				if (alen < 3)
185118552Sharti					goto bad_param;
186118823Sharti				GET3BYTE(op.param.tparam.pcr, addr, alen);
187118552Sharti				break;
188118552Sharti
189118552Sharti			  case ATMIO_TRAFFIC_VBR:
190118552Sharti				if (alen < 3 * 3)
191118552Sharti					goto bad_param;
192118823Sharti				GET3BYTE(op.param.tparam.pcr, addr, alen);
193118823Sharti				GET3BYTE(op.param.tparam.scr, addr, alen);
194118823Sharti				GET3BYTE(op.param.tparam.mbs, addr, alen);
195118552Sharti				break;
196118552Sharti
197118552Sharti			  case ATMIO_TRAFFIC_ABR:
198118823Sharti				if (alen < 4 * 3 + 2 + 1 * 2 + 3)
199118552Sharti					goto bad_param;
200118823Sharti				GET3BYTE(op.param.tparam.pcr, addr, alen);
201118823Sharti				GET3BYTE(op.param.tparam.mcr, addr, alen);
202118823Sharti				GET3BYTE(op.param.tparam.icr, addr, alen);
203118823Sharti				GET3BYTE(op.param.tparam.tbe, addr, alen);
204118823Sharti				GET1BYTE(op.param.tparam.nrm, addr, alen);
205118823Sharti				GET1BYTE(op.param.tparam.trm, addr, alen);
206118823Sharti				GET2BYTE(op.param.tparam.adtf, addr, alen);
207118823Sharti				GET1BYTE(op.param.tparam.rif, addr, alen);
208118823Sharti				GET1BYTE(op.param.tparam.rdf, addr, alen);
209118823Sharti				GET1BYTE(op.param.tparam.cdf, addr, alen);
210118552Sharti				break;
211118552Sharti
212118552Sharti			  default:
213118552Sharti			  bad_param:
214118552Sharti				printf("%s: bad traffic params\n", __func__);
215118552Sharti				goto failed;
216118552Sharti			}
217118552Sharti		}
218118552Sharti		op.param.rmtu = op.param.tmtu = rt->rt_ifp->if_mtu;
21925603Skjc#ifdef NATM
22025603Skjc		/*
22125603Skjc		 * let native ATM know we are using this VCI/VPI
22225603Skjc		 * (i.e. reserve it)
22325603Skjc		 */
22425603Skjc		sin = (struct sockaddr_in *) rt_key(rt);
22525603Skjc		if (sin->sin_family != AF_INET)
22625603Skjc			goto failed;
227118552Sharti		npcb = npcb_add(NULL, rt->rt_ifp, op.param.vci,  op.param.vpi);
228133874Srwatson		if (npcb == NULL)
22925603Skjc			goto failed;
23025603Skjc		npcb->npcb_flags |= NPCB_IP;
23125603Skjc		npcb->ipaddr.s_addr = sin->sin_addr.s_addr;
23225603Skjc		/* XXX: move npcb to llinfo when ATM ARP is ready */
233216466Sbz#ifdef __notyet_restored__
23425603Skjc		rt->rt_llinfo = (caddr_t) npcb;
235216466Sbz#endif
23625603Skjc		rt->rt_flags |= RTF_LLINFO;
23725603Skjc#endif
23825603Skjc		/*
23925603Skjc		 * let the lower level know this circuit is active
24025603Skjc		 */
241118552Sharti		op.rxhand = NULL;
242118552Sharti		op.param.flags |= ATMIO_FLAG_ASYNC;
243133874Srwatson		if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMOPENVCC,
244118552Sharti		    (caddr_t)&op) != 0) {
24525603Skjc			printf("atm: couldn't add VC\n");
24625603Skjc			goto failed;
24725603Skjc		}
24825603Skjc
24925603Skjc		SDL(gate)->sdl_type = rt->rt_ifp->if_type;
25025603Skjc		SDL(gate)->sdl_index = rt->rt_ifp->if_index;
25125603Skjc
252148980Srodrigc#ifdef NATM
253148980Srodrigc		NATM_UNLOCK();
254148980Srodrigc#endif
25525603Skjc		break;
25625603Skjc
25725603Skjcfailed:
25825603Skjc#ifdef NATM
25925603Skjc		if (npcb) {
26025603Skjc			npcb_free(npcb, NPCB_DESTROY);
261216466Sbz#ifdef __notyet_restored__
26225603Skjc			rt->rt_llinfo = NULL;
263216466Sbz#endif
26425603Skjc			rt->rt_flags &= ~RTF_LLINFO;
26525603Skjc		}
266148980Srodrigc		NATM_UNLOCK();
26725603Skjc#endif
268118499Sharti		/* mark as invalid. We cannot RTM_DELETE the route from
269118499Sharti		 * here, because the recursive call to rtrequest1 does
270118499Sharti		 * not really work. */
271118499Sharti		rt->rt_flags |= RTF_REJECT;
27225603Skjc		break;
27325603Skjc
27425603Skjc	case RTM_DELETE:
27525603Skjc#ifdef NATM
27625603Skjc		/*
27725603Skjc		 * tell native ATM we are done with this VC
27825603Skjc		 */
27925603Skjc		if (rt->rt_flags & RTF_LLINFO) {
280148980Srodrigc			NATM_LOCK();
281216466Sbz#ifdef __notyet_restored__
282133874Srwatson			npcb_free((struct natmpcb *)rt->rt_llinfo,
283118497Sharti			    NPCB_DESTROY);
28425603Skjc			rt->rt_llinfo = NULL;
285216466Sbz#endif
28625603Skjc			rt->rt_flags &= ~RTF_LLINFO;
287148980Srodrigc			NATM_UNLOCK();
28825603Skjc		}
28925603Skjc#endif
29025603Skjc		/*
29125603Skjc		 * tell the lower layer to disable this circuit
29225603Skjc		 */
293118552Sharti		bzero(&op, sizeof(op));
294118552Sharti		addr = LLADDR(SDL(gate));
295118552Sharti		addr++;
296118552Sharti		cl.vpi = *addr++;
297118552Sharti		cl.vci = *addr++ << 8;
298118552Sharti		cl.vci |= *addr++;
299133874Srwatson		(void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMCLOSEVCC,
300118552Sharti		    (caddr_t)&cl);
30125603Skjc		break;
30225603Skjc	}
30325603Skjc}
30425603Skjc
30525603Skjc/*
30625603Skjc * atmresolve:
30725603Skjc *   inputs:
30825603Skjc *     [1] "rt" = the link level route to use (or null if need to look one up)
30925603Skjc *     [2] "m" = mbuf containing the data to be sent
31025603Skjc *     [3] "dst" = sockaddr_in (IP) address of dest.
31125603Skjc *   output:
31225603Skjc *     [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info
313133874Srwatson *   return:
31425603Skjc *     0 == resolve FAILED; note that "m" gets m_freem'd in this case
31525603Skjc *     1 == resolve OK; desten contains result
31625603Skjc *
31725603Skjc *   XXX: will need more work if we wish to support ATMARP in the kernel,
31825603Skjc *   but this is enough for PVCs entered via the "route" command.
31925603Skjc */
32025603Skjcint
321249925Sglebiusatmresolve(struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst,
322118497Sharti    struct atm_pseudohdr *desten)
32325603Skjc{
32425603Skjc	struct sockaddr_dl *sdl;
32525603Skjc
326118497Sharti	if (m->m_flags & (M_BCAST | M_MCAST)) {
327149506Sglebius		log(LOG_INFO,
328149506Sglebius		    "atmresolve: BCAST/MCAST packet detected/dumped\n");
32925603Skjc		goto bad;
33025603Skjc	}
33125603Skjc
33225603Skjc	if (rt == NULL) {
333249925Sglebius		/* link level on table 0 XXX MRT */
334249925Sglebius		rt = RTALLOC1(__DECONST(struct sockaddr *, dst), 0);
335118497Sharti		if (rt == NULL)
336118497Sharti			goto bad;	/* failed */
337122334Ssam		RT_REMREF(rt);		/* don't keep LL references */
338133874Srwatson		if ((rt->rt_flags & RTF_GATEWAY) != 0 ||
339118497Sharti		    rt->rt_gateway->sa_family != AF_LINK) {
340120727Ssam			RT_UNLOCK(rt);
341118497Sharti			goto bad;
34225603Skjc		}
343120727Ssam		RT_UNLOCK(rt);
34425603Skjc	}
34525603Skjc
34625603Skjc	/*
347133874Srwatson	 * note that rt_gateway is a sockaddr_dl which contains the
34825603Skjc	 * atm_pseudohdr data structure for this route.   we currently
34925603Skjc	 * don't need any rt_llinfo info (but will if we want to support
35025603Skjc	 * ATM ARP [c.f. if_ether.c]).
35125603Skjc	 */
35225603Skjc	sdl = SDL(rt->rt_gateway);
35325603Skjc
35425603Skjc	/*
35525603Skjc	 * Check the address family and length is valid, the address
35625603Skjc	 * is resolved; otherwise, try to resolve.
35725603Skjc	 */
358118552Sharti	if (sdl->sdl_family == AF_LINK && sdl->sdl_alen >= sizeof(*desten)) {
359118552Sharti		bcopy(LLADDR(sdl), desten, sizeof(*desten));
360118552Sharti		return (1);	/* ok, go for it! */
36125603Skjc	}
36225603Skjc
36325603Skjc	/*
36425603Skjc	 * we got an entry, but it doesn't have valid link address
36525603Skjc	 * info in it (it is prob. the interface route, which has
36625603Skjc	 * sdl_alen == 0).    dump packet.  (fall through to "bad").
36725603Skjc	 */
36825603Skjcbad:
36925603Skjc	m_freem(m);
370118497Sharti	return (0);
37125603Skjc}
37225603Skjc#endif /* INET */
373