1/*- 2 * Copyright (c) 2005-2006 Robert N. M. Watson 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 * 26 * Copyright (c) 1996 Charles D. Cranor and Washington University. 27 * All rights reserved. 28 * 29 * Redistribution and use in source and binary forms, with or without 30 * modification, are permitted provided that the following conditions 31 * are met: 32 * 1. Redistributions of source code must retain the above copyright 33 * notice, this list of conditions and the following disclaimer. 34 * 2. Redistributions in binary form must reproduce the above copyright 35 * notice, this list of conditions and the following disclaimer in the 36 * documentation and/or other materials provided with the distribution. 37 * 3. All advertising materials mentioning features or use of this software 38 * must display the following acknowledgement: 39 * This product includes software developed by Charles D. Cranor and 40 * Washington University. 41 * 4. The name of the author may not be used to endorse or promote products 42 * derived from this software without specific prior written permission. 43 * 44 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 45 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 46 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 47 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 48 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 49 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 50 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 51 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 52 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 53 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 54 * 55 * $NetBSD: natm.c,v 1.5 1996/11/09 03:26:26 chuck Exp $ 56 */ 57 58/* 59 * natm.c: Native mode ATM access (both aal0 and aal5). 60 */ 61 62#include <sys/cdefs.h> 63__FBSDID("$FreeBSD$"); 64 65#include <sys/param.h> 66#include <sys/conf.h> 67#include <sys/kernel.h> 68#include <sys/lock.h> 69#include <sys/malloc.h> 70#include <sys/mbuf.h> 71#include <sys/protosw.h> 72#include <sys/signalvar.h> 73#include <sys/socket.h> 74#include <sys/socketvar.h> 75#include <sys/sockio.h> 76#include <sys/sx.h> 77#include <sys/systm.h> 78#include <sys/sysctl.h> 79 80#include <net/if.h> 81#include <net/if_atm.h> 82#include <net/netisr.h> 83 84#include <netinet/in.h> 85 86#include <netnatm/natm.h> 87 88static const u_long natm5_sendspace = 16*1024; 89static const u_long natm5_recvspace = 16*1024; 90 91static const u_long natm0_sendspace = 16*1024; 92static const u_long natm0_recvspace = 16*1024; 93 94/* 95 * netnatm global subsystem lock, protects all global data structures in 96 * netnatm. 97 */ 98struct mtx natm_mtx; 99 100/* 101 * User socket requests. 102 */ 103static int natm_usr_attach(struct socket *, int, struct thread *); 104static void natm_usr_detach(struct socket *); 105static int natm_usr_connect(struct socket *, struct sockaddr *, 106 struct thread *); 107static int natm_usr_disconnect(struct socket *); 108static int natm_usr_shutdown(struct socket *); 109static int natm_usr_send(struct socket *, int, struct mbuf *, 110 struct sockaddr *, struct mbuf *, struct thread *); 111static int natm_usr_peeraddr(struct socket *, struct sockaddr **); 112static int natm_usr_control(struct socket *, u_long, caddr_t, 113 struct ifnet *, struct thread *); 114static void natm_usr_abort(struct socket *); 115static int natm_usr_bind(struct socket *, struct sockaddr *, 116 struct thread *); 117static int natm_usr_sockaddr(struct socket *, struct sockaddr **); 118 119static int 120natm_usr_attach(struct socket *so, int proto, struct thread *p) 121{ 122 struct natmpcb *npcb; 123 int error = 0; 124 125 npcb = (struct natmpcb *)so->so_pcb; 126 KASSERT(npcb == NULL, ("natm_usr_attach: so_pcb != NULL")); 127 128 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { 129 if (proto == PROTO_NATMAAL5) 130 error = soreserve(so, natm5_sendspace, 131 natm5_recvspace); 132 else 133 error = soreserve(so, natm0_sendspace, 134 natm0_recvspace); 135 if (error) 136 return (error); 137 } 138 so->so_pcb = npcb = npcb_alloc(M_WAITOK); 139 npcb->npcb_socket = so; 140 return (error); 141} 142 143static void 144natm_usr_detach(struct socket *so) 145{ 146 struct natmpcb *npcb; 147 148 npcb = (struct natmpcb *)so->so_pcb; 149 KASSERT(npcb != NULL, ("natm_usr_detach: npcb == NULL")); 150 151 NATM_LOCK(); 152 npcb_free(npcb, NPCB_DESTROY); /* drain */ 153 so->so_pcb = NULL; 154 NATM_UNLOCK(); 155} 156 157static int 158natm_usr_connect(struct socket *so, struct sockaddr *nam, struct thread *p) 159{ 160 struct natmpcb *npcb; 161 struct sockaddr_natm *snatm; 162 struct atmio_openvcc op; 163 struct ifnet *ifp; 164 int error = 0; 165 int proto = so->so_proto->pr_protocol; 166 167 npcb = (struct natmpcb *)so->so_pcb; 168 KASSERT(npcb != NULL, ("natm_usr_connect: npcb == NULL")); 169 170 /* 171 * Validate nam and npcb. 172 */ 173 NATM_LOCK(); 174 snatm = (struct sockaddr_natm *)nam; 175 if (snatm->snatm_len != sizeof(*snatm) || 176 (npcb->npcb_flags & NPCB_FREE) == 0) { 177 NATM_UNLOCK(); 178 return (EINVAL); 179 } 180 if (snatm->snatm_family != AF_NATM) { 181 NATM_UNLOCK(); 182 return (EAFNOSUPPORT); 183 } 184 185 snatm->snatm_if[IFNAMSIZ - 1] = '\0'; /* XXX ensure null termination 186 since ifunit() uses strcmp */ 187 188 /* 189 * Convert interface string to ifp, validate. 190 */ 191 ifp = ifunit(snatm->snatm_if); 192 if (ifp == NULL || (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) { 193 NATM_UNLOCK(); 194 return (ENXIO); 195 } 196 if (ifp->if_output != atm_output) { 197 NATM_UNLOCK(); 198 return (EAFNOSUPPORT); 199 } 200 201 /* 202 * Register us with the NATM PCB layer. 203 */ 204 if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) { 205 NATM_UNLOCK(); 206 return (EADDRINUSE); 207 } 208 209 /* 210 * Open the channel. 211 * 212 * XXXRW: Eventually desirable to hold mutex over ioctl? 213 */ 214 bzero(&op, sizeof(op)); 215 op.rxhand = npcb; 216 op.param.flags = ATMIO_FLAG_PVC; 217 op.param.vpi = npcb->npcb_vpi; 218 op.param.vci = npcb->npcb_vci; 219 op.param.rmtu = op.param.tmtu = ifp->if_mtu; 220 op.param.aal = (proto == PROTO_NATMAAL5) ? ATMIO_AAL_5 : ATMIO_AAL_0; 221 op.param.traffic = ATMIO_TRAFFIC_UBR; 222 NATM_UNLOCK(); 223 224 if (ifp->if_ioctl == NULL || 225 ifp->if_ioctl(ifp, SIOCATMOPENVCC, (caddr_t)&op) != 0) 226 return (EIO); 227 soisconnected(so); 228 return (error); 229} 230 231static int 232natm_usr_disconnect(struct socket *so) 233{ 234 struct natmpcb *npcb; 235 struct atmio_closevcc cl; 236 struct ifnet *ifp; 237 int error = 0; 238 239 npcb = (struct natmpcb *)so->so_pcb; 240 KASSERT(npcb != NULL, ("natm_usr_disconnect: npcb == NULL")); 241 242 NATM_LOCK(); 243 if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) { 244 NATM_UNLOCK(); 245 printf("natm: disconnected check\n"); 246 return (EIO); 247 } 248 ifp = npcb->npcb_ifp; 249 250 /* 251 * Disable rx. 252 * 253 * XXXRW: Eventually desirable to hold mutex over ioctl? 254 */ 255 cl.vpi = npcb->npcb_vpi; 256 cl.vci = npcb->npcb_vci; 257 NATM_UNLOCK(); 258 if (ifp->if_ioctl != NULL) 259 ifp->if_ioctl(ifp, SIOCATMCLOSEVCC, (caddr_t)&cl); 260 soisdisconnected(so); 261 return (error); 262} 263 264static int 265natm_usr_shutdown(struct socket *so) 266{ 267 268 socantsendmore(so); 269 return (0); 270} 271 272static int 273natm_usr_send(struct socket *so, int flags, struct mbuf *m, 274 struct sockaddr *nam, struct mbuf *control, struct thread *p) 275{ 276 struct natmpcb *npcb; 277 struct atm_pseudohdr *aph; 278 int error = 0; 279 int proto = so->so_proto->pr_protocol; 280 281 npcb = (struct natmpcb *)so->so_pcb; 282 KASSERT(npcb != NULL, ("natm_usr_send: npcb == NULL")); 283 284 NATM_LOCK(); 285 if (control && control->m_len) { 286 NATM_UNLOCK(); 287 m_freem(control); 288 m_freem(m); 289 return (EINVAL); 290 } 291 292 /* 293 * Send the data. We must put an atm_pseudohdr on first. 294 */ 295 M_PREPEND(m, sizeof(*aph), M_NOWAIT); 296 if (m == NULL) { 297 NATM_UNLOCK(); 298 m_freem(control); 299 return (ENOBUFS); 300 } 301 aph = mtod(m, struct atm_pseudohdr *); 302 ATM_PH_VPI(aph) = npcb->npcb_vpi; 303 ATM_PH_SETVCI(aph, npcb->npcb_vci); 304 ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0; 305 error = atm_output(npcb->npcb_ifp, m, NULL, NULL); 306 NATM_UNLOCK(); 307 return (error); 308} 309 310static int 311natm_usr_peeraddr(struct socket *so, struct sockaddr **nam) 312{ 313 struct natmpcb *npcb; 314 struct sockaddr_natm *snatm, ssnatm; 315 316 npcb = (struct natmpcb *)so->so_pcb; 317 KASSERT(npcb != NULL, ("natm_usr_peeraddr: npcb == NULL")); 318 319 NATM_LOCK(); 320 snatm = &ssnatm; 321 bzero(snatm, sizeof(*snatm)); 322 snatm->snatm_len = sizeof(*snatm); 323 snatm->snatm_family = AF_NATM; 324 strlcpy(snatm->snatm_if, npcb->npcb_ifp->if_xname, 325 sizeof(snatm->snatm_if)); 326 snatm->snatm_vci = npcb->npcb_vci; 327 snatm->snatm_vpi = npcb->npcb_vpi; 328 NATM_UNLOCK(); 329 *nam = sodupsockaddr((struct sockaddr *)snatm, M_WAITOK); 330 return (0); 331} 332 333static int 334natm_usr_control(struct socket *so, u_long cmd, caddr_t arg, 335 struct ifnet *ifp, struct thread *p) 336{ 337 struct natmpcb *npcb; 338 339 npcb = (struct natmpcb *)so->so_pcb; 340 KASSERT(npcb != NULL, ("natm_usr_control: npcb == NULL")); 341 342 switch (cmd) { 343 case SIOCSIFADDR: 344 case SIOCSIFBRDADDR: 345 case SIOCSIFDSTADDR: 346 case SIOCSIFNETMASK: 347 /* 348 * Although we should pass any non-ATM ioctl requests 349 * down to driver, we filter some legacy INET requests. 350 * Drivers trust SIOCSIFADDR et al to come from an already 351 * privileged layer, and do not perform any credentials 352 * checks or input validation. 353 */ 354 return (EINVAL); 355 } 356 357 if (ifp == NULL || ifp->if_ioctl == NULL) 358 return (EOPNOTSUPP); 359 return ((*ifp->if_ioctl)(ifp, cmd, arg)); 360} 361 362static void 363natm_usr_abort(struct socket *so) 364{ 365 366} 367 368static void 369natm_usr_close(struct socket *so) 370{ 371 372} 373 374static int 375natm_usr_bind(struct socket *so, struct sockaddr *nam, struct thread *p) 376{ 377 378 return (EOPNOTSUPP); 379} 380 381static int 382natm_usr_sockaddr(struct socket *so, struct sockaddr **nam) 383{ 384 385 return (EOPNOTSUPP); 386} 387 388/* xxx - should be const */ 389struct pr_usrreqs natm_usrreqs = { 390 .pru_abort = natm_usr_abort, 391 .pru_attach = natm_usr_attach, 392 .pru_bind = natm_usr_bind, 393 .pru_connect = natm_usr_connect, 394 .pru_control = natm_usr_control, 395 .pru_detach = natm_usr_detach, 396 .pru_disconnect = natm_usr_disconnect, 397 .pru_peeraddr = natm_usr_peeraddr, 398 .pru_send = natm_usr_send, 399 .pru_shutdown = natm_usr_shutdown, 400 .pru_sockaddr = natm_usr_sockaddr, 401 .pru_close = natm_usr_close, 402}; 403 404/* 405 * natmintr: interrupt 406 * 407 * Note: we expect a socket pointer in rcvif rather than an interface 408 * pointer. We can get the interface pointer from the so's PCB if we really 409 * need it. 410 */ 411void 412natmintr(struct mbuf *m) 413{ 414 struct socket *so; 415 struct natmpcb *npcb; 416 417#ifdef DIAGNOSTIC 418 M_ASSERTPKTHDR(m); 419#endif 420 421 NATM_LOCK(); 422 npcb = (struct natmpcb *)m->m_pkthdr.rcvif; /* XXX: overloaded */ 423 so = npcb->npcb_socket; 424 425 npcb->npcb_inq--; 426 427 if (npcb->npcb_flags & NPCB_DRAIN) { 428 if (npcb->npcb_inq == 0) 429 free(npcb, M_PCB); /* done! */ 430 NATM_UNLOCK(); 431 m_freem(m); 432 return; 433 } 434 435 if (npcb->npcb_flags & NPCB_FREE) { 436 NATM_UNLOCK(); 437 m_freem(m); /* drop */ 438 return; 439 } 440 441#ifdef NEED_TO_RESTORE_IFP 442 m->m_pkthdr.rcvif = npcb->npcb_ifp; 443#else 444#ifdef DIAGNOSTIC 445 m->m_pkthdr.rcvif = NULL; /* null it out to be safe */ 446#endif 447#endif 448 449 if (sbspace(&so->so_rcv) > m->m_pkthdr.len) { 450#ifdef NATM_STAT 451 natm_sookcnt++; 452 natm_sookbytes += m->m_pkthdr.len; 453#endif 454 sbappendrecord(&so->so_rcv, m); 455 sorwakeup(so); 456 NATM_UNLOCK(); 457 } else { 458#ifdef NATM_STAT 459 natm_sodropcnt++; 460 natm_sodropbytes += m->m_pkthdr.len; 461#endif 462 NATM_UNLOCK(); 463 m_freem(m); 464 } 465} 466 467/* 468 * natm0_sysctl: not used, but here in case we want to add something 469 * later... 470 */ 471int 472natm0_sysctl(SYSCTL_HANDLER_ARGS) 473{ 474 475 /* All sysctl names at this level are terminal. */ 476 return (ENOENT); 477} 478 479/* 480 * natm5_sysctl: not used, but here in case we want to add something 481 * later... 482 */ 483int 484natm5_sysctl(SYSCTL_HANDLER_ARGS) 485{ 486 487 /* All sysctl names at this level are terminal. */ 488 return (ENOENT); 489} 490