1/* $NetBSD: if_atm.c,v 1.6 1996/10/13 02:03:01 christos Exp $ */ 2 3/*- 4 * 5 * Copyright (c) 1996 Charles D. Cranor and Washington University. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by Charles D. Cranor and 19 * Washington University. 20 * 4. The name of the author may not be used to endorse or promote products 21 * derived from this software without specific prior written permission. 22 * 23 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 24 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 25 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 26 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 27 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 28 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 29 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 30 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 31 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 32 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 33 */ 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD$"); 36 37/* 38 * IP <=> ATM address resolution. 39 */ 40#include "opt_inet.h" 41#include "opt_inet6.h" 42#include "opt_natm.h" 43 44#if defined(INET) || defined(INET6) 45 46#include <sys/param.h> 47#include <sys/systm.h> 48#include <sys/queue.h> 49#include <sys/mbuf.h> 50#include <sys/socket.h> 51#include <sys/sockio.h> 52#include <sys/syslog.h> 53 54#include <net/if.h> 55#include <net/if_dl.h> 56#include <net/route.h> 57#include <net/if_atm.h> 58 59#include <netinet/in.h> 60#include <netinet/if_atm.h> 61 62#ifdef NATM 63#include <netnatm/natm.h> 64#endif 65 66#define SDL(s) ((struct sockaddr_dl *)s) 67 68#define GET3BYTE(V, A, L) do { \ 69 (V) = ((A)[0] << 16) | ((A)[1] << 8) | (A)[2]; \ 70 (A) += 3; \ 71 (L) -= 3; \ 72 } while (0) 73 74#define GET2BYTE(V, A, L) do { \ 75 (V) = ((A)[0] << 8) | (A)[1]; \ 76 (A) += 2; \ 77 (L) -= 2; \ 78 } while (0) 79 80#define GET1BYTE(V, A, L) do { \ 81 (V) = *(A)++; \ 82 (L)--; \ 83 } while (0) 84 85 86/* 87 * atm_rtrequest: handle ATM rt request (in support of generic code) 88 * inputs: "req" = request code 89 * "rt" = route entry 90 * "info" = rt_addrinfo 91 */ 92void 93atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) 94{ 95 struct sockaddr *gate = rt->rt_gateway; 96 struct atmio_openvcc op; 97 struct atmio_closevcc cl; 98 u_char *addr; 99 u_int alen; 100#ifdef NATM 101 struct sockaddr_in *sin; 102 struct natmpcb *npcb = NULL; 103#endif 104 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 105 106 if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ 107 return; 108 109 switch (req) { 110 111 case RTM_RESOLVE: /* resolve: only happens when cloning */ 112 printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); 113 break; 114 115 case RTM_ADD: 116 /* 117 * route added by a command (e.g. ifconfig, route, arp...). 118 * 119 * first check to see if this is not a host route, in which 120 * case we are being called via "ifconfig" to set the address. 121 */ 122 if ((rt->rt_flags & RTF_HOST) == 0) { 123 rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl); 124 gate = rt->rt_gateway; 125 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 126 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 127 break; 128 } 129 130 if (gate->sa_family != AF_LINK || 131 gate->sa_len < sizeof(null_sdl)) { 132 log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); 133 break; 134 } 135 136 KASSERT(rt->rt_ifp->if_ioctl != NULL, 137 ("atm_rtrequest: null ioctl")); 138 139 /* 140 * Parse and verify the link level address as 141 * an open request 142 */ 143#ifdef NATM 144 NATM_LOCK(); 145#endif 146 bzero(&op, sizeof(op)); 147 addr = LLADDR(SDL(gate)); 148 alen = SDL(gate)->sdl_alen; 149 if (alen < 4) { 150 printf("%s: bad link-level address\n", __func__); 151 goto failed; 152 } 153 154 if (alen == 4) { 155 /* old type address */ 156 GET1BYTE(op.param.flags, addr, alen); 157 GET1BYTE(op.param.vpi, addr, alen); 158 GET2BYTE(op.param.vci, addr, alen); 159 op.param.traffic = ATMIO_TRAFFIC_UBR; 160 op.param.aal = (op.param.flags & ATM_PH_AAL5) ? 161 ATMIO_AAL_5 : ATMIO_AAL_0; 162 } else { 163 /* new address */ 164 op.param.aal = ATMIO_AAL_5; 165 166 GET1BYTE(op.param.flags, addr, alen); 167 op.param.flags &= ATM_PH_LLCSNAP; 168 169 GET1BYTE(op.param.vpi, addr, alen); 170 GET2BYTE(op.param.vci, addr, alen); 171 172 GET1BYTE(op.param.traffic, addr, alen); 173 174 switch (op.param.traffic) { 175 176 case ATMIO_TRAFFIC_UBR: 177 if (alen >= 3) 178 GET3BYTE(op.param.tparam.pcr, 179 addr, alen); 180 break; 181 182 case ATMIO_TRAFFIC_CBR: 183 if (alen < 3) 184 goto bad_param; 185 GET3BYTE(op.param.tparam.pcr, addr, alen); 186 break; 187 188 case ATMIO_TRAFFIC_VBR: 189 if (alen < 3 * 3) 190 goto bad_param; 191 GET3BYTE(op.param.tparam.pcr, addr, alen); 192 GET3BYTE(op.param.tparam.scr, addr, alen); 193 GET3BYTE(op.param.tparam.mbs, addr, alen); 194 break; 195 196 case ATMIO_TRAFFIC_ABR: 197 if (alen < 4 * 3 + 2 + 1 * 2 + 3) 198 goto bad_param; 199 GET3BYTE(op.param.tparam.pcr, addr, alen); 200 GET3BYTE(op.param.tparam.mcr, addr, alen); 201 GET3BYTE(op.param.tparam.icr, addr, alen); 202 GET3BYTE(op.param.tparam.tbe, addr, alen); 203 GET1BYTE(op.param.tparam.nrm, addr, alen); 204 GET1BYTE(op.param.tparam.trm, addr, alen); 205 GET2BYTE(op.param.tparam.adtf, addr, alen); 206 GET1BYTE(op.param.tparam.rif, addr, alen); 207 GET1BYTE(op.param.tparam.rdf, addr, alen); 208 GET1BYTE(op.param.tparam.cdf, addr, alen); 209 break; 210 211 default: 212 bad_param: 213 printf("%s: bad traffic params\n", __func__); 214 goto failed; 215 } 216 } 217 op.param.rmtu = op.param.tmtu = rt->rt_ifp->if_mtu; 218#ifdef NATM 219 /* 220 * let native ATM know we are using this VCI/VPI 221 * (i.e. reserve it) 222 */ 223 sin = (struct sockaddr_in *) rt_key(rt); 224 if (sin->sin_family != AF_INET) 225 goto failed; 226 npcb = npcb_add(NULL, rt->rt_ifp, op.param.vci, op.param.vpi); 227 if (npcb == NULL) 228 goto failed; 229 npcb->npcb_flags |= NPCB_IP; 230 npcb->ipaddr.s_addr = sin->sin_addr.s_addr; 231 /* XXX: move npcb to llinfo when ATM ARP is ready */ 232#ifdef __notyet_restored__ 233 rt->rt_llinfo = (caddr_t) npcb; 234#endif 235 rt->rt_flags |= RTF_LLINFO; 236#endif 237 /* 238 * let the lower level know this circuit is active 239 */ 240 op.rxhand = NULL; 241 op.param.flags |= ATMIO_FLAG_ASYNC; 242 if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMOPENVCC, 243 (caddr_t)&op) != 0) { 244 printf("atm: couldn't add VC\n"); 245 goto failed; 246 } 247 248 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 249 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 250 251#ifdef NATM 252 NATM_UNLOCK(); 253#endif 254 break; 255 256failed: 257#ifdef NATM 258 if (npcb) { 259 npcb_free(npcb, NPCB_DESTROY); 260#ifdef __notyet_restored__ 261 rt->rt_llinfo = NULL; 262#endif 263 rt->rt_flags &= ~RTF_LLINFO; 264 } 265 NATM_UNLOCK(); 266#endif 267 /* mark as invalid. We cannot RTM_DELETE the route from 268 * here, because the recursive call to rtrequest1 does 269 * not really work. */ 270 rt->rt_flags |= RTF_REJECT; 271 break; 272 273 case RTM_DELETE: 274#ifdef NATM 275 /* 276 * tell native ATM we are done with this VC 277 */ 278 if (rt->rt_flags & RTF_LLINFO) { 279 NATM_LOCK(); 280#ifdef __notyet_restored__ 281 npcb_free((struct natmpcb *)rt->rt_llinfo, 282 NPCB_DESTROY); 283 rt->rt_llinfo = NULL; 284#endif 285 rt->rt_flags &= ~RTF_LLINFO; 286 NATM_UNLOCK(); 287 } 288#endif 289 /* 290 * tell the lower layer to disable this circuit 291 */ 292 bzero(&op, sizeof(op)); 293 addr = LLADDR(SDL(gate)); 294 addr++; 295 cl.vpi = *addr++; 296 cl.vci = *addr++ << 8; 297 cl.vci |= *addr++; 298 (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMCLOSEVCC, 299 (caddr_t)&cl); 300 break; 301 } 302} 303 304/* 305 * atmresolve: 306 * inputs: 307 * [1] "rt" = the link level route to use (or null if need to look one up) 308 * [2] "m" = mbuf containing the data to be sent 309 * [3] "dst" = sockaddr_in (IP) address of dest. 310 * output: 311 * [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info 312 * return: 313 * 0 == resolve FAILED; note that "m" gets m_freem'd in this case 314 * 1 == resolve OK; desten contains result 315 * 316 * XXX: will need more work if we wish to support ATMARP in the kernel, 317 * but this is enough for PVCs entered via the "route" command. 318 */ 319int 320atmresolve(struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, 321 struct atm_pseudohdr *desten) 322{ 323 struct sockaddr_dl *sdl; 324 325 if (m->m_flags & (M_BCAST | M_MCAST)) { 326 log(LOG_INFO, 327 "atmresolve: BCAST/MCAST packet detected/dumped\n"); 328 goto bad; 329 } 330 331 if (rt == NULL) { 332 /* link level on table 0 XXX MRT */ 333 rt = RTALLOC1(__DECONST(struct sockaddr *, dst), 0); 334 if (rt == NULL) 335 goto bad; /* failed */ 336 RT_REMREF(rt); /* don't keep LL references */ 337 if ((rt->rt_flags & RTF_GATEWAY) != 0 || 338 rt->rt_gateway->sa_family != AF_LINK) { 339 RT_UNLOCK(rt); 340 goto bad; 341 } 342 RT_UNLOCK(rt); 343 } 344 345 /* 346 * note that rt_gateway is a sockaddr_dl which contains the 347 * atm_pseudohdr data structure for this route. we currently 348 * don't need any rt_llinfo info (but will if we want to support 349 * ATM ARP [c.f. if_ether.c]). 350 */ 351 sdl = SDL(rt->rt_gateway); 352 353 /* 354 * Check the address family and length is valid, the address 355 * is resolved; otherwise, try to resolve. 356 */ 357 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen >= sizeof(*desten)) { 358 bcopy(LLADDR(sdl), desten, sizeof(*desten)); 359 return (1); /* ok, go for it! */ 360 } 361 362 /* 363 * we got an entry, but it doesn't have valid link address 364 * info in it (it is prob. the interface route, which has 365 * sdl_alen == 0). dump packet. (fall through to "bad"). 366 */ 367bad: 368 m_freem(m); 369 return (0); 370} 371#endif /* INET */ 372