|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1996-1994 The University of Utah and ! 3: * the Computer Systems Laboratory (CSL). All rights reserved. ! 4: * ! 5: * Permission to use, copy, modify and distribute this software is hereby ! 6: * granted provided that (1) source code retains these copyright, permission, ! 7: * and disclaimer notices, and (2) redistributions including binaries ! 8: * reproduce the notices in supporting documentation, and (3) all advertising ! 9: * materials mentioning features or use of this software display the following ! 10: * acknowledgement: ``This product includes software developed by the ! 11: * Computer Systems Laboratory at the University of Utah.'' ! 12: * ! 13: * THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 14: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSL DISCLAIM ANY LIABILITY OF ! 15: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 16: * ! 17: * CSL requests users of this software to return to [email protected] any ! 18: * improvements that they make and grant CSL redistribution rights. ! 19: * ! 20: * Utah $Hdr: fipc.c 1.1 96/2/29$ ! 21: * Author: Linus Kamb ! 22: */ ! 23: ! 24: #ifdef FIPC ! 25: ! 26: #include <mach/kern_return.h> ! 27: ! 28: #include <device/device_types.h> ! 29: #include <device/device.h> ! 30: #include <device/dev_hdr.h> ! 31: #include <device/device_port.h> ! 32: #include <device/io_req.h> ! 33: #include <device/if_ether.h> ! 34: #include <net_io.h> ! 35: #include <spl.h> ! 36: #include <kern/lock.h> ! 37: ! 38: #include "fipc.h" ! 39: ! 40: void fipc_packet(); ! 41: void allocate_fipc_buffers(boolean_t); ! 42: int fipc_lookup(unsigned short port); ! 43: int fipc_lookup_table_enter(unsigned short port); ! 44: int fipc_lookup_table_remove(unsigned short port); ! 45: int f_lookup_hash(unsigned short port); ! 46: int fipc_done(io_req_t ior); ! 47: ! 48: ! 49: /******************************************************************** ! 50: * fipc variables ! 51: ********************************************************************/ ! 52: ! 53: fipc_port_t fports[N_MAX_OPEN_FIPC_PORTS]; ! 54: fipc_lookup_table_ent fipc_lookup_table[N_MAX_OPEN_FIPC_PORTS]; ! 55: ! 56: int n_free_recv_bufs = 0; ! 57: int n_free_send_bufs = 0; ! 58: int n_fipc_recv_ports_used = 0; ! 59: ! 60: int fipc_sends = 0; ! 61: int fipc_recvs =0; ! 62: ! 63: fipc_stat_t fipc_stats; ! 64: ! 65: char *fipc_recv_free_list = NULL; ! 66: char *fipc_recv_free_list_tail = NULL; ! 67: char *fipc_send_free_list = NULL; ! 68: char *fipc_send_free_list_tail = NULL; ! 69: ! 70: /* fipc locks */ ! 71: decl_simple_lock_data(, fipc_lock); ! 72: decl_simple_lock_data(, fipc_buf_q_lock); ! 73: ! 74: ! 75: /* ! 76: * Routine: fipc_init(): initializes the fipc data structures. ! 77: */ ! 78: ! 79: void fipc_init(void) ! 80: { ! 81: int i; ! 82: ! 83: allocate_fipc_buffers(TRUE); /* recv buffers */ ! 84: allocate_fipc_buffers(FALSE); /* send buffers */ ! 85: ! 86: fipc_stats.dropped_msgs = 0; ! 87: ! 88: bzero (&fports, sizeof(fports)); ! 89: for (i=0; i<N_MAX_OPEN_FIPC_PORTS; i++) ! 90: { ! 91: simple_lock_init(&(fports[i].lock)); ! 92: fipc_lookup_table[i].fpt_num = INVALID; ! 93: fipc_lookup_table[i].fipc_port = INVALID; ! 94: } ! 95: } ! 96: ! 97: ! 98: /* ! 99: * Routine: allocate_fipc_buffers(): allocate more buffers ! 100: * Currently we are only allocating 1500 byte (ETHERMTU) buffers. ! 101: * We use the first word in the buffer as the pointer to the next. ! 102: */ ! 103: ! 104: void allocate_fipc_buffers(boolean_t r_buf) ! 105: { ! 106: char *new_pg; ! 107: char **free_list, **free_list_tail; ! 108: int *free_count, min_count, max_count; ! 109: int total_buffer_size; ! 110: ! 111: if (r_buf) ! 112: { ! 113: free_count = &n_free_recv_bufs; ! 114: min_count = N_MIN_RECV_BUFS; ! 115: max_count = N_MAX_RECV_BUFS; ! 116: free_list = &fipc_recv_free_list; ! 117: free_list_tail = &fipc_recv_free_list_tail; ! 118: total_buffer_size = (N_MAX_RECV_BUFS * FIPC_BUFFER_SIZE); ! 119: total_buffer_size = round_page(total_buffer_size); ! 120: } ! 121: else ! 122: { ! 123: free_count = &n_free_send_bufs; ! 124: min_count = N_MIN_SEND_BUFS; ! 125: max_count = N_MAX_SEND_BUFS; ! 126: free_list = &fipc_send_free_list; ! 127: free_list_tail = &fipc_send_free_list_tail; ! 128: total_buffer_size = (N_MAX_SEND_BUFS * FIPC_BUFFER_SIZE); ! 129: total_buffer_size = round_page(total_buffer_size); ! 130: } ! 131: ! 132: if (!(*free_count)) /* empty buffer pool */ ! 133: { ! 134: #ifdef FI_DEBUG ! 135: printf ("Allocating new fipc "); ! 136: if (r_buf) ! 137: printf ("recv buffer pool.\n"); ! 138: else ! 139: printf ("send buffer pool.\n"); ! 140: #endif ! 141: *free_list = (char*)kalloc (total_buffer_size); ! 142: if (!*free_list) /* bummer */ ! 143: panic("allocate_fipc_buffers: no memory"); ! 144: *free_list_tail = *free_list; ! 145: for (*free_count=1; *free_count<max_count; (*free_count)++) ! 146: { ! 147: *(char**)*free_list_tail = *free_list_tail + FIPC_BUFFER_SIZE; ! 148: *free_list_tail += FIPC_BUFFER_SIZE; ! 149: } ! 150: *(char**)*free_list_tail = NULL; ! 151: } ! 152: else /* Request to grow the buffer pool. */ ! 153: { ! 154: #ifdef FI_DEBUG ! 155: printf ("Growing fipc "); ! 156: if (r_buf) ! 157: printf ("recv buffer pool.\n"); ! 158: else ! 159: printf ("send buffer pool.\n"); ! 160: #endif ! 161: ! 162: #define GROW_SIZE 8192 ! 163: new_pg = (char*)kalloc (round_page(GROW_SIZE)); ! 164: if (new_pg) ! 165: { ! 166: int new_cnt, n_new = GROW_SIZE / FIPC_BUFFER_SIZE; ! 167: ! 168: if (*free_list_tail != NULL) ! 169: *(char**)*free_list_tail = new_pg; ! 170: for ( new_cnt =0; new_cnt<n_new; new_cnt++) ! 171: { ! 172: *(char**)*free_list_tail = *free_list_tail + FIPC_BUFFER_SIZE; ! 173: *free_list_tail += FIPC_BUFFER_SIZE; ! 174: } ! 175: *(char**)*free_list_tail = NULL; ! 176: *free_count +=new_cnt; ! 177: } ! 178: #ifdef FI_DEBUG ! 179: else ! 180: printf ("### kalloc failed in allocate_fipc_buffers()\n"); ! 181: #endif ! 182: ! 183: } ! 184: } ! 185: ! 186: ! 187: /* ! 188: * Routine: get_fipc_buffer (): returns a free buffer ! 189: * Takes a size (currently not used), a boolean flag to tell if it is a ! 190: * receive buffer, and a boolean flag if the request is coming at interrupt ! 191: * level. ! 192: */ ! 193: ! 194: inline ! 195: char* get_fipc_buffer(int size, boolean_t r_buf, boolean_t at_int_lvl) ! 196: { ! 197: /* we currently don't care about size, since there is only one ! 198: * buffer pool. */ ! 199: ! 200: char* head; ! 201: char **free_list; ! 202: int *free_count, min_count; ! 203: ! 204: if (r_buf) ! 205: { ! 206: free_count = &n_free_recv_bufs; ! 207: free_list = &fipc_recv_free_list; ! 208: min_count = N_MIN_RECV_BUFS; ! 209: } ! 210: else ! 211: { ! 212: free_count = &n_free_send_bufs; ! 213: free_list = &fipc_send_free_list; ! 214: min_count = N_MIN_SEND_BUFS; ! 215: } ! 216: ! 217: /* ! 218: * Since we currently allocate a full complement of receive buffers, ! 219: * there is no need to allocate more receive buffers. But that is likely ! 220: * to change, I'm sure. ! 221: */ ! 222: ! 223: if (*free_count < min_count) ! 224: { ! 225: if (!at_int_lvl) ! 226: allocate_fipc_buffers(r_buf); ! 227: } ! 228: ! 229: if (*free_count) ! 230: { ! 231: head = *free_list; ! 232: *free_list = *(char**)*free_list; ! 233: (*free_count)--; ! 234: return head; ! 235: } ! 236: else ! 237: return NULL; ! 238: } ! 239: ! 240: ! 241: /* ! 242: * Routine: return_fipc_buffer (): puts a used buffer back in the pool. ! 243: */ ! 244: ! 245: inline ! 246: void return_fipc_buffer(char* buf, int size, ! 247: boolean_t r_buf, boolean_t at_int_lvl) ! 248: { ! 249: /* return the buffer to the free pool */ ! 250: char **free_list, **free_list_tail; ! 251: int *free_count, min_count; ! 252: ! 253: if (r_buf) ! 254: { ! 255: free_count = &n_free_recv_bufs; ! 256: free_list = &fipc_recv_free_list; ! 257: free_list_tail = &fipc_recv_free_list_tail; ! 258: min_count = N_MIN_RECV_BUFS; ! 259: } ! 260: else ! 261: { ! 262: free_count = &n_free_send_bufs; ! 263: free_list = &fipc_send_free_list; ! 264: free_list_tail = &fipc_send_free_list_tail; ! 265: min_count = N_MIN_SEND_BUFS; ! 266: } ! 267: ! 268: #ifdef FI_SECURE ! 269: bzero(buf, FIPC_BUFFER_SIZE); ! 270: #endif ! 271: ! 272: if (*free_list_tail != NULL) ! 273: *(char**)*free_list_tail = buf; ! 274: *free_list_tail = buf; ! 275: (*free_count)++; ! 276: *(char**)buf = NULL; ! 277: ! 278: if (!at_int_lvl) ! 279: if (*free_count < min_count) ! 280: allocate_fipc_buffers(r_buf); ! 281: ! 282: return; ! 283: } ! 284: ! 285: inline ! 286: int f_lookup_hash(unsigned short port) ! 287: { ! 288: /* Ok, so it's not really a hash function */ ! 289: int bail=0; ! 290: int chk=0; ! 291: ! 292: if (n_fipc_recv_ports_used == N_MAX_OPEN_FIPC_PORTS || ! 293: port > MAX_FIPC_PORT_NUM) ! 294: return INVALID; ! 295: ! 296: while (fipc_lookup_table[chk].fipc_port != port && ! 297: fipc_lookup_table[chk].fpt_num != INVALID && ! 298: bail < N_MAX_OPEN_FIPC_PORTS) ! 299: { ! 300: chk = (chk+1) % N_MAX_OPEN_FIPC_PORTS; ! 301: bail++; ! 302: } ! 303: ! 304: /* This is redundent, but better safe then sorry */ ! 305: if (bail<N_MAX_OPEN_FIPC_PORTS) ! 306: return chk; ! 307: else ! 308: return INVALID; ! 309: } ! 310: ! 311: inline ! 312: int fipc_lookup_table_enter(unsigned short port) ! 313: { ! 314: int cfpn = n_fipc_recv_ports_used; ! 315: int lu_tbl_num = f_lookup_hash(port); ! 316: ! 317: if (lu_tbl_num == INVALID) ! 318: return INVALID; ! 319: ! 320: fipc_lookup_table[lu_tbl_num].fipc_port = port; ! 321: fipc_lookup_table[lu_tbl_num].fpt_num = cfpn; ! 322: n_fipc_recv_ports_used += 1; ! 323: return cfpn; ! 324: } ! 325: ! 326: inline ! 327: int fipc_lookup(unsigned short port) ! 328: { ! 329: int chk = f_lookup_hash(port); ! 330: ! 331: if (chk == INVALID) ! 332: return INVALID; ! 333: ! 334: if (fipc_lookup_table[chk].fpt_num == INVALID) ! 335: return fipc_lookup_table_enter(port); ! 336: else ! 337: return fipc_lookup_table[chk].fpt_num; ! 338: } ! 339: ! 340: inline ! 341: int fipc_lookup_table_remove(unsigned short port) ! 342: { ! 343: int chk = f_lookup_hash(port); ! 344: ! 345: if (chk == INVALID) ! 346: return 0; ! 347: ! 348: if (fipc_lookup_table[chk].fipc_port == port) ! 349: { ! 350: fports[fipc_lookup_table[chk].fpt_num].valid_msg = 0; ! 351: fports[fipc_lookup_table[chk].fpt_num].bound = FALSE; ! 352: fipc_lookup_table[chk].fpt_num = INVALID; ! 353: fipc_lookup_table[chk].fipc_port = INVALID; ! 354: n_fipc_recv_ports_used -=1; ! 355: return 1; ! 356: } ! 357: return 0; ! 358: } ! 359: ! 360: /* ! 361: * Routine: fipc_packet(): handles incoming fipc packets. ! 362: * does some simple packet handling and wakes up receiving thread, if any. ! 363: * called by device controller (currently, nerecv only.) ! 364: * called at interrupt level and splimp. ! 365: * Messages are dropped if the recv queue is full. ! 366: */ ! 367: ! 368: void fipc_packet( char* msg_buf, struct ether_header sender) ! 369: { ! 370: int to_port = ((fipc_header_t*)msg_buf)->dest_port; ! 371: int from_port = ((fipc_header_t*)msg_buf)->send_port; ! 372: int f_tbl_num; ! 373: fipc_port_t *cfp; ! 374: fipc_buffer_q_ent *crqe; ! 375: int *tail; ! 376: ! 377: #ifdef FI_DEBUG ! 378: printf ("fipc_packet :(0x%x) %s", msg_buf, ! 379: msg_buf+sizeof(fipc_header_t)); ! 380: #endif ! 381: ! 382: f_tbl_num = fipc_lookup(to_port); ! 383: if (f_tbl_num == INVALID) ! 384: { ! 385: #ifdef FI_DEBUG ! 386: printf ("Lookup failed.\n"); ! 387: #endif ! 388: fipc_stats.dropped_msgs += 1; ! 389: return_fipc_buffer (msg_buf, FIPC_BUFFER_SIZE, TRUE, TRUE); ! 390: return; ! 391: } ! 392: ! 393: cfp = &fports[f_tbl_num]; ! 394: tail = &cfp->rq_tail; ! 395: crqe = &cfp->recv_q[*tail]; ! 396: ! 397: if (cfp->valid_msg == FIPC_RECV_Q_SIZE) ! 398: { ! 399: /* Queue full. ! 400: * Drop packet, return buffer, and return. */ ! 401: #ifdef FI_DEBUG ! 402: printf ("Port %d queue is full: valid_msg count: %d\n", ! 403: to_port, cfp->valid_msg); ! 404: #endif ! 405: fipc_stats.dropped_msgs += 1; ! 406: return_fipc_buffer (msg_buf, FIPC_BUFFER_SIZE, TRUE, TRUE); ! 407: return; ! 408: } ! 409: ! 410: /* "enqueue" at "tail" */ ! 411: crqe->buffer = msg_buf; ! 412: crqe->size = ((fipc_header_t*)msg_buf)->msg_size; ! 413: /* This could certainly be done faster... */ ! 414: bcopy(&(sender.ether_shost), &(crqe->sender.hwaddr), ETHER_HWADDR_SIZE); ! 415: /* This is actually useless, since there _is_ no sender port.. duh. */ ! 416: crqe->sender.port = from_port; ! 417: ! 418: *tail = ((*tail)+1) % FIPC_RECV_Q_SIZE; ! 419: ! 420: if (cfp->bound) ! 421: thread_wakeup(&(cfp->valid_msg)); ! 422: cfp->valid_msg++; ! 423: #ifdef FI_DEBUG ! 424: printf ("valid_msg: %d\n", cfp->valid_msg); ! 425: #endif ! 426: ! 427: return; ! 428: } ! 429: ! 430: ! 431: /* ! 432: * loopback(): for fipc_sends to the local host. ! 433: */ ! 434: ! 435: inline ! 436: kern_return_t loopback(char *packet) ! 437: { ! 438: fipc_packet(packet+sizeof(struct ether_header), ! 439: *(struct ether_header*)packet); ! 440: return KERN_SUCCESS; ! 441: } ! 442: ! 443: ! 444: /******************************************************************** ! 445: * Routine: fipc_send ! 446: ********************************************************************/ ! 447: ! 448: kern_return_t syscall_fipc_send(fipc_endpoint_t dest, ! 449: char *user_buffer, int len) ! 450: { ! 451: #ifdef i386 ! 452: static mach_device_t eth_device = 0; ! 453: #else ! 454: static device_t eth_device = 0; ! 455: #endif ! 456: static unsigned char hwaddr[ETHER_HWADDR_SIZE+2]; ! 457: ! 458: io_return_t rc; ! 459: kern_return_t open_res, kr; ! 460: dev_mode_t mode = D_WRITE; ! 461: /* register */ io_req_t ior = NULL; ! 462: struct ether_header *ehdr; ! 463: fipc_header_t *fhdr; ! 464: int *d_addr; ! 465: int data_count; ! 466: char *fipc_buf, *data_buffer; ! 467: #ifdef FIPC_LOOPBACK ! 468: boolean_t local_send = FALSE; ! 469: #endif ! 470: ! 471: #ifdef FI_DEBUG ! 472: printf("fipc_send(dest: %s, port:%d, len:%d, buf:x%x) !!!\n", ! 473: ether_sprintf(dest.hwaddr), dest.port, len, user_buffer); ! 474: #endif ! 475: ! 476: if (dest.port > MAX_FIPC_PORT_NUM || ! 477: len > FIPC_MSG_SIZE) ! 478: { ! 479: #ifdef FI_DEBUG ! 480: printf ("len: %d, dest.port: %u\n", len, dest.port); ! 481: #endif ! 482: return KERN_INVALID_ARGUMENT; ! 483: } ! 484: ! 485: /* We should only need to probe the device once. */ ! 486: ! 487: if (!eth_device) ! 488: { ! 489: unsigned char net_hwaddr[ETHER_HWADDR_SIZE+2]; ! 490: int stat_count = sizeof(net_hwaddr)/sizeof(int); ! 491: ! 492: /* XXX Automatic lookup for ne0 or ne1 was failing... */ ! 493: eth_device = device_lookup(ETHER_DEVICE_NAME); ! 494: #ifdef i386 ! 495: if (eth_device == (mach_device_t) DEVICE_NULL || ! 496: eth_device == (mach_device_t)D_NO_SUCH_DEVICE) ! 497: #else ! 498: if (eth_device == DEVICE_NULL || ! 499: eth_device == (device_t)D_NO_SUCH_DEVICE) ! 500: #endif ! 501: { ! 502: #ifdef FI_DEBUG ! 503: printf ("FIPC: Couldn't find ethernet device %s.\n", ! 504: ETHER_DEVICE_NAME); ! 505: #endif ! 506: return (KERN_FAILURE); ! 507: } ! 508: ! 509: /* The device should be open! */ ! 510: if (eth_device->state != DEV_STATE_OPEN) ! 511: { ! 512: #ifdef FI_DEBUG ! 513: printf ("Opening ethernet device.\n"); ! 514: #endif ! 515: ! 516: io_req_alloc (ior, 0); ! 517: ! 518: io_req_alloc (ior, 0); ! 519: ! 520: ior->io_device = eth_device; ! 521: ior->io_unit = eth_device->dev_number; ! 522: ior->io_op = IO_OPEN | IO_CALL; ! 523: ior->io_mode = mode; ! 524: ior->io_error = 0; ! 525: ior->io_done = 0; ! 526: ior->io_reply_port = MACH_PORT_NULL; ! 527: ior->io_reply_port_type = 0; ! 528: ! 529: /* open the device */ ! 530: open_res = ! 531: (*eth_device->dev_ops->d_open) ! 532: (eth_device->dev_number, ! 533: (int)mode, ior); ! 534: if (ior->io_error != D_SUCCESS) ! 535: { ! 536: #ifdef FI_DEBUG ! 537: printf ("Failed to open device ne0\n"); ! 538: #endif ! 539: return open_res; ! 540: } ! 541: } ! 542: #ifdef i386 ! 543: rc = mach_device_get_status(eth_device, NET_ADDRESS, ! 544: net_hwaddr, &stat_count); ! 545: #else ! 546: rc = ds_device_get_status(eth_device, NET_ADDRESS, net_hwaddr, ! 547: &stat_count); ! 548: #endif ! 549: if (rc != D_SUCCESS) ! 550: { ! 551: #ifdef FI_DEBUG ! 552: printf("FIPC: Couldn't determine hardware ethernet address: %d\n", ! 553: rc); ! 554: #endif ! 555: return KERN_FAILURE; ! 556: } ! 557: *(int*)hwaddr = ntohl(*(int*)net_hwaddr); ! 558: *(int*)(hwaddr+4) = ntohl(*(int*)(net_hwaddr+4)); ! 559: #ifdef FI_DEBUG ! 560: printf ("host: %s\n", ether_sprintf(hwaddr)); ! 561: #endif ! 562: } ! 563: ! 564: #ifdef FIPC_LOOPBACK ! 565: if (!memcmp(dest.hwaddr, hwaddr, ETHER_HWADDR_SIZE)) ! 566: /* ! 567: if ((*(int*)dest.hwaddr == *(int*)hwaddr) && ! 568: ((*(int*)(((char*)dest.hwaddr+4) >> 16)) == ! 569: ((*(int*)(((char*)hwaddr+4) >> 16))))) ! 570: */ ! 571: { ! 572: local_send = TRUE; ! 573: #ifdef FI_DEBUG ! 574: printf ("loopback: \n"); ! 575: printf ("host: %s, ", ether_sprintf(hwaddr)); ! 576: printf ("dest: %s\n", ether_sprintf(dest.hwaddr)); ! 577: #endif ! 578: } ! 579: #endif ! 580: ! 581: data_count = len + sizeof (struct ether_header) ! 582: + sizeof (fipc_header_t); ! 583: ! 584: #ifdef FIPC_LOOPBACK ! 585: fipc_buf = get_fipc_buffer(data_count, local_send, FALSE) ; ! 586: #else ! 587: fipc_buf = get_fipc_buffer(data_count, FALSE, FALSE) ; ! 588: #endif ! 589: ! 590: if (fipc_buf == NULL) ! 591: return KERN_RESOURCE_SHORTAGE; ! 592: ! 593: ehdr = (struct ether_header *)fipc_buf; ! 594: d_addr = (int *)ehdr->ether_dhost; ! 595: ! 596: *(int *)ehdr->ether_dhost = *(int*)dest.hwaddr; ! 597: *(int *)(ehdr->ether_dhost+4) = *(int*)(dest.hwaddr+4); ! 598: *(int *)ehdr->ether_shost = *(int *)hwaddr; ! 599: *(int *)(ehdr->ether_shost+4) = *(int *)(hwaddr+4); ! 600: ehdr->ether_type = 0x1234; /* Yep. */ ! 601: ! 602: #ifdef FIPC_LOOPBACK ! 603: if (!local_send) ! 604: { ! 605: #endif ! 606: if (!ior) ! 607: io_req_alloc (ior, 0); ! 608: ! 609: /* Set up the device information. */ ! 610: ior->io_device = eth_device; ! 611: ior->io_unit = eth_device->dev_number; ! 612: ior->io_op = IO_WRITE | IO_INBAND | IO_INTERNAL; ! 613: ior->io_mode = D_WRITE; ! 614: ior->io_recnum = 0; ! 615: ior->io_data = fipc_buf; ! 616: ior->io_count = data_count; ! 617: ior->io_total = data_count; ! 618: ior->io_alloc_size = 0; ! 619: ior->io_residual = 0; ! 620: ior->io_error = 0; ! 621: ior->io_done = fipc_done; ! 622: ior->io_reply_port = MACH_PORT_NULL; ! 623: ior->io_reply_port_type = 0; ! 624: ior->io_copy = VM_MAP_COPY_NULL; ! 625: #ifdef FIPC_LOOPBACK ! 626: } ! 627: #endif ! 628: ! 629: #ifdef FI_DEBUG ! 630: printf("sending from %s ", ether_sprintf(ehdr->ether_shost)); ! 631: printf("to %s, type x%x, user_port x%x\n", ! 632: ether_sprintf(ehdr->ether_dhost), ! 633: (int)ehdr->ether_type, ! 634: (int)dest.port); ! 635: #endif ! 636: ! 637: if (len <= FIPC_MSG_SIZE) ! 638: { ! 639: fhdr = (fipc_header_t*)(fipc_buf+sizeof(struct ether_header)); ! 640: fhdr->dest_port = dest.port; ! 641: fhdr->msg_size = len; ! 642: data_buffer = (char*)fhdr+sizeof(fipc_header_t); ! 643: ! 644: copyin (user_buffer, data_buffer, ! 645: min (FIPC_BUFFER_SIZE-sizeof(fipc_header_t), len)); ! 646: ! 647: #ifdef FIPC_LOOPBACK ! 648: /* ! 649: * Sending to same node. Queue on dest.port of this node. ! 650: * We just call fipc_packet after setting up the necessary info ! 651: * and return. fipc_packet queues the packet on the receive ! 652: * queue for the destination port. ! 653: */ ! 654: if (local_send) ! 655: return (loopback(fipc_buf)); ! 656: #endif ! 657: ! 658: /* Now write to the device */ ! 659: /* d_port_death has been co-opted for fipc stuff. ! 660: * It maps to nefoutput(). */ ! 661: ! 662: rc = (*eth_device->dev_ops->d_port_death) /* that's the one */ ! 663: (eth_device->dev_number, ior); ! 664: } ! 665: #ifdef FI_DEBUG ! 666: else /* len > ETHERMTU: multi-packet request */ ! 667: printf ("### multi-packet messages are not supported.\n"); ! 668: #endif ! 669: ! 670: if (rc == D_IO_QUEUED) ! 671: return KERN_SUCCESS; ! 672: else ! 673: return KERN_FAILURE; ! 674: } ! 675: ! 676: #ifdef FIPC_LOOPBACK ! 677: if (!local_send) ! 678: { ! 679: #endif ! 680: if (!ior) ! 681: io_req_alloc (ior, 0); ! 682: ! 683: /* Set up the device information. */ ! 684: ior->io_device = eth_device; ! 685: ior->io_unit = eth_device->dev_number; ! 686: ior->io_op = IO_WRITE | IO_INBAND | IO_INTERNAL; ! 687: ior->io_mode = D_WRITE; ! 688: ior->io_recnum = 0; ! 689: ior->io_data = fipc_buf; ! 690: ior->io_count = data_count; ! 691: ior->io_total = data_count; ! 692: ior->io_alloc_size = 0; ! 693: ior->io_residual = 0; ! 694: ior->io_error = 0; ! 695: ior->io_done = fipc_done; ! 696: ior->io_reply_port = MACH_PORT_NULL; ! 697: ior->io_reply_port_type = 0; ! 698: ior->io_copy = VM_MAP_COPY_NULL; ! 699: #ifdef FIPC_LOOPBACK ! 700: } ! 701: #endif ! 702: ! 703: /******************************************************************** ! 704: * syscall_fipc_recv() ! 705: * ! 706: ********************************************************************/ ! 707: ! 708: kern_return_t syscall_fipc_recv(unsigned short user_port, ! 709: char *user_buffer, int *user_size, fipc_endpoint_t *user_sender) ! 710: { ! 711: char* f_buffer; ! 712: fipc_port_t *cfp; ! 713: fipc_buffer_q_ent *crqe; ! 714: int *head; ! 715: int msg_size; ! 716: int fport_num = fipc_lookup(user_port); ! 717: spl_t spl; ! 718: ! 719: #ifdef FI_DEBUG ! 720: printf("fipc_recv(0x%x, 0x%x) !!!\n", user_port, user_buffer); ! 721: #endif ! 722: ! 723: if (user_port > MAX_FIPC_PORT_NUM) ! 724: { ! 725: #ifdef FI_DEBUG ! 726: printf ("Invalid FIPC port: %u\n", user_port); ! 727: #endif ! 728: return KERN_INVALID_ARGUMENT; ! 729: } ! 730: ! 731: if (fport_num == INVALID) ! 732: return KERN_RESOURCE_SHORTAGE; ! 733: ! 734: cfp = &fports[fport_num]; ! 735: head = &cfp->rq_head; ! 736: crqe = &cfp->recv_q[*head]; ! 737: ! 738: if (cfp->bound != FALSE) ! 739: { ! 740: #ifdef FI_DEBUG ! 741: printf ("FIPC Port %u is currently bound.\n", user_port); ! 742: #endif ! 743: return KERN_RESOURCE_SHORTAGE; ! 744: } ! 745: ! 746: copyin(user_size, &msg_size, sizeof(int)); ! 747: ! 748: spl = splimp(); ! 749: ! 750: cfp->bound = TRUE; ! 751: while (!(cfp->valid_msg)) ! 752: { ! 753: assert_wait(&(cfp->valid_msg), TRUE); ! 754: splx(spl); ! 755: thread_block ((void(*)())0); ! 756: if (current_thread()->wait_result != THREAD_AWAKENED) ! 757: { ! 758: cfp->bound = FALSE; ! 759: return KERN_FAILURE; ! 760: } ! 761: spl = splimp(); ! 762: } ! 763: ! 764: cfp->valid_msg--; ! 765: f_buffer = crqe->buffer; ! 766: msg_size = min (crqe->size, msg_size); ! 767: ! 768: crqe->buffer = NULL; ! 769: crqe->size = 0; ! 770: *head = ((*head)+1) % FIPC_RECV_Q_SIZE; ! 771: cfp->bound = FALSE; ! 772: ! 773: splx(spl); ! 774: ! 775: copyout(f_buffer+sizeof(fipc_header_t), user_buffer, msg_size); ! 776: copyout(&(crqe->sender), user_sender, sizeof(fipc_endpoint_t)); ! 777: copyout(&msg_size, user_size, sizeof(msg_size)); ! 778: ! 779: return_fipc_buffer(f_buffer, FIPC_BUFFER_SIZE, TRUE, FALSE); ! 780: ! 781: return KERN_SUCCESS; ! 782: } ! 783: ! 784: ! 785: /* ! 786: * Final clean-up after the packet has been sent off. ! 787: */ ! 788: int fipc_done(io_req_t ior) ! 789: { ! 790: return_fipc_buffer(ior->io_data, FIPC_BUFFER_SIZE, FALSE, FALSE); ! 791: ! 792: return 1; ! 793: } ! 794: ! 795: #endif /* FIPC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.