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 * IP <=> ATM address resolution. 30 */ 31 32#include <sys/cdefs.h> 33__KERNEL_RCSID(0, "$NetBSD$"); 34 35#include "opt_inet.h" 36#include "opt_natm.h" 37 38#if defined(INET) || defined(INET6) 39 40#include <sys/param.h> 41#include <sys/systm.h> 42#include <sys/malloc.h> 43#include <sys/mbuf.h> 44#include <sys/socket.h> 45#include <sys/time.h> 46#include <sys/kernel.h> 47#include <sys/errno.h> 48#include <sys/ioctl.h> 49#include <sys/syslog.h> 50#include <sys/proc.h> 51 52#include <net/if.h> 53#include <net/if_dl.h> 54#include <net/route.h> 55#include <net/if_atm.h> 56 57#include <netinet/in.h> 58#include <netinet/in_systm.h> 59#include <netinet/in_var.h> 60#include <netinet/ip.h> 61#include <netinet/if_atm.h> 62 63#ifdef NATM 64#include <netnatm/natm.h> 65#endif 66 67 68/* 69 * atm_rtrequest: handle ATM rt request (in support of generic code) 70 * inputs: "req" = request code 71 * "rt" = route entry 72 * "sa" = sockaddr 73 */ 74 75void 76atm_rtrequest(int req, struct rtentry *rt, const struct rt_addrinfo *info) 77{ 78 struct sockaddr *gate = rt->rt_gateway; 79 struct atm_pseudoioctl api; 80#ifdef NATM 81 const struct sockaddr_in *sin; 82 struct natmpcb *npcb = NULL; 83 const struct atm_pseudohdr *aph; 84#endif 85 const struct ifnet *ifp = rt->rt_ifp; 86 uint8_t namelen = strlen(ifp->if_xname); 87 uint8_t addrlen = ifp->if_addrlen; 88 89 if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ 90 return; 91 92 switch (req) { 93 94 case RTM_RESOLVE: /* resolve: only happens when cloning */ 95 printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); 96 break; 97 98 case RTM_ADD: 99 100 /* 101 * route added by a command (e.g. ifconfig, route, arp...). 102 * 103 * first check to see if this is not a host route, in which 104 * case we are being called via "ifconfig" to set the address. 105 */ 106 107 if ((rt->rt_flags & RTF_HOST) == 0) { 108 union { 109 struct sockaddr sa; 110 struct sockaddr_dl sdl; 111 struct sockaddr_storage ss; 112 } u; 113 114 sockaddr_dl_init(&u.sdl, sizeof(u.ss), 115 ifp->if_index, ifp->if_type, 116 NULL, namelen, NULL, addrlen); 117 rt_setgate(rt, &u.sa); 118 gate = rt->rt_gateway; 119 break; 120 } 121 122 if ((rt->rt_flags & RTF_CLONING) != 0) { 123 printf("atm_rtrequest: cloning route detected?\n"); 124 break; 125 } 126 if (gate->sa_family != AF_LINK || 127 gate->sa_len < sockaddr_dl_measure(namelen, addrlen)) { 128 log(LOG_DEBUG, "atm_rtrequest: bad gateway value\n"); 129 break; 130 } 131 132#ifdef DIAGNOSTIC 133 if (rt->rt_ifp->if_ioctl == NULL) panic("atm null ioctl"); 134#endif 135 136#ifdef NATM 137 /* 138 * let native ATM know we are using this VCI/VPI 139 * (i.e. reserve it) 140 */ 141 sin = satocsin(rt_getkey(rt)); 142 if (sin->sin_family != AF_INET) 143 goto failed; 144 aph = (const struct atm_pseudohdr *)CLLADDR(satosdl(gate)); 145 npcb = npcb_add(NULL, rt->rt_ifp, ATM_PH_VCI(aph), 146 ATM_PH_VPI(aph)); 147 if (npcb == NULL) 148 goto failed; 149 npcb->npcb_flags |= NPCB_IP; 150 npcb->ipaddr.s_addr = sin->sin_addr.s_addr; 151 /* XXX: move npcb to llinfo when ATM ARP is ready */ 152 rt->rt_llinfo = (void *) npcb; 153 rt->rt_flags |= RTF_LLINFO; 154#endif 155 /* 156 * let the lower level know this circuit is active 157 */ 158 memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); 159 api.rxhand = NULL; 160 if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMENA, &api) != 0) { 161 printf("atm: couldn't add VC\n"); 162 goto failed; 163 } 164 165 satosdl(gate)->sdl_type = rt->rt_ifp->if_type; 166 satosdl(gate)->sdl_index = rt->rt_ifp->if_index; 167 168 break; 169 170failed: 171#ifdef NATM 172 if (npcb) { 173 npcb_free(npcb, NPCB_DESTROY); 174 rt->rt_llinfo = NULL; 175 rt->rt_flags &= ~RTF_LLINFO; 176 } 177#endif 178 rtrequest(RTM_DELETE, rt_getkey(rt), NULL, 179 rt_mask(rt), 0, NULL); 180 break; 181 182 case RTM_DELETE: 183 184#ifdef NATM 185 /* 186 * tell native ATM we are done with this VC 187 */ 188 189 if (rt->rt_flags & RTF_LLINFO) { 190 npcb_free((struct natmpcb *)rt->rt_llinfo, 191 NPCB_DESTROY); 192 rt->rt_llinfo = NULL; 193 rt->rt_flags &= ~RTF_LLINFO; 194 } 195#endif 196 /* 197 * tell the lower layer to disable this circuit 198 */ 199 200 memcpy(&api.aph, CLLADDR(satocsdl(gate)), sizeof(api.aph)); 201 api.rxhand = NULL; 202 (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMDIS, &api); 203 204 break; 205 } 206} 207 208/* 209 * atmresolve: 210 * inputs: 211 * [1] "rt" = the link level route to use (or null if need to look one up) 212 * [2] "m" = mbuf containing the data to be sent 213 * [3] "dst" = sockaddr_in (IP) address of dest. 214 * output: 215 * [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info 216 * return: 217 * 0 == resolve FAILED; note that "m" gets m_freem'd in this case 218 * 1 == resolve OK; desten contains result 219 * 220 * XXX: will need more work if we wish to support ATMARP in the kernel, 221 * but this is enough for PVCs entered via the "route" command. 222 */ 223 224int 225atmresolve(struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, 226 struct atm_pseudohdr *desten /* OUT */) 227{ 228 const struct sockaddr_dl *sdl; 229 230 if (m->m_flags & (M_BCAST|M_MCAST)) { 231 log(LOG_INFO, "atmresolve: BCAST/MCAST packet detected/dumped\n"); 232 goto bad; 233 } 234 235 if (rt == NULL) { 236 rt = RTALLOC1(dst, 0); 237 if (rt == NULL) goto bad; /* failed */ 238 rt->rt_refcnt--; /* don't keep LL references */ 239 if ((rt->rt_flags & RTF_GATEWAY) != 0 || 240 (rt->rt_flags & RTF_LLINFO) == 0 || 241 /* XXX: are we using LLINFO? */ 242 rt->rt_gateway->sa_family != AF_LINK) { 243 goto bad; 244 } 245 } 246 247 /* 248 * note that rt_gateway is a sockaddr_dl which contains the 249 * atm_pseudohdr data structure for this route. we currently 250 * don't need any rt_llinfo info (but will if we want to support 251 * ATM ARP [c.f. if_ether.c]). 252 */ 253 254 sdl = satocsdl(rt->rt_gateway); 255 256 /* 257 * Check the address family and length is valid, the address 258 * is resolved; otherwise, try to resolve. 259 */ 260 261 262 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen == sizeof(*desten)) { 263 memcpy(desten, CLLADDR(sdl), sdl->sdl_alen); 264 return (1); /* ok, go for it! */ 265 } 266 267 /* 268 * we got an entry, but it doesn't have valid link address 269 * info in it (it is prob. the interface route, which has 270 * sdl_alen == 0). dump packet. (fall through to "bad"). 271 */ 272 273bad: 274 m_freem(m); 275 return (0); 276} 277#endif /* INET */ 278