|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* Copyright (c) 1997, 1998 Apple Computer, Inc. All Rights Reserved */ ! 23: /* ! 24: * @(#)ndrv.c 1.1 (MacOSX) 6/10/43 ! 25: * Justin Walker, 970604 ! 26: * AF_NDRV support ! 27: * 980130 - Cleanup, reorg, performance improvemements ! 28: */ ! 29: ! 30: /* ! 31: * PF_NDRV allows raw access to a specified network device, directly ! 32: * with a socket. Expected use involves a socket option to request ! 33: * protocol packets. This lets ndrv_output() call dlil_output(), and ! 34: * lets DLIL find the proper recipient for incoming packets. ! 35: * The purpose here is for user-mode protocol implementation. ! 36: * Note that "pure raw access" will still be accomplished with BPF. ! 37: * ! 38: * In addition to the former use, when combined with socket NKEs, ! 39: * PF_NDRV permits a fairly flexible mechanism for implementing ! 40: * strange protocol support. One of the main ones will be the ! 41: * BlueBox/Classic Shared IP Address support. ! 42: * ! 43: * TODO: Add user access to protocol registration ! 44: */ ! 45: ! 46: #include <sys/param.h> ! 47: #include <sys/systm.h> ! 48: #include <sys/kernel.h> ! 49: #include <sys/malloc.h> ! 50: #include <sys/mbuf.h> ! 51: #include <sys/protosw.h> ! 52: #include <sys/domain.h> ! 53: #include <sys/socket.h> ! 54: #include <sys/socketvar.h> ! 55: #include <sys/ioctl.h> ! 56: #include <sys/errno.h> ! 57: #include <sys/syslog.h> ! 58: #include <sys/proc.h> ! 59: ! 60: #include <kern/queue.h> ! 61: ! 62: #include <net/if.h> ! 63: #include <net/netisr.h> ! 64: #include <net/route.h> ! 65: #include <net/if_llc.h> ! 66: #include <net/if_dl.h> ! 67: #include <net/if_types.h> ! 68: #include "if_blue.h" /* TEMP! Until BB gets in synch */ ! 69: #include "ndrv.h" ! 70: ! 71: #if INET ! 72: #include <netinet/in.h> ! 73: #include <netinet/in_var.h> ! 74: #endif ! 75: #include <netinet/if_ether.h> ! 76: ! 77: #if NS ! 78: #include <netns/ns.h> ! 79: #include <netns/ns_if.h> ! 80: #endif ! 81: ! 82: #if ISO ! 83: #include <netiso/argo_debug.h> ! 84: #include <netiso/iso.h> ! 85: #include <netiso/iso_var.h> ! 86: #include <netiso/iso_snpac.h> ! 87: #endif ! 88: ! 89: #if LLC ! 90: #include <netccitt/dll.h> ! 91: #include <netccitt/llc_var.h> ! 92: #endif ! 93: ! 94: #include <machine/spl.h> ! 95: ! 96: int local_ndrv_attach(struct socket *, int); ! 97: int local_ndrv_detach(struct ndrv_cb *); ! 98: int local_ndrv_bind(struct socket *, struct sockaddr_ndrv *); ! 99: int local_ndrv_disconnect(struct ndrv_cb *); ! 100: ! 101: extern int splitter_ctl(struct socket *, int, caddr_t, struct ifnet *); ! 102: ! 103: void local_ndrv_dinit(void); ! 104: ! 105: unsigned long ndrv_sendspace = NDRVSNDQ; ! 106: unsigned long ndrv_recvspace = NDRVRCVQ; ! 107: struct ndrv_cb ndrvl; /* Head of controlblock list */ ! 108: ! 109: #define BLUEQMAXLEN 50 ! 110: int blueqmaxlen = BLUEQMAXLEN; /* Default */ ! 111: ! 112: /* Domain init function for AF_NDRV - noop */ ! 113: void ! 114: local_ndrv_dinit(void) ! 115: { ! 116: } ! 117: ! 118: /* ! 119: * Protocol init function for NDRV protocol ! 120: * Init the control block list. ! 121: */ ! 122: void ! 123: ndrv_init() ! 124: { ndrvl.nd_next = ndrvl.nd_prev = &ndrvl; ! 125: blueq.ifq_maxlen = blueqmaxlen; ! 126: } ! 127: ! 128: /* ! 129: * Protocol output - Called to output a raw network packet directly ! 130: * to the driver. If we're splitting, maybe loop it back. ! 131: */ ! 132: int ! 133: ndrv_output(register struct mbuf *m, ! 134: register struct socket *so) ! 135: { register struct ndrv_cb *np = sotondrvcb(so); ! 136: register struct ifnet *ifp = np->nd_if; ! 137: int s, error; ! 138: extern struct ifnet_blue *blue_if; ! 139: extern void kprintf(const char *, ...); ! 140: extern int Filter_check(struct mbuf **); ! 141: #define senderr(e) { error = (e); goto bad;} ! 142: ! 143: #if NDRV_DEBUG ! 144: kprintf("NDRV output: %x, %x, %x\n", m, so, np); ! 145: #endif ! 146: ! 147: /* ! 148: * No header is a format error ! 149: */ ! 150: if ((m->m_flags&M_PKTHDR) == 0) ! 151: return(ENOBUFS); /* EINVAL??? */ ! 152: ! 153: /* If we're splitting, */ ! 154: if (ifp->if_flags&IFF_SPLITTER) /* Splitter is turned on */ ! 155: { register struct mbuf *m0; ! 156: struct mbuf *m1; ! 157: register int rv; ! 158: extern struct mbuf *m_dup(struct mbuf *, int); ! 159: #if 0 ! 160: kprintf("NDRV_OUTPUT: m0 = %x\n", m0); ! 161: #endif ! 162: ! 163: m1 = m; ! 164: rv = Filter_check(&m1); ! 165: m = m1; ! 166: /* ! 167: * -1 => Not For MacOSX ! 168: * 0 => For Both ! 169: * 1 => For MacOSX ! 170: */ ! 171: if (rv >= 0) ! 172: { register struct ether_header *eh; ! 173: ! 174: if (rv == 0) ! 175: { if ((m0 = m_dup(m, M_WAIT)) == NULL) ! 176: ((struct ifnet_blue *)ifp->if_Y)->no_bufs2++; ! 177: } else ! 178: { m0 = m; ! 179: m = NULL; ! 180: } ! 181: /* Hack alert! */ ! 182: eh = mtod(m0, struct ether_header *); ! 183: m0->m_data += sizeof(struct ether_header); ! 184: m0->m_len -= sizeof (struct ether_header); ! 185: m0->m_pkthdr.len -= sizeof(struct ether_header); ! 186: m0->m_flags |= 0x80; ! 187: #if NDRV_DEBUG ! 188: kprintf("NDRV_OUTPUT: m0 = %x\n", m0); ! 189: #endif ! 190: new_ether_input(m0, eh, (struct ifnet *)blue_if, 0, 1); ! 191: if (!m) ! 192: return(0); ! 193: } ! 194: } ! 195: ! 196: /* ! 197: * Output to real device. ! 198: * ! 199: * Can't do multicast accounting because we don't know ! 200: * (a) if our interface does multicast; and ! 201: * (b) what a multicast address looks like ! 202: */ ! 203: s = splimp(); ! 204: ! 205: /* ! 206: * Can't call DLIL to do the job - we don't have a tag ! 207: * and we aren't really a protocol ! 208: */ ! 209: ! 210: (*ifp->if_output)(ifp, m); ! 211: splx(s); ! 212: ifp->if_obytes += m->m_len; /* MP alert! */ ! 213: blue_if->pkts_out++; ! 214: return (0); ! 215: bad: ! 216: if (m) ! 217: m_freem(m); ! 218: return (error); ! 219: } ! 220: ! 221: ! 222: ! 223: ! 224: ! 225: int ndrv_control(struct socket *so, u_long cmd, caddr_t data, ! 226: struct ifnet *ifp, struct proc *p) ! 227: { ! 228: return (splitter_ctl(so, (int)cmd, data, ! 229: ifp)); ! 230: } ! 231: ! 232: int ndrv_attach(struct socket *so, int proto, ! 233: struct proc *p) ! 234: { ! 235: ! 236: return local_ndrv_attach(so, proto); ! 237: } ! 238: ! 239: ! 240: ! 241: /* ! 242: * Destroy state just before socket deallocation. ! 243: * Flush data or not depending on the options. ! 244: */ ! 245: ! 246: int ndrv_detach(struct socket *so) ! 247: { ! 248: register struct ndrv_cb *np = sotondrvcb(so); ! 249: ! 250: if (np == 0) ! 251: return EINVAL; ! 252: return local_ndrv_detach(np); ! 253: } ! 254: ! 255: ! 256: /* ! 257: * If a socket isn't bound to a single address, ! 258: * the ndrv input routine will hand it anything ! 259: * within that protocol family (assuming there's ! 260: * nothing else around it should go to). ! 261: * ! 262: * Don't expect this to be used. ! 263: */ ! 264: ! 265: int ndrv_connect(struct socket *so, struct sockaddr *nam, ! 266: struct proc *p) ! 267: { ! 268: register struct ndrv_cb *np = sotondrvcb(so); ! 269: ! 270: if (np == 0) ! 271: return EINVAL; ! 272: ! 273: if (np->nd_faddr) ! 274: return EISCONN; ! 275: ! 276: bcopy((caddr_t) nam, (caddr_t) np->nd_faddr, sizeof(struct sockaddr_ndrv)); ! 277: soisconnected(so); ! 278: return 0; ! 279: } ! 280: ! 281: /* ! 282: * This is the "driver open" hook - we 'bind' to the ! 283: * named driver. ! 284: */ ! 285: int ndrv_bind(struct socket *so, struct sockaddr *nam, ! 286: struct proc *p) ! 287: { ! 288: register struct ndrv_cb *np = sotondrvcb(so); ! 289: ! 290: if (np == 0) ! 291: return EINVAL; ! 292: ! 293: if (np->nd_laddr) ! 294: return EINVAL; /* XXX */ ! 295: ! 296: return local_ndrv_bind(so, (struct sockaddr_ndrv *) nam); ! 297: } ! 298: ! 299: ! 300: ! 301: ! 302: int ndrv_disconnect(struct socket *so) ! 303: { ! 304: register struct ndrv_cb *np = sotondrvcb(so); ! 305: ! 306: if (np == 0) ! 307: return EINVAL; ! 308: ! 309: if (np->nd_faddr == 0) ! 310: return ENOTCONN; ! 311: ! 312: local_ndrv_disconnect(np); ! 313: soisdisconnected(so); ! 314: return 0; ! 315: } ! 316: ! 317: /* ! 318: * Mark the connection as being incapable of further input. ! 319: */ ! 320: int ndrv_shutdown(struct socket *so) ! 321: { ! 322: socantsendmore(so); ! 323: return 0; ! 324: } ! 325: ! 326: /* ! 327: * Ship a packet out. The ndrv output will pass it ! 328: * to the appropriate driver. The really tricky part ! 329: * is the destination address... ! 330: */ ! 331: int ndrv_send(struct socket *so, int flags, struct mbuf *m, ! 332: struct sockaddr *addr, struct mbuf *control, ! 333: struct proc *p) ! 334: { ! 335: int error; ! 336: ! 337: if (control) ! 338: return EOPNOTSUPP; ! 339: ! 340: error = ndrv_output(m, so); ! 341: m = NULL; ! 342: return error; ! 343: } ! 344: ! 345: ! 346: int ndrv_abort(struct socket *so) ! 347: { ! 348: register struct ndrv_cb *np = sotondrvcb(so); ! 349: ! 350: if (np == 0) ! 351: return EINVAL; ! 352: ! 353: local_ndrv_disconnect(np); ! 354: sofree(so); ! 355: soisdisconnected(so); ! 356: return 0; ! 357: } ! 358: ! 359: int ndrv_sense(struct socket *so, struct stat *sb) ! 360: { ! 361: /* ! 362: * stat: don't bother with a blocksize. ! 363: */ ! 364: return (0); ! 365: } ! 366: ! 367: int ndrv_sockaddr(struct socket *so, ! 368: struct sockaddr **nam) ! 369: { ! 370: register struct ndrv_cb *np = sotondrvcb(so); ! 371: int len; ! 372: ! 373: if (np == 0) ! 374: return EINVAL; ! 375: ! 376: if (np->nd_laddr == 0) ! 377: return EINVAL; ! 378: ! 379: len = np->nd_laddr->snd_len; ! 380: bcopy((caddr_t)np->nd_laddr, *nam, ! 381: (unsigned)len); ! 382: return 0; ! 383: } ! 384: ! 385: ! 386: int ndrv_peeraddr(struct socket *so, ! 387: struct sockaddr **nam) ! 388: { ! 389: register struct ndrv_cb *np = sotondrvcb(so); ! 390: int len; ! 391: ! 392: if (np == 0) ! 393: return EINVAL; ! 394: ! 395: if (np->nd_faddr == 0) ! 396: return ENOTCONN; ! 397: ! 398: len = np->nd_faddr->snd_len; ! 399: bcopy((caddr_t)np->nd_faddr, *nam, ! 400: (unsigned)len); ! 401: return 0; ! 402: } ! 403: ! 404: ! 405: /* Control input */ ! 406: ! 407: void ndrv_ctlinput(int dummy1, struct sockaddr *dummy2, void *dummy3) ! 408: ! 409: { ! 410: } ! 411: ! 412: /* Control output */ ! 413: ! 414: int ndrv_ctloutput(struct socket *dummy1, struct sockopt *dummy2) ! 415: { ! 416: return(0); ! 417: } ! 418: ! 419: /* Drain the queues */ ! 420: void ! 421: ndrv_drain() ! 422: { ! 423: } ! 424: ! 425: /* Sysctl hook for NDRV */ ! 426: int ! 427: ndrv_sysctl() ! 428: { ! 429: return(0); ! 430: } ! 431: ! 432: /* ! 433: * Allocate an ndrv control block and some buffer space for the socket ! 434: */ ! 435: int ! 436: local_ndrv_attach(register struct socket *so, ! 437: register int proto) ! 438: { int error; ! 439: register struct ndrv_cb *np = sotondrvcb(so); ! 440: ! 441: if ((so->so_state & SS_PRIV) == 0) ! 442: return(EPERM); ! 443: ! 444: #if NDRV_DEBUG ! 445: kprintf("NDRV attach: %x, %x, %x\n", so, proto, np); ! 446: #endif ! 447: MALLOC(np, struct ndrv_cb *, sizeof(*np), M_PCB, M_WAITOK); ! 448: #if NDRV_DEBUG ! 449: kprintf("NDRV attach: %x, %x, %x\n", so, proto, np); ! 450: #endif ! 451: if ((so->so_pcb = (caddr_t)np)) ! 452: bzero(np, sizeof(*np)); ! 453: else ! 454: return(ENOBUFS); ! 455: if ((error = soreserve(so, ndrv_sendspace, ndrv_recvspace))) ! 456: return(error); ! 457: np->nd_signature = NDRV_SIGNATURE; ! 458: np->nd_socket = so; ! 459: np->nd_proto.sp_family = so->so_proto->pr_domain->dom_family; ! 460: np->nd_proto.sp_protocol = proto; ! 461: insque((queue_t)np, (queue_t)&ndrvl); ! 462: //##### eeccckkk added here to get the kext filter "attached"... TEMP ! 463: // sfilter_init(so); ! 464: return(0); ! 465: } ! 466: ! 467: int ! 468: local_ndrv_detach(register struct ndrv_cb *np) ! 469: { register struct socket *so = np->nd_socket; ! 470: extern struct ifnet_blue *blue_if; ! 471: extern void splitter_close(struct ndrv_cb *); ! 472: ! 473: #if NDRV_DEBUG ! 474: kprintf("NDRV detach: %x, %x\n", so, np); ! 475: #endif ! 476: if (blue_if) ! 477: splitter_close(np); /* 'np' is freed within */ ! 478: so->so_pcb = 0; ! 479: sofree(so); ! 480: return(0); ! 481: } ! 482: ! 483: int ! 484: local_ndrv_disconnect(register struct ndrv_cb *np) ! 485: { ! 486: #if NDRV_DEBUG ! 487: kprintf("NDRV disconnect: %x\n", np); ! 488: #endif ! 489: if (np->nd_faddr) ! 490: { m_freem(dtom(np->nd_faddr)); ! 491: np->nd_faddr = 0; ! 492: } ! 493: if (np->nd_socket->so_state & SS_NOFDREF) ! 494: local_ndrv_detach(np); ! 495: return(0); ! 496: } ! 497: ! 498: /* ! 499: * Here's where we latch onto the driver and make it ours. ! 500: */ ! 501: int ! 502: local_ndrv_bind(register struct socket *so, ! 503: register struct sockaddr_ndrv *sa) ! 504: { register char *dname; ! 505: register struct ndrv_cb *np; ! 506: register struct ifnet *ifp; ! 507: extern int name_cmp(struct ifnet *, char *); ! 508: ! 509: if TAILQ_EMPTY(&ifnet) ! 510: return(EADDRNOTAVAIL); /* Quick sanity check */ ! 511: np = sotondrvcb(so); ! 512: ! 513: /* I think we just latch onto a copy here; the caller frees */ ! 514: ! 515: ! 516: np->nd_laddr = _MALLOC(sizeof(struct sockaddr_ndrv), M_IFADDR, M_WAITOK); ! 517: bcopy((caddr_t) sa, (caddr_t) np->nd_laddr, sizeof(struct sockaddr_ndrv)); ! 518: dname = sa->snd_name; ! 519: if (dname == NULL) ! 520: return(EINVAL); ! 521: #if NDRV_DEBUG ! 522: kprintf("NDRV bind: %x, %x, %s\n", so, np, dname); ! 523: #endif ! 524: /* Track down the driver and its ifnet structure. ! 525: * There's no internal call for this so we have to dup the code ! 526: * in if.c/ifconf() ! 527: */ ! 528: TAILQ_FOREACH(ifp, &ifnet, if_link) { ! 529: if (name_cmp(ifp, dname) == 0) ! 530: break; ! 531: } ! 532: ! 533: if (ifp == NULL) ! 534: return(EADDRNOTAVAIL); ! 535: /* ! 536: * Now, at this point, we should force open the driver and somehow ! 537: * register ourselves to receive packets (a la the bpf). ! 538: * However, we have this groaty hack in place that makes it ! 539: * not necessary for blue box purposes (the 'splitter' trick). ! 540: * If we want this to be a full-fledged AF, we have to force the ! 541: * open and implement a filter mechanism. ! 542: */ ! 543: np->nd_if = ifp; ! 544: return(0); ! 545: } ! 546: ! 547: /* ! 548: * Try to compare a device name (q) with one of the funky ifnet ! 549: * device names (ifp). ! 550: */ ! 551: int name_cmp(register struct ifnet *ifp, register char *q) ! 552: { register char *r; ! 553: register int len; ! 554: char buf[IFNAMSIZ]; ! 555: static char *sprint_d(); ! 556: ! 557: r = buf; ! 558: len = strlen(ifp->if_name); ! 559: strncpy(r, ifp->if_name, IFNAMSIZ); ! 560: r += len; ! 561: (void)sprint_d(ifp->if_unit, r, r-buf); ! 562: #if NDRV_DEBUG ! 563: kprintf("Comparing %s, %s\n", buf, q); ! 564: #endif ! 565: return(strncmp(buf, q, IFNAMSIZ)); ! 566: } ! 567: ! 568: /* Hackery - return a string version of a decimal number */ ! 569: static char * ! 570: sprint_d(n, buf, buflen) ! 571: u_int n; ! 572: char *buf; ! 573: int buflen; ! 574: { ! 575: register char *cp = buf + buflen - 1; ! 576: ! 577: *cp = 0; ! 578: do { ! 579: cp--; ! 580: *cp = "0123456789"[n % 10]; ! 581: n /= 10; ! 582: } while (n != 0); ! 583: return (cp); ! 584: } ! 585: ! 586: /* ! 587: * When closing, dump any enqueued mbufs. ! 588: */ ! 589: void ! 590: ndrv_flushq(register struct ifqueue *q) ! 591: { register struct mbuf *m; ! 592: register int s; ! 593: for (;;) ! 594: { s = splimp(); ! 595: IF_DEQUEUE(q, m); ! 596: if (m == NULL) ! 597: break; ! 598: IF_DROP(q); ! 599: splx(s); ! 600: if (m) ! 601: m_freem(m); ! 602: } ! 603: splx(s); ! 604: } ! 605: ! 606: ! 607: struct pr_usrreqs ndrv_usrreqs = { ! 608: ndrv_abort, pru_accept_notsupp, ndrv_attach, ndrv_bind, ! 609: ndrv_connect, pru_connect2_notsupp, ndrv_control, ndrv_detach, ! 610: ndrv_disconnect, pru_listen_notsupp, ndrv_peeraddr, pru_rcvd_notsupp, ! 611: pru_rcvoob_notsupp, ndrv_send, ndrv_sense, ndrv_shutdown, ! 612: ndrv_sockaddr, sosend, soreceive, sopoll ! 613: }; ! 614: ! 615: struct domain ndrvdomain; ! 616: ! 617: struct protosw ndrvsw[] = ! 618: { { SOCK_RAW, &ndrvdomain, 0, PR_ATOMIC|PR_ADDR, ! 619: 0, ndrv_output, ndrv_ctlinput, ndrv_ctloutput, ! 620: 0, ndrv_init, 0, 0, ! 621: ndrv_drain, ndrv_sysctl, &ndrv_usrreqs ! 622: } ! 623: }; ! 624: ! 625: ! 626: struct domain ndrvdomain = ! 627: { AF_NDRV, "NetDriver", NULL, NULL, NULL, ! 628: ndrvsw, ! 629: NULL, NULL, 0, 0, 0, 0 ! 630: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.