|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1993-1989 Carnegie Mellon University
4: * All Rights Reserved.
5: *
6: * Permission to use, copy, modify and distribute this software and its
7: * documentation is hereby granted, provided that both the copyright
8: * notice and this permission notice appear in all copies of the
9: * software, derivative works or modified versions, and any portions
10: * thereof, and that both notices appear in supporting documentation.
11: *
12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15: *
16: * Carnegie Mellon requests users of this software to return to
17: *
18: * Software Distribution Coordinator or [email protected]
19: * School of Computer Science
20: * Carnegie Mellon University
21: * Pittsburgh PA 15213-3890
22: *
23: * any improvements or extensions that they make and grant Carnegie Mellon
24: * the rights to redistribute these changes.
25: */
26: /*
27: * Author: David B. Golub, Carnegie Mellon University
28: * Date: 3/98
29: *
30: * Network IO.
31: *
32: * Packet filter code taken from vaxif/enet.c written
33: * CMU and Stanford.
34: */
35:
36: /*
37: * Note: don't depend on anything in this file.
38: * It may change a lot real soon. -cmaeda 11 June 1993
39: */
40:
41: #include <sys/types.h>
1.1.1.3 root 42: #include <string.h>
43:
1.1 root 44: #include <device/net_status.h>
45: #include <machine/machspl.h> /* spl definitions */
46: #include <device/net_io.h>
47: #include <device/if_hdr.h>
48: #include <device/io_req.h>
49: #include <device/ds_routines.h>
50:
51: #include <mach/boolean.h>
52: #include <mach/vm_param.h>
53:
54: #include <ipc/ipc_port.h>
55: #include <ipc/ipc_kmsg.h>
56: #include <ipc/ipc_mqueue.h>
57:
58: #include <kern/counters.h>
1.1.1.3 root 59: #include <kern/debug.h>
1.1 root 60: #include <kern/lock.h>
1.1.1.3 root 61: #include <kern/printf.h>
1.1 root 62: #include <kern/queue.h>
63: #include <kern/sched_prim.h>
1.1.1.3 root 64: #include <kern/slab.h>
1.1 root 65: #include <kern/thread.h>
66:
67: #include <machine/machspl.h>
68:
69: #if MACH_TTD
70: #include <ttd/ttd_stub.h>
71: #endif /* MACH_TTD */
72:
73: #if MACH_TTD
74: int kttd_async_counter= 0;
75: #endif /* MACH_TTD */
76:
77:
78: /*
79: * Packet Buffer Management
80: *
81: * This module manages a private pool of kmsg buffers.
82: */
83:
84: /*
85: * List of net kmsgs queued to be sent to users.
86: * Messages can be high priority or low priority.
87: * The network thread processes high priority messages first.
88: */
89: decl_simple_lock_data(,net_queue_lock)
90: boolean_t net_thread_awake = FALSE;
91: struct ipc_kmsg_queue net_queue_high;
92: int net_queue_high_size = 0;
93: int net_queue_high_max = 0; /* for debugging */
94: struct ipc_kmsg_queue net_queue_low;
95: int net_queue_low_size = 0;
96: int net_queue_low_max = 0; /* for debugging */
97:
98: /*
99: * List of net kmsgs that can be touched at interrupt level.
100: * If it is empty, we will also steal low priority messages.
101: */
102: decl_simple_lock_data(,net_queue_free_lock)
103: struct ipc_kmsg_queue net_queue_free;
104: int net_queue_free_size = 0; /* on free list */
105: int net_queue_free_max = 0; /* for debugging */
106:
107: /*
108: * This value is critical to network performance.
109: * At least this many buffers should be sitting in net_queue_free.
110: * If this is set too small, we will drop network packets.
111: * Even a low drop rate (<1%) can cause severe network throughput problems.
112: * We add one to net_queue_free_min for every filter.
113: */
114: int net_queue_free_min = 3;
115:
116: int net_queue_free_hits = 0; /* for debugging */
117: int net_queue_free_steals = 0; /* for debugging */
118: int net_queue_free_misses = 0; /* for debugging */
119:
120: int net_kmsg_send_high_hits = 0; /* for debugging */
121: int net_kmsg_send_low_hits = 0; /* for debugging */
122: int net_kmsg_send_high_misses = 0; /* for debugging */
123: int net_kmsg_send_low_misses = 0; /* for debugging */
124:
125: int net_thread_awaken = 0; /* for debugging */
126: int net_ast_taken = 0; /* for debugging */
127:
128: decl_simple_lock_data(,net_kmsg_total_lock)
129: int net_kmsg_total = 0; /* total allocated */
130: int net_kmsg_max; /* initialized below */
131:
132: vm_size_t net_kmsg_size; /* initialized below */
133:
134: /*
135: * We want more buffers when there aren't enough in the free queue
136: * and the low priority queue. However, we don't want to allocate
137: * more than net_kmsg_max.
138: */
139:
140: #define net_kmsg_want_more() \
141: (((net_queue_free_size + net_queue_low_size) < net_queue_free_min) && \
142: (net_kmsg_total < net_kmsg_max))
143:
144: ipc_kmsg_t
145: net_kmsg_get(void)
146: {
1.1.1.4 root 147: ipc_kmsg_t kmsg;
1.1 root 148: spl_t s;
149:
150: /*
151: * First check the list of free buffers.
152: */
153: s = splimp();
154: simple_lock(&net_queue_free_lock);
155: kmsg = ipc_kmsg_queue_first(&net_queue_free);
156: if (kmsg != IKM_NULL) {
157: ipc_kmsg_rmqueue_first_macro(&net_queue_free, kmsg);
158: net_queue_free_size--;
159: net_queue_free_hits++;
160: }
161: simple_unlock(&net_queue_free_lock);
162:
163: if (kmsg == IKM_NULL) {
164: /*
165: * Try to steal from the low priority queue.
166: */
167: simple_lock(&net_queue_lock);
168: kmsg = ipc_kmsg_queue_first(&net_queue_low);
169: if (kmsg != IKM_NULL) {
170: ipc_kmsg_rmqueue_first_macro(&net_queue_low, kmsg);
171: net_queue_low_size--;
172: net_queue_free_steals++;
173: }
174: simple_unlock(&net_queue_lock);
175: }
176:
177: if (kmsg == IKM_NULL)
178: net_queue_free_misses++;
179: (void) splx(s);
180:
181: if (net_kmsg_want_more() || (kmsg == IKM_NULL)) {
182: boolean_t awake;
183:
184: s = splimp();
185: simple_lock(&net_queue_lock);
186: awake = net_thread_awake;
187: net_thread_awake = TRUE;
188: simple_unlock(&net_queue_lock);
189: (void) splx(s);
190:
191: if (!awake)
192: thread_wakeup((event_t) &net_thread_awake);
193: }
194:
195: return kmsg;
196: }
197:
198: void
1.1.1.4 root 199: net_kmsg_put(const ipc_kmsg_t kmsg)
1.1 root 200: {
201: spl_t s;
202:
203: s = splimp();
204: simple_lock(&net_queue_free_lock);
205: ipc_kmsg_enqueue_macro(&net_queue_free, kmsg);
206: if (++net_queue_free_size > net_queue_free_max)
207: net_queue_free_max = net_queue_free_size;
208: simple_unlock(&net_queue_free_lock);
209: (void) splx(s);
210: }
211:
212: void
213: net_kmsg_collect(void)
214: {
1.1.1.4 root 215: ipc_kmsg_t kmsg;
1.1 root 216: spl_t s;
217:
218: s = splimp();
219: simple_lock(&net_queue_free_lock);
220: while (net_queue_free_size > net_queue_free_min) {
221: kmsg = ipc_kmsg_dequeue(&net_queue_free);
222: net_queue_free_size--;
223: simple_unlock(&net_queue_free_lock);
224: (void) splx(s);
225:
226: net_kmsg_free(kmsg);
227: simple_lock(&net_kmsg_total_lock);
228: net_kmsg_total--;
229: simple_unlock(&net_kmsg_total_lock);
230:
231: s = splimp();
232: simple_lock(&net_queue_free_lock);
233: }
234: simple_unlock(&net_queue_free_lock);
235: (void) splx(s);
236: }
237:
238: void
239: net_kmsg_more(void)
240: {
1.1.1.4 root 241: ipc_kmsg_t kmsg;
1.1 root 242:
243: /*
244: * Replenish net kmsg pool if low. We don't have the locks
245: * necessary to look at these variables, but that's OK because
246: * misread values aren't critical. The danger in this code is
247: * that while we allocate buffers, interrupts are happening
248: * which take buffers out of the free list. If we are not
249: * careful, we will sit in the loop and allocate a zillion
250: * buffers while a burst of packets arrives. So we count
251: * buffers in the low priority queue as available, because
252: * net_kmsg_get will make use of them, and we cap the total
253: * number of buffers we are willing to allocate.
254: */
255:
256: while (net_kmsg_want_more()) {
257: simple_lock(&net_kmsg_total_lock);
258: net_kmsg_total++;
259: simple_unlock(&net_kmsg_total_lock);
260: kmsg = net_kmsg_alloc();
261: net_kmsg_put(kmsg);
262: }
263: }
264:
265: /*
266: * Packet Filter Data Structures
267: *
268: * Each network interface has a set of packet filters
269: * that are run on incoming packets.
270: *
271: * Each packet filter may represent a single network
272: * session or multiple network sessions. For example,
273: * all application level TCP sessions would be represented
274: * by a single packet filter data structure.
275: *
276: * If a packet filter has a single session, we use a
277: * struct net_rcv_port to represent it. If the packet
278: * filter represents multiple sessions, we use a
279: * struct net_hash_header to represent it.
280: */
281:
282: /*
283: * Each interface has a write port and a set of read ports.
284: * Each read port has one or more filters to determine what packets
285: * should go to that port.
286: */
287:
288: /*
289: * Receive port for net, with packet filter.
290: * This data structure by itself represents a packet
291: * filter for a single session.
292: */
293: struct net_rcv_port {
1.1.1.3 root 294: queue_chain_t input; /* list of input open_descriptors */
295: queue_chain_t output; /* list of output open_descriptors */
1.1 root 296: ipc_port_t rcv_port; /* port to send packet to */
297: int rcv_qlimit; /* port's qlimit */
298: int rcv_count; /* number of packets received */
299: int priority; /* priority for filter */
300: filter_t *filter_end; /* pointer to end of filter */
301: filter_t filter[NET_MAX_FILTER];
302: /* filter operations */
303: };
304:
1.1.1.3 root 305: struct kmem_cache net_rcv_cache; /* cache of net_rcv_port structs */
1.1 root 306:
307: #define NET_HASH_SIZE 256
308: #define N_NET_HASH 4
309: #define N_NET_HASH_KEYS 4
310:
311: /*
312: * A single hash entry.
313: */
314: struct net_hash_entry {
315: queue_chain_t chain; /* list of entries with same hval */
316: #define he_next chain.next
317: #define he_prev chain.prev
318: ipc_port_t rcv_port; /* destination port */
319: int rcv_qlimit; /* qlimit for the port */
320: unsigned int keys[N_NET_HASH_KEYS];
321: };
322:
1.1.1.3 root 323: struct kmem_cache net_hash_entry_cache;
1.1 root 324:
325: /*
326: * This structure represents a packet filter with multiple sessions.
327: *
328: * For example, all application level TCP sessions might be
329: * represented by one of these structures. It looks like a
330: * net_rcv_port struct so that both types can live on the
331: * same packet filter queues.
332: */
333: struct net_hash_header {
334: struct net_rcv_port rcv;
335: int n_keys; /* zero if not used */
336: int ref_count; /* reference count */
337: net_hash_entry_t table[NET_HASH_SIZE];
338: } filter_hash_header[N_NET_HASH];
339:
340: decl_simple_lock_data(,net_hash_header_lock)
341:
342: #define HASH_ITERATE(head, elt) (elt) = (net_hash_entry_t) (head); do {
343: #define HASH_ITERATE_END(head, elt) \
344: (elt) = (net_hash_entry_t) queue_next((queue_entry_t) (elt)); \
345: } while ((elt) != (head));
346:
1.1.1.3 root 347: #define FILTER_ITERATE(if_port_list, fp, nextfp, chain) \
348: for ((fp) = (net_rcv_port_t) queue_first(if_port_list); \
349: !queue_end(if_port_list, (queue_entry_t)(fp)); \
350: (fp) = (nextfp)) { \
351: (nextfp) = (net_rcv_port_t) queue_next(chain);
1.1 root 352: #define FILTER_ITERATE_END }
353:
354: /* entry_p must be net_rcv_port_t or net_hash_entry_t */
1.1.1.3 root 355: #define ENQUEUE_DEAD(dead, entry_p, chain) { \
1.1.1.5 root 356: (entry_p)->chain.next = (queue_entry_t) (dead); \
1.1 root 357: (dead) = (queue_entry_t)(entry_p); \
358: }
359:
360: /*
361: * ethernet_priority:
362: *
363: * This function properly belongs in the ethernet interfaces;
364: * it should not be called by this module. (We get packet
365: * priorities as an argument to net_filter.) It is here
366: * to avoid massive code duplication.
367: *
368: * Returns TRUE for high-priority packets.
369: */
370:
371: boolean_t ethernet_priority(kmsg)
1.1.1.4 root 372: const ipc_kmsg_t kmsg;
1.1 root 373: {
1.1.1.4 root 374: unsigned char *addr =
1.1 root 375: (unsigned char *) net_kmsg(kmsg)->header;
376:
377: /*
378: * A simplistic check for broadcast packets.
379: */
380:
381: if ((addr[0] == 0xff) && (addr[1] == 0xff) &&
382: (addr[2] == 0xff) && (addr[3] == 0xff) &&
383: (addr[4] == 0xff) && (addr[5] == 0xff))
384: return FALSE;
385: else
386: return TRUE;
387: }
388:
389: mach_msg_type_t header_type = {
390: MACH_MSG_TYPE_BYTE,
391: 8,
392: NET_HDW_HDR_MAX,
393: TRUE,
394: FALSE,
395: FALSE,
396: 0
397: };
398:
399: mach_msg_type_t packet_type = {
400: MACH_MSG_TYPE_BYTE, /* name */
401: 8, /* size */
402: 0, /* number */
403: TRUE, /* inline */
404: FALSE, /* longform */
405: FALSE /* deallocate */
406: };
407:
408: /*
409: * net_deliver:
410: *
411: * Called and returns holding net_queue_lock, at splimp.
412: * Dequeues a message and delivers it at spl0.
413: * Returns FALSE if no messages.
414: */
1.1.1.4 root 415: boolean_t net_deliver(boolean_t nonblocking)
1.1 root 416: {
1.1.1.4 root 417: ipc_kmsg_t kmsg;
1.1 root 418: boolean_t high_priority;
419: struct ipc_kmsg_queue send_list;
420:
421: /*
422: * Pick up a pending network message and deliver it.
423: * Deliver high priority messages before low priority.
424: */
425:
426: if ((kmsg = ipc_kmsg_dequeue(&net_queue_high)) != IKM_NULL) {
427: net_queue_high_size--;
428: high_priority = TRUE;
429: } else if ((kmsg = ipc_kmsg_dequeue(&net_queue_low)) != IKM_NULL) {
430: net_queue_low_size--;
431: high_priority = FALSE;
432: } else
433: return FALSE;
434: simple_unlock(&net_queue_lock);
435: (void) spl0();
436:
437: /*
438: * Run the packet through the filters,
439: * getting back a queue of packets to send.
440: */
441: net_filter(kmsg, &send_list);
442:
443: if (!nonblocking) {
444: /*
445: * There is a danger of running out of available buffers
446: * because they all get moved into the high priority queue
447: * or a port queue. In particular, we might need to
448: * allocate more buffers as we pull (previously available)
449: * buffers out of the low priority queue. But we can only
450: * allocate if we are allowed to block.
451: */
452: net_kmsg_more();
453: }
454:
455: while ((kmsg = ipc_kmsg_dequeue(&send_list)) != IKM_NULL) {
456: int count;
457:
458: /*
459: * Fill in the rest of the kmsg.
460: */
461: count = net_kmsg(kmsg)->net_rcv_msg_packet_count;
462:
463: ikm_init_special(kmsg, IKM_SIZE_NETWORK);
464:
465: kmsg->ikm_header.msgh_bits =
466: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0);
467: /* remember message sizes must be rounded up */
468: kmsg->ikm_header.msgh_size =
1.1.1.3 root 469: (((mach_msg_size_t) (sizeof(struct net_rcv_msg)
1.1.1.4 root 470: - sizeof net_kmsg(kmsg)->sent
1.1.1.3 root 471: - NET_RCV_MAX + count)) + 3) &~ 3;
1.1 root 472: kmsg->ikm_header.msgh_local_port = MACH_PORT_NULL;
473: kmsg->ikm_header.msgh_kind = MACH_MSGH_KIND_NORMAL;
474: kmsg->ikm_header.msgh_id = NET_RCV_MSG_ID;
475:
476: net_kmsg(kmsg)->header_type = header_type;
477: net_kmsg(kmsg)->packet_type = packet_type;
478: net_kmsg(kmsg)->net_rcv_msg_packet_count = count;
479:
480: /*
481: * Send the packet to the destination port. Drop it
482: * if the destination port is over its backlog.
483: */
484:
485: if (ipc_mqueue_send(kmsg, MACH_SEND_TIMEOUT, 0) ==
486: MACH_MSG_SUCCESS) {
487: if (high_priority)
488: net_kmsg_send_high_hits++;
489: else
490: net_kmsg_send_low_hits++;
491: /* the receiver is responsible for the message now */
492: } else {
493: if (high_priority)
494: net_kmsg_send_high_misses++;
495: else
496: net_kmsg_send_low_misses++;
497: ipc_kmsg_destroy(kmsg);
498: }
499: }
500:
501: (void) splimp();
502: simple_lock(&net_queue_lock);
503: return TRUE;
504: }
505:
506: /*
507: * We want to deliver packets using ASTs, so we can avoid the
508: * thread_wakeup/thread_block needed to get to the network
509: * thread. However, we can't allocate memory in the AST handler,
510: * because memory allocation might block. Hence we have the
511: * network thread to allocate memory. The network thread also
512: * delivers packets, so it can be allocating and delivering for a
513: * burst. net_thread_awake is protected by net_queue_lock
514: * (instead of net_queue_free_lock) so that net_packet and
515: * net_ast can safely determine if the network thread is running.
516: * This prevents a race that might leave a packet sitting without
517: * being delivered. It is possible for net_kmsg_get to think
518: * the network thread is awake, and so avoid a wakeup, and then
519: * have the network thread sleep without allocating. The next
520: * net_kmsg_get will do a wakeup.
521: */
522:
1.1.1.4 root 523: void net_ast(void)
1.1 root 524: {
525: spl_t s;
526:
527: net_ast_taken++;
528:
529: /*
530: * If the network thread is awake, then we would
531: * rather deliver messages from it, because
532: * it can also allocate memory.
533: */
534:
535: s = splimp();
536: simple_lock(&net_queue_lock);
537: while (!net_thread_awake && net_deliver(TRUE))
538: continue;
539:
540: /*
541: * Prevent an unnecessary AST. Either the network
542: * thread will deliver the messages, or there are
543: * no messages left to deliver.
544: */
545:
546: simple_unlock(&net_queue_lock);
547: (void) splsched();
548: ast_off(cpu_number(), AST_NETWORK);
549: (void) splx(s);
550: }
551:
1.1.1.4 root 552: void __attribute__ ((noreturn)) net_thread_continue(void)
1.1 root 553: {
554: for (;;) {
555: spl_t s;
556:
557: net_thread_awaken++;
558:
559: /*
560: * First get more buffers.
561: */
562: net_kmsg_more();
563:
564: s = splimp();
565: simple_lock(&net_queue_lock);
566: while (net_deliver(FALSE))
567: continue;
568:
569: net_thread_awake = FALSE;
570: assert_wait(&net_thread_awake, FALSE);
571: simple_unlock(&net_queue_lock);
572: (void) splx(s);
573: counter(c_net_thread_block++);
574: thread_block(net_thread_continue);
575: }
576: }
577:
1.1.1.4 root 578: void net_thread(void)
1.1 root 579: {
580: spl_t s;
581:
582: /*
583: * We should be very high priority.
584: */
585:
586: thread_set_own_priority(0);
587:
588: /*
589: * We sleep initially, so that we don't allocate any buffers
590: * unless the network is really in use and they are needed.
591: */
592:
593: s = splimp();
594: simple_lock(&net_queue_lock);
595: net_thread_awake = FALSE;
596: assert_wait(&net_thread_awake, FALSE);
597: simple_unlock(&net_queue_lock);
598: (void) splx(s);
599: counter(c_net_thread_block++);
600: thread_block(net_thread_continue);
601: net_thread_continue();
602: /*NOTREACHED*/
603: }
604:
605: void
1.1.1.4 root 606: reorder_queue(
607: queue_t first,
608: queue_t last)
1.1 root 609: {
1.1.1.4 root 610: queue_entry_t prev, next;
1.1 root 611:
612: prev = first->prev;
613: next = last->next;
614:
615: prev->next = last;
616: next->prev = first;
617:
618: last->prev = prev;
619: last->next = first;
620:
621: first->next = next;
622: first->prev = last;
623: }
624:
625: /*
626: * Incoming packet. Header has already been moved to proper place.
627: * We are already at splimp.
628: */
629: void
1.1.1.4 root 630: net_packet(
631: struct ifnet *ifp,
632: ipc_kmsg_t kmsg,
633: unsigned int count,
634: boolean_t priority)
1.1 root 635: {
636: boolean_t awake;
637:
638: #if MACH_TTD
639: /*
640: * Do a quick check to see if it is a kernel TTD packet.
641: *
642: * Only check if KernelTTD is enabled, ie. the current
1.1.1.4 root 643: * device driver supports TTD, and the bootp succeeded.
1.1 root 644: */
645: if (kttd_enabled && kttd_handle_async(kmsg)) {
646: /*
647: * Packet was a valid ttd packet and
648: * doesn't need to be passed up to filter.
649: * The ttd code put the used kmsg buffer
650: * back onto the free list.
651: */
652: if (kttd_debug)
653: printf("**%x**", kttd_async_counter++);
654: return;
655: }
656: #endif /* MACH_TTD */
657:
658: kmsg->ikm_header.msgh_remote_port = (mach_port_t) ifp;
659: net_kmsg(kmsg)->net_rcv_msg_packet_count = count;
660:
661: simple_lock(&net_queue_lock);
662: if (priority) {
663: ipc_kmsg_enqueue(&net_queue_high, kmsg);
664: if (++net_queue_high_size > net_queue_high_max)
665: net_queue_high_max = net_queue_high_size;
666: } else {
667: ipc_kmsg_enqueue(&net_queue_low, kmsg);
668: if (++net_queue_low_size > net_queue_low_max)
669: net_queue_low_max = net_queue_low_size;
670: }
671: /*
672: * If the network thread is awake, then we don't
673: * need to take an AST, because the thread will
674: * deliver the packet.
675: */
676: awake = net_thread_awake;
677: simple_unlock(&net_queue_lock);
678:
679: if (!awake) {
680: spl_t s = splsched();
681: ast_on(cpu_number(), AST_NETWORK);
682: (void) splx(s);
683: }
684: }
685:
686: int net_filter_queue_reorder = 0; /* non-zero to enable reordering */
687:
688: /*
689: * Run a packet through the filters, returning a list of messages.
690: * We are *not* called at interrupt level.
691: */
692: void
693: net_filter(kmsg, send_list)
1.1.1.4 root 694: const ipc_kmsg_t kmsg;
1.1 root 695: ipc_kmsg_queue_t send_list;
696: {
1.1.1.4 root 697: struct ifnet *ifp;
698: net_rcv_port_t infp, nextfp;
699: ipc_kmsg_t new_kmsg;
1.1 root 700:
701: net_hash_entry_t entp, *hash_headp;
702: ipc_port_t dest;
703: queue_entry_t dead_infp = (queue_entry_t) 0;
704: queue_entry_t dead_entp = (queue_entry_t) 0;
705: unsigned int ret_count;
706:
1.1.1.3 root 707: queue_head_t *if_port_list;
708:
1.1 root 709: int count = net_kmsg(kmsg)->net_rcv_msg_packet_count;
710: ifp = (struct ifnet *) kmsg->ikm_header.msgh_remote_port;
711: ipc_kmsg_queue_init(send_list);
712:
1.1.1.3 root 713: if (net_kmsg(kmsg)->sent)
714: if_port_list = &ifp->if_snd_port_list;
715: else
716: if_port_list = &ifp->if_rcv_port_list;
717:
1.1 root 718: /*
719: * Unfortunately we can't allocate or deallocate memory
1.1.1.3 root 720: * while holding these locks. And we can't drop the locks
721: * while examining the filter lists.
722: * Both locks are hold in case a filter is removed from both
723: * queues.
1.1 root 724: */
725: simple_lock(&ifp->if_rcv_port_list_lock);
1.1.1.3 root 726: simple_lock(&ifp->if_snd_port_list_lock);
727: FILTER_ITERATE(if_port_list, infp, nextfp,
728: net_kmsg(kmsg)->sent ? &infp->output : &infp->input)
729: {
1.1 root 730: entp = (net_hash_entry_t) 0;
1.1.1.3 root 731: if ((infp->filter[0] & NETF_TYPE_MASK) == NETF_BPF) {
732: ret_count = bpf_do_filter(infp, net_kmsg(kmsg)->packet
733: + sizeof(struct packet_header),
734: count - sizeof(struct packet_header),
735: net_kmsg(kmsg)->header,
736: ifp->if_header_size, &hash_headp,
737: &entp);
1.1 root 738: if (entp == (net_hash_entry_t) 0)
739: dest = infp->rcv_port;
740: else
741: dest = entp->rcv_port;
1.1.1.3 root 742: if (ret_count)
743: ret_count += sizeof(struct packet_header);
1.1 root 744: } else {
745: ret_count = net_do_filter(infp, net_kmsg(kmsg)->packet, count,
746: net_kmsg(kmsg)->header);
747: if (ret_count)
748: ret_count = count;
749: dest = infp->rcv_port;
750: }
751:
752: if (ret_count) {
753:
754: /*
755: * Make a send right for the destination.
756: */
757:
758: dest = ipc_port_copy_send(dest);
759: if (!IP_VALID(dest)) {
760: /*
761: * This filter is dead. We remove it from the
762: * filter list and set it aside for deallocation.
763: */
764:
765: if (entp == (net_hash_entry_t) 0) {
1.1.1.3 root 766: if (infp->filter[0] & NETF_IN)
767: queue_remove(&ifp->if_rcv_port_list, infp,
768: net_rcv_port_t, input);
769: if (infp->filter[0] & NETF_OUT)
770: queue_remove(&ifp->if_snd_port_list, infp,
771: net_rcv_port_t, output);
772:
773: /* Use input only for queues of dead filters. */
774: ENQUEUE_DEAD(dead_infp, infp, input);
1.1 root 775: continue;
776: } else {
777: hash_ent_remove (ifp,
778: (net_hash_header_t)infp,
779: FALSE, /* no longer used */
780: hash_headp,
781: entp,
782: &dead_entp);
783: continue;
784: }
785: }
786:
787: /*
788: * Deliver copy of packet to this channel.
789: */
790: if (ipc_kmsg_queue_empty(send_list)) {
791: /*
792: * Only receiver, so far
793: */
794: new_kmsg = kmsg;
795: } else {
796: /*
797: * Other receivers - must allocate message and copy.
798: */
799: new_kmsg = net_kmsg_get();
800: if (new_kmsg == IKM_NULL) {
801: ipc_port_release_send(dest);
802: break;
803: }
804:
1.1.1.3 root 805: memcpy(
1.1 root 806: net_kmsg(new_kmsg)->packet,
1.1.1.3 root 807: net_kmsg(kmsg)->packet,
1.1 root 808: ret_count);
1.1.1.3 root 809: memcpy(
1.1 root 810: net_kmsg(new_kmsg)->header,
1.1.1.3 root 811: net_kmsg(kmsg)->header,
1.1 root 812: NET_HDW_HDR_MAX);
813: }
814: net_kmsg(new_kmsg)->net_rcv_msg_packet_count = ret_count;
815: new_kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest;
816: ipc_kmsg_enqueue(send_list, new_kmsg);
817:
818: {
1.1.1.4 root 819: net_rcv_port_t prevfp;
1.1 root 820: int rcount = ++infp->rcv_count;
821:
822: /*
823: * See if ordering of filters is wrong
824: */
825: if (infp->priority >= NET_HI_PRI) {
1.1.1.3 root 826: #define REORDER_PRIO(chain) \
827: prevfp = (net_rcv_port_t) queue_prev(&infp->chain); \
828: /* \
829: * If infp is not the first element on the queue, \
830: * and the previous element is at equal priority \
831: * but has a lower count, then promote infp to \
832: * be in front of prevfp. \
833: */ \
834: if ((queue_t)prevfp != if_port_list && \
835: infp->priority == prevfp->priority) { \
836: /* \
837: * Threshold difference to prevent thrashing \
838: */ \
839: if (net_filter_queue_reorder \
840: && (100 + prevfp->rcv_count < rcount)) \
841: reorder_queue(&prevfp->chain, &infp->chain);\
1.1 root 842: }
1.1.1.3 root 843:
844: REORDER_PRIO(input);
845: REORDER_PRIO(output);
846:
1.1 root 847: /*
848: * High-priority filter -> no more deliveries
849: */
850: break;
851: }
852: }
853: }
854: }
855: FILTER_ITERATE_END
1.1.1.3 root 856: simple_unlock(&ifp->if_snd_port_list_lock);
1.1 root 857: simple_unlock(&ifp->if_rcv_port_list_lock);
858:
859: /*
860: * Deallocate dead filters.
861: */
862: if (dead_infp != 0)
863: net_free_dead_infp(dead_infp);
864: if (dead_entp != 0)
865: net_free_dead_entp(dead_entp);
866:
867: if (ipc_kmsg_queue_empty(send_list)) {
868: /* Not sent - recycle */
869: net_kmsg_put(kmsg);
870: }
871: }
872:
873: boolean_t
874: net_do_filter(infp, data, data_count, header)
875: net_rcv_port_t infp;
1.1.1.4 root 876: const char * data;
1.1 root 877: unsigned int data_count;
1.1.1.4 root 878: const char * header;
1.1 root 879: {
880: int stack[NET_FILTER_STACK_DEPTH+1];
1.1.1.4 root 881: int *sp;
882: filter_t *fp, *fpe;
883: unsigned int op, arg;
1.1 root 884:
885: /*
886: * The filter accesses the header and data
887: * as unsigned short words.
888: */
889: data_count /= sizeof(unsigned short);
890:
891: #define data_word ((unsigned short *)data)
892: #define header_word ((unsigned short *)header)
893:
894: sp = &stack[NET_FILTER_STACK_DEPTH];
1.1.1.3 root 895: fp = &infp->filter[1]; /* filter[0] used for flags */
1.1 root 896: fpe = infp->filter_end;
897:
898: *sp = TRUE;
899:
900: while (fp < fpe) {
901: arg = *fp++;
902: op = NETF_OP(arg);
903: arg = NETF_ARG(arg);
904:
905: switch (arg) {
906: case NETF_NOPUSH:
907: arg = *sp++;
908: break;
909: case NETF_PUSHZERO:
910: arg = 0;
911: break;
912: case NETF_PUSHLIT:
913: arg = *fp++;
914: break;
915: case NETF_PUSHIND:
916: arg = *sp++;
917: if (arg >= data_count)
918: return FALSE;
919: arg = data_word[arg];
920: break;
921: case NETF_PUSHHDRIND:
922: arg = *sp++;
923: if (arg >= NET_HDW_HDR_MAX/sizeof(unsigned short))
924: return FALSE;
925: arg = header_word[arg];
926: break;
927: default:
928: if (arg >= NETF_PUSHSTK) {
929: arg = sp[arg - NETF_PUSHSTK];
930: }
931: else if (arg >= NETF_PUSHHDR) {
932: arg = header_word[arg - NETF_PUSHHDR];
933: }
934: else {
935: arg -= NETF_PUSHWORD;
936: if (arg >= data_count)
937: return FALSE;
938: arg = data_word[arg];
939: }
940: break;
941:
942: }
943: switch (op) {
944: case NETF_OP(NETF_NOP):
945: *--sp = arg;
946: break;
947: case NETF_OP(NETF_AND):
948: *sp &= arg;
949: break;
950: case NETF_OP(NETF_OR):
951: *sp |= arg;
952: break;
953: case NETF_OP(NETF_XOR):
954: *sp ^= arg;
955: break;
956: case NETF_OP(NETF_EQ):
957: *sp = (*sp == arg);
958: break;
959: case NETF_OP(NETF_NEQ):
960: *sp = (*sp != arg);
961: break;
962: case NETF_OP(NETF_LT):
963: *sp = (*sp < arg);
964: break;
965: case NETF_OP(NETF_LE):
966: *sp = (*sp <= arg);
967: break;
968: case NETF_OP(NETF_GT):
969: *sp = (*sp > arg);
970: break;
971: case NETF_OP(NETF_GE):
972: *sp = (*sp >= arg);
973: break;
974: case NETF_OP(NETF_COR):
975: if (*sp++ == arg)
976: return (TRUE);
977: break;
978: case NETF_OP(NETF_CAND):
979: if (*sp++ != arg)
980: return (FALSE);
981: break;
982: case NETF_OP(NETF_CNOR):
983: if (*sp++ == arg)
984: return (FALSE);
985: break;
986: case NETF_OP(NETF_CNAND):
987: if (*sp++ != arg)
988: return (TRUE);
989: break;
990: case NETF_OP(NETF_LSH):
991: *sp <<= arg;
992: break;
993: case NETF_OP(NETF_RSH):
994: *sp >>= arg;
995: break;
996: case NETF_OP(NETF_ADD):
997: *sp += arg;
998: break;
999: case NETF_OP(NETF_SUB):
1000: *sp -= arg;
1001: break;
1002: }
1003: }
1004: return ((*sp) ? TRUE : FALSE);
1005:
1006: #undef data_word
1007: #undef header_word
1008: }
1009:
1010: /*
1011: * Check filter for invalid operations or stack over/under-flow.
1012: */
1013: boolean_t
1.1.1.4 root 1014: parse_net_filter(
1015: filter_t *filter,
1016: unsigned int count)
1017: {
1018: int sp;
1019: filter_t *fpe = &filter[count];
1020: filter_t op, arg;
1.1 root 1021:
1.1.1.3 root 1022: /*
1023: * count is at least 1, and filter[0] is used for flags.
1024: */
1025: filter++;
1.1 root 1026: sp = NET_FILTER_STACK_DEPTH;
1027:
1028: for (; filter < fpe; filter++) {
1029: op = NETF_OP(*filter);
1030: arg = NETF_ARG(*filter);
1031:
1032: switch (arg) {
1033: case NETF_NOPUSH:
1034: break;
1035: case NETF_PUSHZERO:
1036: sp--;
1037: break;
1038: case NETF_PUSHLIT:
1039: filter++;
1040: if (filter >= fpe)
1041: return (FALSE); /* literal value not in filter */
1042: sp--;
1043: break;
1044: case NETF_PUSHIND:
1045: case NETF_PUSHHDRIND:
1046: break;
1047: default:
1048: if (arg >= NETF_PUSHSTK) {
1049: if (arg - NETF_PUSHSTK + sp > NET_FILTER_STACK_DEPTH)
1050: return FALSE;
1051: }
1052: else if (arg >= NETF_PUSHHDR) {
1053: if (arg - NETF_PUSHHDR >=
1054: NET_HDW_HDR_MAX/sizeof(unsigned short))
1055: return FALSE;
1056: }
1057: /* else... cannot check for packet bounds
1058: without packet */
1059: sp--;
1060: break;
1061: }
1062: if (sp < 2) {
1063: return (FALSE); /* stack overflow */
1064: }
1065: if (op == NETF_OP(NETF_NOP))
1066: continue;
1067:
1068: /*
1069: * all non-NOP operators are binary.
1070: */
1071: if (sp > NET_MAX_FILTER-2)
1072: return (FALSE);
1073:
1074: sp++;
1075: switch (op) {
1076: case NETF_OP(NETF_AND):
1077: case NETF_OP(NETF_OR):
1078: case NETF_OP(NETF_XOR):
1079: case NETF_OP(NETF_EQ):
1080: case NETF_OP(NETF_NEQ):
1081: case NETF_OP(NETF_LT):
1082: case NETF_OP(NETF_LE):
1083: case NETF_OP(NETF_GT):
1084: case NETF_OP(NETF_GE):
1085: case NETF_OP(NETF_COR):
1086: case NETF_OP(NETF_CAND):
1087: case NETF_OP(NETF_CNOR):
1088: case NETF_OP(NETF_CNAND):
1089: case NETF_OP(NETF_LSH):
1090: case NETF_OP(NETF_RSH):
1091: case NETF_OP(NETF_ADD):
1092: case NETF_OP(NETF_SUB):
1093: break;
1094: default:
1095: return (FALSE);
1096: }
1097: }
1098: return (TRUE);
1099: }
1100:
1101: /*
1102: * Set a filter for a network interface.
1103: *
1104: * We are given a naked send right for the rcv_port.
1105: * If we are successful, we must consume that right.
1106: */
1107: io_return_t
1.1.1.4 root 1108: net_set_filter(
1109: struct ifnet *ifp,
1110: ipc_port_t rcv_port,
1111: int priority,
1112: filter_t *filter,
1113: unsigned int filter_count)
1.1 root 1114: {
1115: int filter_bytes;
1116: bpf_insn_t match;
1.1.1.4 root 1117: net_rcv_port_t infp, my_infp;
1.1 root 1118: net_rcv_port_t nextfp;
1119: net_hash_header_t hhp;
1.1.1.4 root 1120: net_hash_entry_t entp;
1.1 root 1121: net_hash_entry_t *head, nextentp;
1122: queue_entry_t dead_infp, dead_entp;
1123: int i;
1124: int ret, is_new_infp;
1125: io_return_t rval;
1.1.1.3 root 1126: boolean_t in, out;
1.1 root 1127:
1.1.1.4 root 1128: /* Initialize hash_entp to NULL to quiet GCC
1129: * warning about uninitialized variable. hash_entp is only
1130: * used when match != 0; in that case it is properly initialized
1131: * by kmem_cache_alloc().
1132: */
1133: net_hash_entry_t hash_entp = NULL;
1134:
1.1 root 1135: /*
1136: * Check the filter syntax.
1137: */
1138:
1139: filter_bytes = CSPF_BYTES(filter_count);
1140: match = (bpf_insn_t) 0;
1141:
1.1.1.3 root 1142: if (filter_count == 0) {
1143: return (D_INVALID_OPERATION);
1144: } else if (!((filter[0] & NETF_IN) || (filter[0] & NETF_OUT))) {
1145: return (D_INVALID_OPERATION); /* NETF_IN or NETF_OUT required */
1146: } else if ((filter[0] & NETF_TYPE_MASK) == NETF_BPF) {
1.1 root 1147: ret = bpf_validate((bpf_insn_t)filter, filter_bytes, &match);
1148: if (!ret)
1149: return (D_INVALID_OPERATION);
1.1.1.3 root 1150: } else if ((filter[0] & NETF_TYPE_MASK) == 0) {
1.1 root 1151: if (!parse_net_filter(filter, filter_count))
1152: return (D_INVALID_OPERATION);
1.1.1.3 root 1153: } else {
1154: return (D_INVALID_OPERATION);
1.1 root 1155: }
1156:
1157: rval = D_SUCCESS; /* default return value */
1158: dead_infp = dead_entp = 0;
1159:
1160: if (match == (bpf_insn_t) 0) {
1161: /*
1162: * If there is no match instruction, we allocate
1163: * a normal packet filter structure.
1164: */
1.1.1.3 root 1165: my_infp = (net_rcv_port_t) kmem_cache_alloc(&net_rcv_cache);
1.1 root 1166: my_infp->rcv_port = rcv_port;
1167: is_new_infp = TRUE;
1168: } else {
1169: /*
1.1.1.3 root 1170: * If there is a match instruction, we assume there will be
1171: * multiple sessions with a common substructure and allocate
1.1 root 1172: * a hash table to deal with them.
1173: */
1174: my_infp = 0;
1.1.1.3 root 1175: hash_entp = (net_hash_entry_t) kmem_cache_alloc(&net_hash_entry_cache);
1.1 root 1176: is_new_infp = FALSE;
1177: }
1178:
1179: /*
1180: * Look for an existing filter on the same reply port.
1181: * Look for filters with dead ports (for GC).
1182: * Look for a filter with the same code except KEY insns.
1183: */
1.1.1.3 root 1184: void check_filter_list(queue_head_t *if_port_list)
1.1 root 1185: {
1.1.1.3 root 1186: FILTER_ITERATE(if_port_list, infp, nextfp,
1187: (if_port_list == &ifp->if_rcv_port_list)
1188: ? &infp->input : &infp->output)
1189: {
1.1 root 1190: if (infp->rcv_port == MACH_PORT_NULL) {
1.1.1.3 root 1191: if (match != 0
1192: && infp->priority == priority
1193: && my_infp == 0
1194: && (infp->filter_end - infp->filter) == filter_count
1195: && bpf_eq((bpf_insn_t)infp->filter,
1196: (bpf_insn_t)filter, filter_bytes))
1197: my_infp = infp;
1198:
1199: for (i = 0; i < NET_HASH_SIZE; i++) {
1200: head = &((net_hash_header_t) infp)->table[i];
1201: if (*head == 0)
1202: continue;
1203:
1204: /*
1205: * Check each hash entry to make sure the
1206: * destination port is still valid. Remove
1207: * any invalid entries.
1208: */
1209: entp = *head;
1210: do {
1211: nextentp = (net_hash_entry_t) entp->he_next;
1.1 root 1212:
1.1.1.3 root 1213: /* checked without
1214: ip_lock(entp->rcv_port) */
1215: if (entp->rcv_port == rcv_port
1216: || !IP_VALID(entp->rcv_port)
1217: || !ip_active(entp->rcv_port)) {
1218: ret = hash_ent_remove (ifp,
1219: (net_hash_header_t)infp,
1220: (my_infp == infp),
1221: head,
1222: entp,
1223: &dead_entp);
1224: if (ret)
1225: goto hash_loop_end;
1226: }
1.1 root 1227:
1.1.1.3 root 1228: entp = nextentp;
1229: /* While test checks head since hash_ent_remove
1230: might modify it.
1231: */
1232: } while (*head != 0 && entp != *head);
1233: }
1234:
1.1 root 1235: hash_loop_end:
1236: ;
1237: } else if (infp->rcv_port == rcv_port
1238: || !IP_VALID(infp->rcv_port)
1239: || !ip_active(infp->rcv_port)) {
1.1.1.3 root 1240:
1241: /* Remove the old filter from lists */
1242: if (infp->filter[0] & NETF_IN)
1243: queue_remove(&ifp->if_rcv_port_list, infp,
1244: net_rcv_port_t, input);
1245: if (infp->filter[0] & NETF_OUT)
1246: queue_remove(&ifp->if_snd_port_list, infp,
1247: net_rcv_port_t, output);
1248:
1249: ENQUEUE_DEAD(dead_infp, infp, input);
1.1 root 1250: }
1.1.1.3 root 1251: }
1252: FILTER_ITERATE_END
1.1 root 1253: }
1.1.1.3 root 1254:
1255: in = (filter[0] & NETF_IN) != 0;
1256: out = (filter[0] & NETF_OUT) != 0;
1257:
1258: simple_lock(&ifp->if_rcv_port_list_lock);
1259: simple_lock(&ifp->if_snd_port_list_lock);
1260:
1261: if (in)
1262: check_filter_list(&ifp->if_rcv_port_list);
1263: if (out)
1264: check_filter_list(&ifp->if_snd_port_list);
1.1 root 1265:
1266: if (my_infp == 0) {
1267: /* Allocate a dummy infp */
1268: simple_lock(&net_hash_header_lock);
1269: for (i = 0; i < N_NET_HASH; i++) {
1270: if (filter_hash_header[i].n_keys == 0)
1271: break;
1272: }
1273: if (i == N_NET_HASH) {
1274: simple_unlock(&net_hash_header_lock);
1.1.1.3 root 1275: simple_unlock(&ifp->if_snd_port_list_lock);
1.1 root 1276: simple_unlock(&ifp->if_rcv_port_list_lock);
1277:
1278: ipc_port_release_send(rcv_port);
1279: if (match != 0)
1.1.1.3 root 1280: kmem_cache_free(&net_hash_entry_cache,
1281: (vm_offset_t)hash_entp);
1.1 root 1282:
1283: rval = D_NO_MEMORY;
1284: goto clean_and_return;
1285: }
1286:
1287: hhp = &filter_hash_header[i];
1288: hhp->n_keys = match->jt;
1289: simple_unlock(&net_hash_header_lock);
1290:
1291: hhp->ref_count = 0;
1292: for (i = 0; i < NET_HASH_SIZE; i++)
1293: hhp->table[i] = 0;
1294:
1295: my_infp = (net_rcv_port_t)hhp;
1296: my_infp->rcv_port = MACH_PORT_NULL; /* indication of dummy */
1297: is_new_infp = TRUE;
1298: }
1299:
1300: if (is_new_infp) {
1301: my_infp->priority = priority;
1302: my_infp->rcv_count = 0;
1303:
1304: /* Copy filter program. */
1.1.1.3 root 1305: memcpy (my_infp->filter, filter, filter_bytes);
1.1 root 1306: my_infp->filter_end =
1307: (filter_t *)((char *)my_infp->filter + filter_bytes);
1308:
1309: if (match == 0) {
1310: my_infp->rcv_qlimit = net_add_q_info(rcv_port);
1311: } else {
1312: my_infp->rcv_qlimit = 0;
1313: }
1314:
1315: /* Insert my_infp according to priority */
1.1.1.3 root 1316: if (in) {
1317: queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, input)
1318: if (priority > infp->priority)
1319: break;
1320:
1321: queue_enter(&ifp->if_rcv_port_list, my_infp, net_rcv_port_t, input);
1322: }
1323:
1324: if (out) {
1325: queue_iterate(&ifp->if_snd_port_list, infp, net_rcv_port_t, output)
1326: if (priority > infp->priority)
1327: break;
1328:
1329: queue_enter(&ifp->if_snd_port_list, my_infp, net_rcv_port_t, output);
1330: }
1.1 root 1331: }
1332:
1333: if (match != 0)
1334: { /* Insert to hash list */
1335: net_hash_entry_t *p;
1336:
1337: hash_entp->rcv_port = rcv_port;
1338: for (i = 0; i < match->jt; i++) /* match->jt is n_keys */
1339: hash_entp->keys[i] = match[i+1].k;
1340: p = &((net_hash_header_t)my_infp)->
1341: table[bpf_hash(match->jt, hash_entp->keys)];
1342:
1343: /* Not checking for the same key values */
1344: if (*p == 0) {
1.1.1.3 root 1345: queue_init (&hash_entp->chain);
1.1 root 1346: *p = hash_entp;
1347: } else {
1.1.1.3 root 1348: enqueue_tail(&(*p)->chain, &hash_entp->chain);
1.1 root 1349: }
1350:
1351: ((net_hash_header_t)my_infp)->ref_count++;
1352: hash_entp->rcv_qlimit = net_add_q_info(rcv_port);
1353: }
1354:
1.1.1.3 root 1355: simple_unlock(&ifp->if_snd_port_list_lock);
1.1 root 1356: simple_unlock(&ifp->if_rcv_port_list_lock);
1357:
1358: clean_and_return:
1359: /* No locks are held at this point. */
1360:
1361: if (dead_infp != 0)
1362: net_free_dead_infp(dead_infp);
1363: if (dead_entp != 0)
1364: net_free_dead_entp(dead_entp);
1365:
1366: return (rval);
1367: }
1368:
1369: /*
1370: * Other network operations
1371: */
1372: io_return_t
1.1.1.4 root 1373: net_getstat(
1374: struct ifnet *ifp,
1375: dev_flavor_t flavor,
1376: dev_status_t status, /* pointer to OUT array */
1377: natural_t *count) /* OUT */
1.1 root 1378: {
1379: switch (flavor) {
1380: case NET_STATUS:
1381: {
1.1.1.4 root 1382: struct net_status *ns = (struct net_status *)status;
1.1 root 1383:
1384: if (*count < NET_STATUS_COUNT)
1385: return (D_INVALID_OPERATION);
1386:
1387: ns->min_packet_size = ifp->if_header_size;
1388: ns->max_packet_size = ifp->if_header_size + ifp->if_mtu;
1389: ns->header_format = ifp->if_header_format;
1390: ns->header_size = ifp->if_header_size;
1391: ns->address_size = ifp->if_address_size;
1392: ns->flags = ifp->if_flags;
1393: ns->mapped_size = 0;
1394:
1395: *count = NET_STATUS_COUNT;
1396: break;
1397: }
1398: case NET_ADDRESS:
1399: {
1.1.1.4 root 1400: int addr_byte_count;
1401: int addr_int_count;
1402: int i;
1.1 root 1403:
1404: addr_byte_count = ifp->if_address_size;
1405: addr_int_count = (addr_byte_count + (sizeof(int)-1))
1406: / sizeof(int);
1407:
1408: if (*count < addr_int_count)
1409: {
1410: /* XXX debug hack. */
1411: printf ("net_getstat: count: %d, addr_int_count: %d\n",
1412: *count, addr_int_count);
1413: return (D_INVALID_OPERATION);
1414: }
1415:
1.1.1.3 root 1416: memcpy(status, ifp->if_address, addr_byte_count);
1.1 root 1417: if (addr_byte_count < addr_int_count * sizeof(int))
1.1.1.3 root 1418: memset((char *)status + addr_byte_count, 0,
1419: (addr_int_count * sizeof(int)
1.1 root 1420: - addr_byte_count));
1421:
1422: for (i = 0; i < addr_int_count; i++) {
1.1.1.4 root 1423: int word;
1.1 root 1424:
1425: word = status[i];
1426: status[i] = htonl(word);
1427: }
1428: *count = addr_int_count;
1429: break;
1430: }
1431: default:
1432: return (D_INVALID_OPERATION);
1433: }
1434: return (D_SUCCESS);
1435: }
1436:
1437: io_return_t
1.1.1.4 root 1438: net_write(
1439: struct ifnet *ifp,
1440: int (*start)(),
1441: io_req_t ior)
1.1 root 1442: {
1443: spl_t s;
1444: kern_return_t rc;
1445: boolean_t wait;
1446:
1447: /*
1448: * Reject the write if the interface is down.
1449: */
1450: if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING))
1451: return (D_DEVICE_DOWN);
1452:
1453: /*
1454: * Reject the write if the packet is too large or too small.
1455: */
1456: if (ior->io_count < ifp->if_header_size ||
1457: ior->io_count > ifp->if_header_size + ifp->if_mtu)
1458: return (D_INVALID_SIZE);
1459:
1460: /*
1461: * Wire down the memory.
1462: */
1463:
1464: rc = device_write_get(ior, &wait);
1465: if (rc != KERN_SUCCESS)
1466: return (rc);
1467:
1468: /*
1469: * Network interfaces can't cope with VM continuations.
1470: * If wait is set, just panic.
1471: */
1472: if (wait) {
1473: panic("net_write: VM continuation");
1474: }
1475:
1476: /*
1477: * Queue the packet on the output queue, and
1478: * start the device.
1479: */
1480: s = splimp();
1481: IF_ENQUEUE(&ifp->if_snd, ior);
1482: (*start)(ifp->if_unit);
1483: splx(s);
1484:
1485: return (D_IO_QUEUED);
1486: }
1487:
1488: /*
1489: * Initialize the whole package.
1490: */
1491: void
1.1.1.4 root 1492: net_io_init(void)
1.1 root 1493: {
1.1.1.4 root 1494: vm_size_t size;
1.1 root 1495:
1496: size = sizeof(struct net_rcv_port);
1.1.1.3 root 1497: kmem_cache_init(&net_rcv_cache, "net_rcv_port", size, 0,
1.1.1.6 ! root 1498: NULL, 0);
1.1 root 1499:
1500: size = sizeof(struct net_hash_entry);
1.1.1.3 root 1501: kmem_cache_init(&net_hash_entry_cache, "net_hash_entry", size, 0,
1.1.1.6 ! root 1502: NULL, 0);
1.1 root 1503:
1504: size = ikm_plus_overhead(sizeof(struct net_rcv_msg));
1505: net_kmsg_size = round_page(size);
1506:
1507: /*
1508: * net_kmsg_max caps the number of buffers
1509: * we are willing to allocate. By default,
1510: * we allow for net_queue_free_min plus
1511: * the queue limit for each filter.
1512: * (Added as the filters are added.)
1513: */
1514:
1515: simple_lock_init(&net_kmsg_total_lock);
1516: if (net_kmsg_max == 0)
1517: net_kmsg_max = net_queue_free_min;
1518:
1519: simple_lock_init(&net_queue_free_lock);
1520: ipc_kmsg_queue_init(&net_queue_free);
1521:
1522: simple_lock_init(&net_queue_lock);
1523: ipc_kmsg_queue_init(&net_queue_high);
1524: ipc_kmsg_queue_init(&net_queue_low);
1525:
1526: simple_lock_init(&net_hash_header_lock);
1527: }
1528:
1529:
1530: /* ======== BPF: Berkeley Packet Filter ======== */
1531:
1532: /*-
1533: * Copyright (c) 1990-1991 The Regents of the University of California.
1534: * All rights reserved.
1535: *
1536: * This code is derived from the Stanford/CMU enet packet filter,
1537: * (net/enet.c) distributed as part of 4.3BSD, and code contributed
1538: * to Berkeley by Steven McCanne and Van Jacobson both of Lawrence
1539: * Berkeley Laboratory.
1540: *
1541: * Redistribution and use in source and binary forms, with or without
1542: * modification, are permitted provided that the following conditions
1543: * are met:
1544: * 1. Redistributions of source code must retain the above copyright
1545: * notice, this list of conditions and the following disclaimer.
1546: * 2. Redistributions in binary form must reproduce the above copyright
1547: * notice, this list of conditions and the following disclaimer in the
1548: * documentation and/or other materials provided with the distribution.
1549: * 4. Neither the name of the University nor the names of its contributors
1550: * may be used to endorse or promote products derived from this software
1551: * without specific prior written permission.
1552: *
1553: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
1554: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1555: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1556: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
1557: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1558: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1559: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
1560: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
1561: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
1562: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
1563: * SUCH DAMAGE.
1564: *
1565: * @(#)bpf.c 7.5 (Berkeley) 7/15/91
1566: */
1567:
1568: #if defined(sparc) || defined(mips) || defined(ibm032) || defined(alpha)
1569: #define BPF_ALIGN
1570: #endif
1571:
1572: #ifndef BPF_ALIGN
1573: #define EXTRACT_SHORT(p) ((u_short)ntohs(*(u_short *)p))
1574: #define EXTRACT_LONG(p) (ntohl(*(u_long *)p))
1575: #else
1576: #define EXTRACT_SHORT(p)\
1577: ((u_short)\
1578: ((u_short)*((u_char *)p+0)<<8|\
1579: (u_short)*((u_char *)p+1)<<0))
1580: #define EXTRACT_LONG(p)\
1581: ((u_long)*((u_char *)p+0)<<24|\
1582: (u_long)*((u_char *)p+1)<<16|\
1583: (u_long)*((u_char *)p+2)<<8|\
1584: (u_long)*((u_char *)p+3)<<0)
1585: #endif
1586:
1587: /*
1588: * Execute the filter program starting at pc on the packet p
1589: * wirelen is the length of the original packet
1590: * buflen is the amount of data present
1591: */
1592:
1593: int
1.1.1.4 root 1594: bpf_do_filter(
1595: net_rcv_port_t infp,
1596: char * p, /* packet data */
1597: unsigned int wirelen, /* data_count (in bytes) */
1598: char * header,
1599: unsigned int hlen, /* header len (in bytes) */
1600: net_hash_entry_t **hash_headpp,
1601: net_hash_entry_t *entpp) /* out */
1.1 root 1602: {
1.1.1.4 root 1603: bpf_insn_t pc, pc_end;
1604: unsigned int buflen;
1.1 root 1605:
1.1.1.4 root 1606: unsigned int A, X;
1607: int k;
1.1.1.3 root 1608: unsigned int mem[BPF_MEMWORDS];
1609:
1610: /* Generic pointer to either HEADER or P according to the specified offset. */
1611: char *data = NULL;
1.1 root 1612:
1613: pc = ((bpf_insn_t) infp->filter) + 1;
1.1.1.3 root 1614: /* filter[0].code is (NETF_BPF | flags) */
1.1 root 1615: pc_end = (bpf_insn_t)infp->filter_end;
1616: buflen = NET_RCV_MAX;
1617: *entpp = 0; /* default */
1618:
1619: A = 0;
1620: X = 0;
1.1.1.3 root 1621:
1.1 root 1622: for (; pc < pc_end; ++pc) {
1623: switch (pc->code) {
1624:
1625: default:
1626: #ifdef KERNEL
1627: return 0;
1628: #else
1629: abort();
1630: #endif
1631: case BPF_RET|BPF_K:
1632: if (infp->rcv_port == MACH_PORT_NULL &&
1633: *entpp == 0) {
1634: return 0;
1635: }
1636: return ((u_int)pc->k <= wirelen) ?
1637: pc->k : wirelen;
1638:
1639: case BPF_RET|BPF_A:
1640: if (infp->rcv_port == MACH_PORT_NULL &&
1641: *entpp == 0) {
1642: return 0;
1643: }
1644: return ((u_int)A <= wirelen) ?
1645: A : wirelen;
1646:
1647: case BPF_RET|BPF_MATCH_IMM:
1648: if (bpf_match ((net_hash_header_t)infp, pc->jt, mem,
1649: hash_headpp, entpp)) {
1650: return ((u_int)pc->k <= wirelen) ?
1651: pc->k : wirelen;
1652: }
1653: return 0;
1654:
1655: case BPF_LD|BPF_W|BPF_ABS:
1656: k = pc->k;
1657:
1.1.1.3 root 1658: load_word:
1659: if ((u_int)k + sizeof(int) <= hlen)
1660: data = header;
1661: else if ((u_int)k + sizeof(int) <= buflen) {
1662: k -= hlen;
1663: data = p;
1664: } else
1665: return 0;
1666:
1.1 root 1667: #ifdef BPF_ALIGN
1.1.1.3 root 1668: if (((int)(data + k) & 3) != 0)
1669: A = EXTRACT_LONG(&data[k]);
1670: else
1.1 root 1671: #endif
1.1.1.3 root 1672: A = ntohl(*(int *)(data + k));
1673: continue;
1.1 root 1674:
1675: case BPF_LD|BPF_H|BPF_ABS:
1676: k = pc->k;
1677:
1.1.1.3 root 1678: load_half:
1679: if ((u_int)k + sizeof(short) <= hlen)
1680: data = header;
1681: else if ((u_int)k + sizeof(short) <= buflen) {
1682: k -= hlen;
1683: data = p;
1684: } else
1685: return 0;
1686:
1687: A = EXTRACT_SHORT(&data[k]);
1688: continue;
1.1 root 1689:
1690: case BPF_LD|BPF_B|BPF_ABS:
1.1.1.3 root 1691: k = pc->k;
1692:
1693: load_byte:
1694: if ((u_int)k < hlen)
1695: data = header;
1696: else if ((u_int)k < buflen) {
1697: data = p;
1698: k -= hlen;
1699: } else
1700: return 0;
1701:
1702: A = data[k];
1703: continue;
1.1 root 1704:
1705: case BPF_LD|BPF_W|BPF_LEN:
1706: A = wirelen;
1707: continue;
1708:
1709: case BPF_LDX|BPF_W|BPF_LEN:
1710: X = wirelen;
1711: continue;
1712:
1713: case BPF_LD|BPF_W|BPF_IND:
1714: k = X + pc->k;
1.1.1.3 root 1715: goto load_word;
1716:
1.1 root 1717: case BPF_LD|BPF_H|BPF_IND:
1718: k = X + pc->k;
1.1.1.3 root 1719: goto load_half;
1.1 root 1720:
1721: case BPF_LD|BPF_B|BPF_IND:
1722: k = X + pc->k;
1.1.1.3 root 1723: goto load_byte;
1.1 root 1724:
1725: case BPF_LDX|BPF_MSH|BPF_B:
1726: k = pc->k;
1.1.1.3 root 1727: if (k < hlen)
1728: data = header;
1729: else if (k < buflen) {
1730: data = p;
1731: k -= hlen;
1732: } else
1733: return 0;
1734:
1735: X = (data[k] & 0xf) << 2;
1.1 root 1736: continue;
1737:
1738: case BPF_LD|BPF_IMM:
1739: A = pc->k;
1740: continue;
1741:
1742: case BPF_LDX|BPF_IMM:
1743: X = pc->k;
1744: continue;
1745:
1746: case BPF_LD|BPF_MEM:
1747: A = mem[pc->k];
1748: continue;
1749:
1750: case BPF_LDX|BPF_MEM:
1751: X = mem[pc->k];
1752: continue;
1753:
1754: case BPF_ST:
1755: mem[pc->k] = A;
1756: continue;
1757:
1758: case BPF_STX:
1759: mem[pc->k] = X;
1760: continue;
1761:
1762: case BPF_JMP|BPF_JA:
1763: pc += pc->k;
1764: continue;
1765:
1766: case BPF_JMP|BPF_JGT|BPF_K:
1767: pc += (A > pc->k) ? pc->jt : pc->jf;
1768: continue;
1769:
1770: case BPF_JMP|BPF_JGE|BPF_K:
1771: pc += (A >= pc->k) ? pc->jt : pc->jf;
1772: continue;
1773:
1774: case BPF_JMP|BPF_JEQ|BPF_K:
1775: pc += (A == pc->k) ? pc->jt : pc->jf;
1776: continue;
1777:
1778: case BPF_JMP|BPF_JSET|BPF_K:
1779: pc += (A & pc->k) ? pc->jt : pc->jf;
1780: continue;
1781:
1782: case BPF_JMP|BPF_JGT|BPF_X:
1783: pc += (A > X) ? pc->jt : pc->jf;
1784: continue;
1785:
1786: case BPF_JMP|BPF_JGE|BPF_X:
1787: pc += (A >= X) ? pc->jt : pc->jf;
1788: continue;
1789:
1790: case BPF_JMP|BPF_JEQ|BPF_X:
1791: pc += (A == X) ? pc->jt : pc->jf;
1792: continue;
1793:
1794: case BPF_JMP|BPF_JSET|BPF_X:
1795: pc += (A & X) ? pc->jt : pc->jf;
1796: continue;
1797:
1798: case BPF_ALU|BPF_ADD|BPF_X:
1799: A += X;
1800: continue;
1801:
1802: case BPF_ALU|BPF_SUB|BPF_X:
1803: A -= X;
1804: continue;
1805:
1806: case BPF_ALU|BPF_MUL|BPF_X:
1807: A *= X;
1808: continue;
1809:
1810: case BPF_ALU|BPF_DIV|BPF_X:
1811: if (X == 0)
1812: return 0;
1813: A /= X;
1814: continue;
1815:
1816: case BPF_ALU|BPF_AND|BPF_X:
1817: A &= X;
1818: continue;
1819:
1820: case BPF_ALU|BPF_OR|BPF_X:
1821: A |= X;
1822: continue;
1823:
1824: case BPF_ALU|BPF_LSH|BPF_X:
1825: A <<= X;
1826: continue;
1827:
1828: case BPF_ALU|BPF_RSH|BPF_X:
1829: A >>= X;
1830: continue;
1831:
1832: case BPF_ALU|BPF_ADD|BPF_K:
1833: A += pc->k;
1834: continue;
1835:
1836: case BPF_ALU|BPF_SUB|BPF_K:
1837: A -= pc->k;
1838: continue;
1839:
1840: case BPF_ALU|BPF_MUL|BPF_K:
1841: A *= pc->k;
1842: continue;
1843:
1844: case BPF_ALU|BPF_DIV|BPF_K:
1845: A /= pc->k;
1846: continue;
1847:
1848: case BPF_ALU|BPF_AND|BPF_K:
1849: A &= pc->k;
1850: continue;
1851:
1852: case BPF_ALU|BPF_OR|BPF_K:
1853: A |= pc->k;
1854: continue;
1855:
1856: case BPF_ALU|BPF_LSH|BPF_K:
1857: A <<= pc->k;
1858: continue;
1859:
1860: case BPF_ALU|BPF_RSH|BPF_K:
1861: A >>= pc->k;
1862: continue;
1863:
1864: case BPF_ALU|BPF_NEG:
1865: A = -A;
1866: continue;
1867:
1868: case BPF_MISC|BPF_TAX:
1869: X = A;
1870: continue;
1871:
1872: case BPF_MISC|BPF_TXA:
1873: A = X;
1874: continue;
1875: }
1876: }
1877:
1878: return 0;
1879: }
1880:
1881: /*
1882: * Return 1 if the 'f' is a valid filter program without a MATCH
1883: * instruction. Return 2 if it is a valid filter program with a MATCH
1884: * instruction. Otherwise, return 0.
1885: * The constraints are that each jump be forward and to a valid
1886: * code. The code must terminate with either an accept or reject.
1887: * 'valid' is an array for use by the routine (it must be at least
1888: * 'len' bytes long).
1889: *
1890: * The kernel needs to be able to verify an application's filter code.
1891: * Otherwise, a bogus program could easily crash the system.
1892: */
1893: int
1.1.1.4 root 1894: bpf_validate(
1895: bpf_insn_t f,
1896: int bytes,
1897: bpf_insn_t *match)
1.1 root 1898: {
1.1.1.4 root 1899: int i, j, len;
1900: bpf_insn_t p;
1.1 root 1901:
1902: len = BPF_BYTES2LEN(bytes);
1.1.1.3 root 1903:
1904: /*
1905: * f[0].code is already checked to be (NETF_BPF | flags).
1906: * So skip f[0].
1907: */
1.1 root 1908:
1909: for (i = 1; i < len; ++i) {
1910: /*
1911: * Check that that jumps are forward, and within
1912: * the code block.
1913: */
1914: p = &f[i];
1915: if (BPF_CLASS(p->code) == BPF_JMP) {
1.1.1.4 root 1916: int from = i + 1;
1.1 root 1917:
1918: if (BPF_OP(p->code) == BPF_JA) {
1919: if (from + p->k >= len)
1920: return 0;
1921: }
1922: else if (from + p->jt >= len || from + p->jf >= len)
1923: return 0;
1924: }
1925: /*
1926: * Check that memory operations use valid addresses.
1927: */
1928: if ((BPF_CLASS(p->code) == BPF_ST ||
1929: (BPF_CLASS(p->code) == BPF_LD &&
1930: (p->code & 0xe0) == BPF_MEM)) &&
1931: (p->k >= BPF_MEMWORDS || p->k < 0))
1932: return 0;
1933: /*
1934: * Check for constant division by 0.
1935: */
1936: if (p->code == (BPF_ALU|BPF_DIV|BPF_K) && p->k == 0)
1937: return 0;
1938: /*
1939: * Check for match instruction.
1940: * Only one match instruction per filter is allowed.
1941: */
1942: if (p->code == (BPF_RET|BPF_MATCH_IMM)) {
1943: if (*match != 0 ||
1944: p->jt == 0 ||
1945: p->jt > N_NET_HASH_KEYS)
1946: return 0;
1947: i += p->jt; /* skip keys */
1948: if (i + 1 > len)
1949: return 0;
1950:
1951: for (j = 1; j <= p->jt; j++) {
1952: if (p[j].code != (BPF_MISC|BPF_KEY))
1953: return 0;
1954: }
1955:
1956: *match = p;
1957: }
1958: }
1959: if (BPF_CLASS(f[len - 1].code) == BPF_RET)
1960: return ((*match == 0) ? 1 : 2);
1961: else
1962: return 0;
1963: }
1964:
1965: int
1.1.1.4 root 1966: bpf_eq(
1967: bpf_insn_t f1,
1968: bpf_insn_t f2,
1969: int bytes)
1.1 root 1970: {
1.1.1.4 root 1971: int count;
1.1 root 1972:
1973: count = BPF_BYTES2LEN(bytes);
1974: for (; count--; f1++, f2++) {
1975: if (!BPF_INSN_EQ(f1, f2)) {
1976: if ( f1->code == (BPF_MISC|BPF_KEY) &&
1977: f2->code == (BPF_MISC|BPF_KEY) )
1978: continue;
1979: return FALSE;
1980: }
1981: };
1982: return TRUE;
1983: }
1984:
1985: unsigned int
1986: bpf_hash (n, keys)
1.1.1.4 root 1987: int n;
1988: const unsigned int *keys;
1.1 root 1989: {
1.1.1.4 root 1990: unsigned int hval = 0;
1.1 root 1991:
1992: while (n--) {
1993: hval += *keys++;
1994: }
1995: return (hval % NET_HASH_SIZE);
1996: }
1997:
1998:
1999: int
2000: bpf_match (hash, n_keys, keys, hash_headpp, entpp)
2001: net_hash_header_t hash;
1.1.1.4 root 2002: int n_keys;
2003: const unsigned int *keys;
1.1 root 2004: net_hash_entry_t **hash_headpp, *entpp;
2005: {
1.1.1.4 root 2006: net_hash_entry_t head, entp;
2007: int i;
1.1 root 2008:
2009: if (n_keys != hash->n_keys)
2010: return FALSE;
2011:
2012: *hash_headpp = &hash->table[bpf_hash(n_keys, keys)];
2013: head = **hash_headpp;
2014:
2015: if (head == 0)
2016: return FALSE;
2017:
2018: HASH_ITERATE (head, entp)
2019: {
2020: for (i = 0; i < n_keys; i++) {
2021: if (keys[i] != entp->keys[i])
2022: break;
2023: }
2024: if (i == n_keys) {
2025: *entpp = entp;
2026: return TRUE;
2027: }
2028: }
2029: HASH_ITERATE_END (head, entp)
2030: return FALSE;
2031: }
2032:
2033:
2034: /*
2035: * Removes a hash entry (ENTP) from its queue (HEAD).
2036: * If the reference count of filter (HP) becomes zero and not USED,
1.1.1.3 root 2037: * HP is removed from the corresponding port lists and is freed.
1.1 root 2038: */
2039:
2040: int
1.1.1.4 root 2041: hash_ent_remove(
2042: struct ifnet *ifp,
2043: net_hash_header_t hp,
2044: int used,
2045: net_hash_entry_t *head,
2046: net_hash_entry_t entp,
2047: queue_entry_t *dead_p)
1.1 root 2048: {
2049: hp->ref_count--;
2050:
2051: if (*head == entp) {
2052: if (queue_empty((queue_t) entp)) {
2053: *head = 0;
1.1.1.3 root 2054: ENQUEUE_DEAD(*dead_p, entp, chain);
1.1 root 2055: if (hp->ref_count == 0 && !used) {
1.1.1.3 root 2056: if (((net_rcv_port_t)hp)->filter[0] & NETF_IN)
2057: queue_remove(&ifp->if_rcv_port_list,
2058: (net_rcv_port_t)hp,
2059: net_rcv_port_t, input);
2060: if (((net_rcv_port_t)hp)->filter[0] & NETF_OUT)
2061: queue_remove(&ifp->if_snd_port_list,
2062: (net_rcv_port_t)hp,
2063: net_rcv_port_t, output);
1.1 root 2064: hp->n_keys = 0;
2065: return TRUE;
2066: }
2067: return FALSE;
2068: } else {
2069: *head = (net_hash_entry_t)queue_next((queue_t) entp);
2070: }
2071: }
2072:
2073: remqueue((queue_t)*head, (queue_entry_t)entp);
1.1.1.3 root 2074: ENQUEUE_DEAD(*dead_p, entp, chain);
1.1 root 2075: return FALSE;
2076: }
2077:
2078: int
1.1.1.4 root 2079: net_add_q_info(ipc_port_t rcv_port)
1.1 root 2080: {
2081: mach_port_msgcount_t qlimit = 0;
2082:
2083: /*
2084: * We use a new port, so increase net_queue_free_min
2085: * and net_kmsg_max to allow for more queued messages.
2086: */
2087:
2088: if (IP_VALID(rcv_port)) {
2089: ip_lock(rcv_port);
2090: if (ip_active(rcv_port))
2091: qlimit = rcv_port->ip_qlimit;
2092: ip_unlock(rcv_port);
2093: }
2094:
2095: simple_lock(&net_kmsg_total_lock);
2096: net_queue_free_min++;
2097: net_kmsg_max += qlimit + 1;
2098: simple_unlock(&net_kmsg_total_lock);
2099:
2100: return (int)qlimit;
2101: }
2102:
1.1.1.3 root 2103: void
1.1.1.4 root 2104: net_del_q_info(int qlimit)
1.1 root 2105: {
2106: simple_lock(&net_kmsg_total_lock);
2107: net_queue_free_min--;
2108: net_kmsg_max -= qlimit + 1;
2109: simple_unlock(&net_kmsg_total_lock);
2110: }
2111:
2112:
2113: /*
2114: * net_free_dead_infp (dead_infp)
2115: * queue_entry_t dead_infp; list of dead net_rcv_port_t.
2116: *
2117: * Deallocates dead net_rcv_port_t.
2118: * No locks should be held when called.
2119: */
1.1.1.3 root 2120: void
1.1.1.4 root 2121: net_free_dead_infp(queue_entry_t dead_infp)
1.1 root 2122: {
1.1.1.4 root 2123: net_rcv_port_t infp, nextfp;
1.1 root 2124:
2125: for (infp = (net_rcv_port_t) dead_infp; infp != 0; infp = nextfp)
2126: {
1.1.1.3 root 2127: nextfp = (net_rcv_port_t) queue_next(&infp->input);
1.1 root 2128: ipc_port_release_send(infp->rcv_port);
2129: net_del_q_info(infp->rcv_qlimit);
1.1.1.3 root 2130: kmem_cache_free(&net_rcv_cache, (vm_offset_t) infp);
1.1 root 2131: }
2132: }
2133:
2134: /*
2135: * net_free_dead_entp (dead_entp)
2136: * queue_entry_t dead_entp; list of dead net_hash_entry_t.
2137: *
2138: * Deallocates dead net_hash_entry_t.
2139: * No locks should be held when called.
2140: */
1.1.1.3 root 2141: void
1.1.1.4 root 2142: net_free_dead_entp(queue_entry_t dead_entp)
1.1 root 2143: {
1.1.1.4 root 2144: net_hash_entry_t entp, nextentp;
1.1 root 2145:
2146: for (entp = (net_hash_entry_t)dead_entp; entp != 0; entp = nextentp)
2147: {
2148: nextentp = (net_hash_entry_t) queue_next(&entp->chain);
2149:
2150: ipc_port_release_send(entp->rcv_port);
2151: net_del_q_info(entp->rcv_qlimit);
1.1.1.3 root 2152: kmem_cache_free(&net_hash_entry_cache, (vm_offset_t) entp);
1.1 root 2153: }
2154: }
2155:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.