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_var.h> 56#include <net/if_dl.h> 57#include <net/route.h> 58#include <net/if_atm.h> 59 60#include <netinet/in.h> 61#include <netinet/if_atm.h> 62 63#ifdef NATM 64#include <netnatm/natm.h> 65#endif 66 67#define SDL(s) ((struct sockaddr_dl *)s) 68 69#define GET3BYTE(V, A, L) do { \ 70 (V) = ((A)[0] << 16) | ((A)[1] << 8) | (A)[2]; \ 71 (A) += 3; \ 72 (L) -= 3; \ 73 } while (0) 74 75#define GET2BYTE(V, A, L) do { \ 76 (V) = ((A)[0] << 8) | (A)[1]; \ 77 (A) += 2; \ 78 (L) -= 2; \ 79 } while (0) 80 81#define GET1BYTE(V, A, L) do { \ 82 (V) = *(A)++; \ 83 (L)--; \ 84 } while (0) 85 86 87/* 88 * atm_rtrequest: handle ATM rt request (in support of generic code) 89 * inputs: "req" = request code 90 * "rt" = route entry 91 * "info" = rt_addrinfo 92 */ 93void 94atm_rtrequest(int req, struct rtentry *rt, struct rt_addrinfo *info) 95{ 96 struct sockaddr *gate = rt->rt_gateway; 97 struct atmio_openvcc op; 98 struct atmio_closevcc cl; 99 u_char *addr; 100 u_int alen; 101#ifdef NATM 102 struct sockaddr_in *sin; 103 struct natmpcb *npcb = NULL; 104#endif 105 static struct sockaddr_dl null_sdl = {sizeof(null_sdl), AF_LINK}; 106 107 if (rt->rt_flags & RTF_GATEWAY) /* link level requests only */ 108 return; 109 110 switch (req) { 111 112 case RTM_RESOLVE: /* resolve: only happens when cloning */ 113 printf("atm_rtrequest: RTM_RESOLVE request detected?\n"); 114 break; 115 116 case RTM_ADD: 117 /* 118 * route added by a command (e.g. ifconfig, route, arp...). 119 * 120 * first check to see if this is not a host route, in which 121 * case we are being called via "ifconfig" to set the address. 122 */ 123 if ((rt->rt_flags & RTF_HOST) == 0) { 124 rt_setgate(rt,rt_key(rt),(struct sockaddr *)&null_sdl); 125 gate = rt->rt_gateway; 126 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 127 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 128 break; 129 } 130 131 if (gate->sa_family != AF_LINK || 132 gate->sa_len < sizeof(null_sdl)) { 133 log(LOG_DEBUG, "atm_rtrequest: bad gateway value"); 134 break; 135 } 136 137 KASSERT(rt->rt_ifp->if_ioctl != NULL, 138 ("atm_rtrequest: null ioctl")); 139 140 /* 141 * Parse and verify the link level address as 142 * an open request 143 */ 144#ifdef NATM 145 NATM_LOCK(); 146#endif 147 bzero(&op, sizeof(op)); 148 addr = LLADDR(SDL(gate)); 149 alen = SDL(gate)->sdl_alen; 150 if (alen < 4) { 151 printf("%s: bad link-level address\n", __func__); 152 goto failed; 153 } 154 155 if (alen == 4) { 156 /* old type address */ 157 GET1BYTE(op.param.flags, addr, alen); 158 GET1BYTE(op.param.vpi, addr, alen); 159 GET2BYTE(op.param.vci, addr, alen); 160 op.param.traffic = ATMIO_TRAFFIC_UBR; 161 op.param.aal = (op.param.flags & ATM_PH_AAL5) ? 162 ATMIO_AAL_5 : ATMIO_AAL_0; 163 } else { 164 /* new address */ 165 op.param.aal = ATMIO_AAL_5; 166 167 GET1BYTE(op.param.flags, addr, alen); 168 op.param.flags &= ATM_PH_LLCSNAP; 169 170 GET1BYTE(op.param.vpi, addr, alen); 171 GET2BYTE(op.param.vci, addr, alen); 172 173 GET1BYTE(op.param.traffic, addr, alen); 174 175 switch (op.param.traffic) { 176 177 case ATMIO_TRAFFIC_UBR: 178 if (alen >= 3) 179 GET3BYTE(op.param.tparam.pcr, 180 addr, alen); 181 break; 182 183 case ATMIO_TRAFFIC_CBR: 184 if (alen < 3) 185 goto bad_param; 186 GET3BYTE(op.param.tparam.pcr, addr, alen); 187 break; 188 189 case ATMIO_TRAFFIC_VBR: 190 if (alen < 3 * 3) 191 goto bad_param; 192 GET3BYTE(op.param.tparam.pcr, addr, alen); 193 GET3BYTE(op.param.tparam.scr, addr, alen); 194 GET3BYTE(op.param.tparam.mbs, addr, alen); 195 break; 196 197 case ATMIO_TRAFFIC_ABR: 198 if (alen < 4 * 3 + 2 + 1 * 2 + 3) 199 goto bad_param; 200 GET3BYTE(op.param.tparam.pcr, addr, alen); 201 GET3BYTE(op.param.tparam.mcr, addr, alen); 202 GET3BYTE(op.param.tparam.icr, addr, alen); 203 GET3BYTE(op.param.tparam.tbe, addr, alen); 204 GET1BYTE(op.param.tparam.nrm, addr, alen); 205 GET1BYTE(op.param.tparam.trm, addr, alen); 206 GET2BYTE(op.param.tparam.adtf, addr, alen); 207 GET1BYTE(op.param.tparam.rif, addr, alen); 208 GET1BYTE(op.param.tparam.rdf, addr, alen); 209 GET1BYTE(op.param.tparam.cdf, addr, alen); 210 break; 211 212 default: 213 bad_param: 214 printf("%s: bad traffic params\n", __func__); 215 goto failed; 216 } 217 } 218 op.param.rmtu = op.param.tmtu = rt->rt_ifp->if_mtu; 219#ifdef NATM 220 /* 221 * let native ATM know we are using this VCI/VPI 222 * (i.e. reserve it) 223 */ 224 sin = (struct sockaddr_in *) rt_key(rt); 225 if (sin->sin_family != AF_INET) 226 goto failed; 227 npcb = npcb_add(NULL, rt->rt_ifp, op.param.vci, op.param.vpi); 228 if (npcb == NULL) 229 goto failed; 230 npcb->npcb_flags |= NPCB_IP; 231 npcb->ipaddr.s_addr = sin->sin_addr.s_addr; 232 /* XXX: move npcb to llinfo when ATM ARP is ready */ 233#ifdef __notyet_restored__ 234 rt->rt_llinfo = (caddr_t) npcb; 235#endif 236 rt->rt_flags |= RTF_LLINFO; 237#endif 238 /* 239 * let the lower level know this circuit is active 240 */ 241 op.rxhand = NULL; 242 op.param.flags |= ATMIO_FLAG_ASYNC; 243 if (rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMOPENVCC, 244 (caddr_t)&op) != 0) { 245 printf("atm: couldn't add VC\n"); 246 goto failed; 247 } 248 249 SDL(gate)->sdl_type = rt->rt_ifp->if_type; 250 SDL(gate)->sdl_index = rt->rt_ifp->if_index; 251 252#ifdef NATM 253 NATM_UNLOCK(); 254#endif 255 break; 256 257failed: 258#ifdef NATM 259 if (npcb) { 260 npcb_free(npcb, NPCB_DESTROY); 261#ifdef __notyet_restored__ 262 rt->rt_llinfo = NULL; 263#endif 264 rt->rt_flags &= ~RTF_LLINFO; 265 } 266 NATM_UNLOCK(); 267#endif 268 /* mark as invalid. We cannot RTM_DELETE the route from 269 * here, because the recursive call to rtrequest1 does 270 * not really work. */ 271 rt->rt_flags |= RTF_REJECT; 272 break; 273 274 case RTM_DELETE: 275#ifdef NATM 276 /* 277 * tell native ATM we are done with this VC 278 */ 279 if (rt->rt_flags & RTF_LLINFO) { 280 NATM_LOCK(); 281#ifdef __notyet_restored__ 282 npcb_free((struct natmpcb *)rt->rt_llinfo, 283 NPCB_DESTROY); 284 rt->rt_llinfo = NULL; 285#endif 286 rt->rt_flags &= ~RTF_LLINFO; 287 NATM_UNLOCK(); 288 } 289#endif 290 /* 291 * tell the lower layer to disable this circuit 292 */ 293 bzero(&op, sizeof(op)); 294 addr = LLADDR(SDL(gate)); 295 addr++; 296 cl.vpi = *addr++; 297 cl.vci = *addr++ << 8; 298 cl.vci |= *addr++; 299 (void)rt->rt_ifp->if_ioctl(rt->rt_ifp, SIOCATMCLOSEVCC, 300 (caddr_t)&cl); 301 break; 302 } 303} 304 305/* 306 * atmresolve: 307 * inputs: 308 * [1] "rt" = the link level route to use (or null if need to look one up) 309 * [2] "m" = mbuf containing the data to be sent 310 * [3] "dst" = sockaddr_in (IP) address of dest. 311 * output: 312 * [4] "desten" = ATM pseudo header which we will fill in VPI/VCI info 313 * return: 314 * 0 == resolve FAILED; note that "m" gets m_freem'd in this case 315 * 1 == resolve OK; desten contains result 316 * 317 * XXX: will need more work if we wish to support ATMARP in the kernel, 318 * but this is enough for PVCs entered via the "route" command. 319 */ 320int 321atmresolve(struct rtentry *rt, struct mbuf *m, const struct sockaddr *dst, 322 struct atm_pseudohdr *desten) 323{ 324 struct sockaddr_dl *sdl; 325 326 if (m->m_flags & (M_BCAST | M_MCAST)) { 327 log(LOG_INFO, 328 "atmresolve: BCAST/MCAST packet detected/dumped\n"); 329 goto bad; 330 } 331 332 if (rt == NULL) { 333 /* link level on table 0 XXX MRT */ 334 rt = RTALLOC1(__DECONST(struct sockaddr *, dst), 0); 335 if (rt == NULL) 336 goto bad; /* failed */ 337 RT_REMREF(rt); /* don't keep LL references */ 338 if ((rt->rt_flags & RTF_GATEWAY) != 0 || 339 rt->rt_gateway->sa_family != AF_LINK) { 340 RT_UNLOCK(rt); 341 goto bad; 342 } 343 RT_UNLOCK(rt); 344 } 345 346 /* 347 * note that rt_gateway is a sockaddr_dl which contains the 348 * atm_pseudohdr data structure for this route. we currently 349 * don't need any rt_llinfo info (but will if we want to support 350 * ATM ARP [c.f. if_ether.c]). 351 */ 352 sdl = SDL(rt->rt_gateway); 353 354 /* 355 * Check the address family and length is valid, the address 356 * is resolved; otherwise, try to resolve. 357 */ 358 if (sdl->sdl_family == AF_LINK && sdl->sdl_alen >= sizeof(*desten)) { 359 bcopy(LLADDR(sdl), desten, sizeof(*desten)); 360 return (1); /* ok, go for it! */ 361 } 362 363 /* 364 * we got an entry, but it doesn't have valid link address 365 * info in it (it is prob. the interface route, which has 366 * sdl_alen == 0). dump packet. (fall through to "bad"). 367 */ 368bad: 369 m_freem(m); 370 return (0); 371} 372#endif /* INET */ 373