|
|
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.