Annotation of sys/netnatm/natm.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: natm.c,v 1.7 2006/03/04 22:40:16 brad 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:
! 35: /*
! 36: * natm.c: native mode ATM access (both aal0 and aal5).
! 37: */
! 38:
! 39: #include <sys/param.h>
! 40: #include <sys/systm.h>
! 41: #include <sys/kernel.h>
! 42: #include <sys/domain.h>
! 43: #include <sys/ioctl.h>
! 44: #include <sys/proc.h>
! 45: #include <sys/protosw.h>
! 46: #include <sys/mbuf.h>
! 47: #include <sys/socket.h>
! 48: #include <sys/socketvar.h>
! 49:
! 50: #include <net/if.h>
! 51: #include <net/if_atm.h>
! 52: #include <net/netisr.h>
! 53: #include <net/radix.h>
! 54: #include <net/route.h>
! 55:
! 56: #include <netinet/in.h>
! 57:
! 58: #include <netnatm/natm.h>
! 59:
! 60: u_long natm5_sendspace = 16*1024;
! 61: u_long natm5_recvspace = 16*1024;
! 62:
! 63: u_long natm0_sendspace = 16*1024;
! 64: u_long natm0_recvspace = 16*1024;
! 65:
! 66: /*
! 67: * user requests
! 68: */
! 69:
! 70: #if defined(__NetBSD__)
! 71: int natm_usrreq(so, req, m, nam, control)
! 72: #elif defined(__OpenBSD__) || defined(__FreeBSD__)
! 73: int natm_usrreq(so, req, m, nam, control)
! 74: #endif
! 75: struct socket *so;
! 76: int req;
! 77: struct mbuf *m, *nam, *control;
! 78: #if defined(__NetBSD__)
! 79: struct proc *p;
! 80: #endif
! 81: {
! 82: int error = 0, s, s2;
! 83: struct natmpcb *npcb;
! 84: struct sockaddr_natm *snatm;
! 85: struct atm_pseudoioctl api;
! 86: struct atm_pseudohdr *aph;
! 87: struct atm_rawioctl ario;
! 88: struct ifnet *ifp;
! 89: int proto = so->so_proto->pr_protocol;
! 90:
! 91: s = SPLSOFTNET();
! 92:
! 93: npcb = (struct natmpcb *) so->so_pcb;
! 94:
! 95: if (npcb == NULL && req != PRU_ATTACH) {
! 96: error = EINVAL;
! 97: goto done;
! 98: }
! 99:
! 100:
! 101: switch (req) {
! 102: case PRU_ATTACH: /* attach protocol to up */
! 103:
! 104: if (npcb) {
! 105: error = EISCONN;
! 106: break;
! 107: }
! 108:
! 109: if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) {
! 110: if (proto == PROTO_NATMAAL5)
! 111: error = soreserve(so, natm5_sendspace, natm5_recvspace);
! 112: else
! 113: error = soreserve(so, natm0_sendspace, natm0_recvspace);
! 114: if (error)
! 115: break;
! 116: }
! 117:
! 118: so->so_pcb = (caddr_t) (npcb = npcb_alloc(M_WAITOK));
! 119: npcb->npcb_socket = so;
! 120:
! 121: break;
! 122:
! 123: case PRU_DETACH: /* detach protocol from up */
! 124:
! 125: /*
! 126: * we turn on 'drain' *before* we sofree.
! 127: */
! 128:
! 129: npcb_free(npcb, NPCB_DESTROY); /* drain */
! 130: so->so_pcb = NULL;
! 131: sofree(so);
! 132:
! 133: break;
! 134:
! 135: case PRU_CONNECT: /* establish connection to peer */
! 136:
! 137: /*
! 138: * validate nam and npcb
! 139: */
! 140:
! 141: if (nam->m_len != sizeof(*snatm)) {
! 142: error = EINVAL;
! 143: break;
! 144: }
! 145: snatm = mtod(nam, struct sockaddr_natm *);
! 146: if (snatm->snatm_len != sizeof(*snatm) ||
! 147: (npcb->npcb_flags & NPCB_FREE) == 0) {
! 148: error = EINVAL;
! 149: break;
! 150: }
! 151: if (snatm->snatm_family != AF_NATM) {
! 152: error = EAFNOSUPPORT;
! 153: break;
! 154: }
! 155:
! 156: snatm->snatm_if[IFNAMSIZ-1] = '\0'; /* XXX ensure null termination
! 157: since ifunit() uses strcmp */
! 158:
! 159: /*
! 160: * convert interface string to ifp, validate.
! 161: */
! 162:
! 163: ifp = ifunit(snatm->snatm_if);
! 164: if (ifp == NULL || (ifp->if_flags & IFF_RUNNING) == 0) {
! 165: error = ENXIO;
! 166: break;
! 167: }
! 168: if (ifp->if_output != atm_output) {
! 169: error = EAFNOSUPPORT;
! 170: break;
! 171: }
! 172:
! 173:
! 174: /*
! 175: * register us with the NATM PCB layer
! 176: */
! 177:
! 178: if (npcb_add(npcb, ifp, snatm->snatm_vci, snatm->snatm_vpi) != npcb) {
! 179: error = EADDRINUSE;
! 180: break;
! 181: }
! 182:
! 183: /*
! 184: * enable rx
! 185: */
! 186:
! 187: ATM_PH_FLAGS(&api.aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
! 188: ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
! 189: ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
! 190: api.rxhand = npcb;
! 191: s2 = splnet();
! 192: if (ifp->if_ioctl == NULL ||
! 193: ifp->if_ioctl(ifp, SIOCATMENA, (caddr_t) &api) != 0) {
! 194: splx(s2);
! 195: npcb_free(npcb, NPCB_REMOVE);
! 196: error = EIO;
! 197: break;
! 198: }
! 199: splx(s2);
! 200:
! 201: soisconnected(so);
! 202:
! 203: break;
! 204:
! 205: case PRU_DISCONNECT: /* disconnect from peer */
! 206:
! 207: if ((npcb->npcb_flags & NPCB_CONNECTED) == 0) {
! 208: printf("natm: disconnected check\n");
! 209: error = EIO;
! 210: break;
! 211: }
! 212: ifp = npcb->npcb_ifp;
! 213:
! 214: /*
! 215: * disable rx
! 216: */
! 217:
! 218: ATM_PH_FLAGS(&api.aph) = ATM_PH_AAL5;
! 219: ATM_PH_VPI(&api.aph) = npcb->npcb_vpi;
! 220: ATM_PH_SETVCI(&api.aph, npcb->npcb_vci);
! 221: api.rxhand = npcb;
! 222: s2 = splnet();
! 223: if (ifp->if_ioctl != NULL)
! 224: ifp->if_ioctl(ifp, SIOCATMDIS, (caddr_t) &api);
! 225: splx(s);
! 226:
! 227: npcb_free(npcb, NPCB_REMOVE);
! 228: soisdisconnected(so);
! 229:
! 230: break;
! 231:
! 232: case PRU_SHUTDOWN: /* won't send any more data */
! 233: socantsendmore(so);
! 234: break;
! 235:
! 236: case PRU_SEND: /* send this data */
! 237: if (control && control->m_len) {
! 238: m_freem(control);
! 239: m_freem(m);
! 240: error = EINVAL;
! 241: break;
! 242: }
! 243:
! 244: /*
! 245: * send the data. we must put an atm_pseudohdr on first
! 246: */
! 247:
! 248: M_PREPEND(m, sizeof(*aph), M_WAITOK);
! 249: aph = mtod(m, struct atm_pseudohdr *);
! 250: ATM_PH_VPI(aph) = npcb->npcb_vpi;
! 251: ATM_PH_SETVCI(aph, npcb->npcb_vci);
! 252: ATM_PH_FLAGS(aph) = (proto == PROTO_NATMAAL5) ? ATM_PH_AAL5 : 0;
! 253:
! 254: error = atm_output(npcb->npcb_ifp, m, NULL, NULL);
! 255:
! 256: break;
! 257:
! 258: case PRU_SENSE: /* return status into m */
! 259: /* return zero? */
! 260: break;
! 261:
! 262: case PRU_PEERADDR: /* fetch peer's address */
! 263: snatm = mtod(nam, struct sockaddr_natm *);
! 264: bzero(snatm, sizeof(*snatm));
! 265: nam->m_len = snatm->snatm_len = sizeof(*snatm);
! 266: snatm->snatm_family = AF_NATM;
! 267: #if defined(__NetBSD__) || defined(__OpenBSD__)
! 268: bcopy(npcb->npcb_ifp->if_xname, snatm->snatm_if, sizeof(snatm->snatm_if));
! 269: #elif defined(__FreeBSD__)
! 270: sprintf(snatm->snatm_if, "%s%d", npcb->npcb_ifp->if_name,
! 271: npcb->npcb_ifp->if_unit);
! 272: #endif
! 273: snatm->snatm_vci = npcb->npcb_vci;
! 274: snatm->snatm_vpi = npcb->npcb_vpi;
! 275: break;
! 276:
! 277: case PRU_CONTROL: /* control operations on protocol */
! 278: /*
! 279: * raw atm ioctl. comes in as a SIOCRAWATM. we convert it to
! 280: * SIOCXRAWATM and pass it to the driver.
! 281: */
! 282: if ((u_long)m == SIOCRAWATM) {
! 283: if (npcb->npcb_ifp == NULL) {
! 284: error = ENOTCONN;
! 285: break;
! 286: }
! 287: ario.npcb = npcb;
! 288: ario.rawvalue = *((int *)nam);
! 289: error = npcb->npcb_ifp->if_ioctl(npcb->npcb_ifp,
! 290: SIOCXRAWATM, (caddr_t) &ario);
! 291: if (!error) {
! 292: if (ario.rawvalue)
! 293: npcb->npcb_flags |= NPCB_RAW;
! 294: else
! 295: npcb->npcb_flags &= ~(NPCB_RAW);
! 296: }
! 297:
! 298: break;
! 299: }
! 300:
! 301: error = EOPNOTSUPP;
! 302: break;
! 303:
! 304: case PRU_BIND: /* bind socket to address */
! 305: case PRU_LISTEN: /* listen for connection */
! 306: case PRU_ACCEPT: /* accept connection from peer */
! 307: case PRU_CONNECT2: /* connect two sockets */
! 308: case PRU_ABORT: /* abort (fast DISCONNECT, DETATCH) */
! 309: /* (only happens if LISTEN socket) */
! 310: case PRU_RCVD: /* have taken data; more room now */
! 311: case PRU_FASTTIMO: /* 200ms timeout */
! 312: case PRU_SLOWTIMO: /* 500ms timeout */
! 313: case PRU_RCVOOB: /* retrieve out of band data */
! 314: case PRU_SENDOOB: /* send out of band data */
! 315: case PRU_PROTORCV: /* receive from below */
! 316: case PRU_PROTOSEND: /* send to below */
! 317: case PRU_SOCKADDR: /* fetch socket's address */
! 318: #ifdef DIAGNOSTIC
! 319: printf("natm: PRU #%d unsupported\n", req);
! 320: #endif
! 321: error = EOPNOTSUPP;
! 322: break;
! 323:
! 324: default: panic("natm usrreq");
! 325: }
! 326:
! 327: done:
! 328: splx(s);
! 329: return(error);
! 330: }
! 331:
! 332: /*
! 333: * natmintr: splsoftnet interrupt
! 334: *
! 335: * note: we expect a socket pointer in rcvif rather than an interface
! 336: * pointer. we can get the interface pointer from the so's PCB if
! 337: * we really need it.
! 338: */
! 339:
! 340: void
! 341: natmintr()
! 342:
! 343: {
! 344: int s;
! 345: struct mbuf *m;
! 346: struct socket *so;
! 347: struct natmpcb *npcb;
! 348:
! 349: next:
! 350: s = splnet();
! 351: IF_DEQUEUE(&natmintrq, m);
! 352: splx(s);
! 353: if (m == NULL)
! 354: return;
! 355:
! 356: #ifdef DIAGNOSTIC
! 357: if ((m->m_flags & M_PKTHDR) == 0)
! 358: panic("natmintr no HDR");
! 359: #endif
! 360:
! 361: npcb = (struct natmpcb *) m->m_pkthdr.rcvif; /* XXX: overloaded */
! 362: so = npcb->npcb_socket;
! 363:
! 364: s = splnet(); /* could have atm devs @ different levels */
! 365: npcb->npcb_inq--;
! 366: splx(s);
! 367:
! 368: if (npcb->npcb_flags & NPCB_DRAIN) {
! 369: m_freem(m);
! 370: if (npcb->npcb_inq == 0)
! 371: FREE(npcb, M_PCB); /* done! */
! 372: goto next;
! 373: }
! 374:
! 375: if (npcb->npcb_flags & NPCB_FREE) {
! 376: m_freem(m); /* drop */
! 377: goto next;
! 378: }
! 379:
! 380: #ifdef NEED_TO_RESTORE_IFP
! 381: m->m_pkthdr.rcvif = npcb->npcb_ifp;
! 382: #else
! 383: #ifdef DIAGNOSTIC
! 384: m->m_pkthdr.rcvif = NULL; /* null it out to be safe */
! 385: #endif
! 386: #endif
! 387:
! 388: if (sbspace(&so->so_rcv) > m->m_pkthdr.len ||
! 389: ((npcb->npcb_flags & NPCB_RAW) != 0 && so->so_rcv.sb_cc < NPCB_RAWCC) ) {
! 390: #ifdef NATM_STAT
! 391: natm_sookcnt++;
! 392: natm_sookbytes += m->m_pkthdr.len;
! 393: #endif
! 394: sbappendrecord(&so->so_rcv, m);
! 395: sorwakeup(so);
! 396: } else {
! 397: #ifdef NATM_STAT
! 398: natm_sodropcnt++;
! 399: natm_sodropbytes += m->m_pkthdr.len;
! 400: #endif
! 401: m_freem(m);
! 402: }
! 403:
! 404: goto next;
! 405: }
! 406:
! 407: #if defined(__FreeBSD__)
! 408: NETISR_SET(NETISR_NATM, natmintr);
! 409: #endif
! 410:
! 411:
! 412: /*
! 413: * natm0_sysctl: not used, but here in case we want to add something
! 414: * later...
! 415: */
! 416:
! 417: int natm0_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
! 418:
! 419: int *name;
! 420: u_int namelen;
! 421: void *oldp;
! 422: size_t *oldlenp;
! 423: void *newp;
! 424: size_t newlen;
! 425:
! 426: {
! 427: /* All sysctl names at this level are terminal. */
! 428: if (namelen != 1)
! 429: return (ENOTDIR);
! 430: return (ENOPROTOOPT);
! 431: }
! 432:
! 433: /*
! 434: * natm5_sysctl: not used, but here in case we want to add something
! 435: * later...
! 436: */
! 437:
! 438: int natm5_sysctl(name, namelen, oldp, oldlenp, newp, newlen)
! 439:
! 440: int *name;
! 441: u_int namelen;
! 442: void *oldp;
! 443: size_t *oldlenp;
! 444: void *newp;
! 445: size_t newlen;
! 446:
! 447: {
! 448: /* All sysctl names at this level are terminal. */
! 449: if (namelen != 1)
! 450: return (ENOTDIR);
! 451: return (ENOPROTOOPT);
! 452: }
CVSweb