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