--- Gnu-Mach/device/net_io.c 2020/09/02 04:36:57 1.1.1.1 +++ Gnu-Mach/device/net_io.c 2020/09/02 04:47:52 1.1.1.4 @@ -38,10 +38,9 @@ * It may change a lot real soon. -cmaeda 11 June 1993 */ -#include -#include - #include +#include + #include #include /* spl definitions */ #include @@ -57,15 +56,14 @@ #include #include +#include #include +#include #include #include +#include #include -#if NORMA_ETHER -#include -#endif /*NORMA_ETHER*/ - #include #if MACH_TTD @@ -146,7 +144,7 @@ vm_size_t net_kmsg_size; /* initialize ipc_kmsg_t net_kmsg_get(void) { - register ipc_kmsg_t kmsg; + ipc_kmsg_t kmsg; spl_t s; /* @@ -198,7 +196,7 @@ net_kmsg_get(void) } void -net_kmsg_put(register ipc_kmsg_t kmsg) +net_kmsg_put(const ipc_kmsg_t kmsg) { spl_t s; @@ -214,7 +212,7 @@ net_kmsg_put(register ipc_kmsg_t kmsg) void net_kmsg_collect(void) { - register ipc_kmsg_t kmsg; + ipc_kmsg_t kmsg; spl_t s; s = splimp(); @@ -240,7 +238,7 @@ net_kmsg_collect(void) void net_kmsg_more(void) { - register ipc_kmsg_t kmsg; + ipc_kmsg_t kmsg; /* * Replenish net kmsg pool if low. We don't have the locks @@ -293,7 +291,8 @@ net_kmsg_more(void) * filter for a single session. */ struct net_rcv_port { - queue_chain_t chain; /* list of open_descriptors */ + queue_chain_t input; /* list of input open_descriptors */ + queue_chain_t output; /* list of output open_descriptors */ ipc_port_t rcv_port; /* port to send packet to */ int rcv_qlimit; /* port's qlimit */ int rcv_count; /* number of packets received */ @@ -302,17 +301,13 @@ struct net_rcv_port { filter_t filter[NET_MAX_FILTER]; /* filter operations */ }; -typedef struct net_rcv_port *net_rcv_port_t; - -zone_t net_rcv_zone; /* zone of net_rcv_port structs */ +struct kmem_cache net_rcv_cache; /* cache of net_rcv_port structs */ #define NET_HASH_SIZE 256 #define N_NET_HASH 4 #define N_NET_HASH_KEYS 4 -unsigned int bpf_hash (int, unsigned int *); - /* * A single hash entry. */ @@ -324,9 +319,8 @@ struct net_hash_entry { int rcv_qlimit; /* qlimit for the port */ unsigned int keys[N_NET_HASH_KEYS]; }; -typedef struct net_hash_entry *net_hash_entry_t; -zone_t net_hash_entry_zone; +struct kmem_cache net_hash_entry_cache; /* * This structure represents a packet filter with multiple sessions. @@ -343,8 +337,6 @@ struct net_hash_header { net_hash_entry_t table[NET_HASH_SIZE]; } filter_hash_header[N_NET_HASH]; -typedef struct net_hash_header *net_hash_header_t; - decl_simple_lock_data(,net_hash_header_lock) #define HASH_ITERATE(head, elt) (elt) = (net_hash_entry_t) (head); do { @@ -352,24 +344,19 @@ decl_simple_lock_data(,net_hash_header_l (elt) = (net_hash_entry_t) queue_next((queue_entry_t) (elt)); \ } while ((elt) != (head)); - -#define FILTER_ITERATE(ifp, fp, nextfp) \ - for ((fp) = (net_rcv_port_t) queue_first(&(ifp)->if_rcv_port_list);\ - !queue_end(&(ifp)->if_rcv_port_list, (queue_entry_t)(fp)); \ - (fp) = (nextfp)) { \ - (nextfp) = (net_rcv_port_t) queue_next(&(fp)->chain); +#define FILTER_ITERATE(if_port_list, fp, nextfp, chain) \ + for ((fp) = (net_rcv_port_t) queue_first(if_port_list); \ + !queue_end(if_port_list, (queue_entry_t)(fp)); \ + (fp) = (nextfp)) { \ + (nextfp) = (net_rcv_port_t) queue_next(chain); #define FILTER_ITERATE_END } /* entry_p must be net_rcv_port_t or net_hash_entry_t */ -#define ENQUEUE_DEAD(dead, entry_p) { \ +#define ENQUEUE_DEAD(dead, entry_p, chain) { \ queue_next(&(entry_p)->chain) = (queue_entry_t) (dead); \ (dead) = (queue_entry_t)(entry_p); \ } -extern boolean_t net_do_filter(); /* CSPF */ -extern int bpf_do_filter(); /* BPF */ - - /* * ethernet_priority: * @@ -382,9 +369,9 @@ extern int bpf_do_filter(); /* BPF */ */ boolean_t ethernet_priority(kmsg) - ipc_kmsg_t kmsg; + const ipc_kmsg_t kmsg; { - register unsigned char *addr = + unsigned char *addr = (unsigned char *) net_kmsg(kmsg)->header; /* @@ -425,10 +412,9 @@ mach_msg_type_t packet_type = { * Dequeues a message and delivers it at spl0. * Returns FALSE if no messages. */ -boolean_t net_deliver(nonblocking) - boolean_t nonblocking; +boolean_t net_deliver(boolean_t nonblocking) { - register ipc_kmsg_t kmsg; + ipc_kmsg_t kmsg; boolean_t high_priority; struct ipc_kmsg_queue send_list; @@ -480,8 +466,9 @@ boolean_t net_deliver(nonblocking) MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0); /* remember message sizes must be rounded up */ kmsg->ikm_header.msgh_size = - ((mach_msg_size_t) (sizeof(struct net_rcv_msg) - - NET_RCV_MAX + count))+3 &~ 3; + (((mach_msg_size_t) (sizeof(struct net_rcv_msg) + - sizeof net_kmsg(kmsg)->sent + - NET_RCV_MAX + count)) + 3) &~ 3; kmsg->ikm_header.msgh_local_port = MACH_PORT_NULL; kmsg->ikm_header.msgh_kind = MACH_MSGH_KIND_NORMAL; kmsg->ikm_header.msgh_id = NET_RCV_MSG_ID; @@ -533,7 +520,7 @@ boolean_t net_deliver(nonblocking) * net_kmsg_get will do a wakeup. */ -void net_ast() +void net_ast(void) { spl_t s; @@ -562,7 +549,7 @@ void net_ast() (void) splx(s); } -void net_thread_continue() +void __attribute__ ((noreturn)) net_thread_continue(void) { for (;;) { spl_t s; @@ -588,7 +575,7 @@ void net_thread_continue() } } -void net_thread() +void net_thread(void) { spl_t s; @@ -616,10 +603,11 @@ void net_thread() } void -reorder_queue(first, last) - register queue_t first, last; +reorder_queue( + queue_t first, + queue_t last) { - register queue_entry_t prev, next; + queue_entry_t prev, next; prev = first->prev; next = last->next; @@ -639,26 +627,20 @@ reorder_queue(first, last) * We are already at splimp. */ void -net_packet(ifp, kmsg, count, priority) - register struct ifnet *ifp; - register ipc_kmsg_t kmsg; - unsigned int count; - boolean_t priority; +net_packet( + struct ifnet *ifp, + ipc_kmsg_t kmsg, + unsigned int count, + boolean_t priority) { boolean_t awake; -#if NORMA_ETHER - if (netipc_net_packet(kmsg, count)) { - return; - } -#endif NORMA_ETHER - #if MACH_TTD /* * Do a quick check to see if it is a kernel TTD packet. * * Only check if KernelTTD is enabled, ie. the current - * device driver supports TTD, and the bootp succeded. + * device driver supports TTD, and the bootp succeeded. */ if (kttd_enabled && kttd_handle_async(kmsg)) { /* @@ -709,12 +691,12 @@ int net_filter_queue_reorder = 0; /* non */ void net_filter(kmsg, send_list) - register ipc_kmsg_t kmsg; + const ipc_kmsg_t kmsg; ipc_kmsg_queue_t send_list; { - register struct ifnet *ifp; - register net_rcv_port_t infp, nextfp; - register ipc_kmsg_t new_kmsg; + struct ifnet *ifp; + net_rcv_port_t infp, nextfp; + ipc_kmsg_t new_kmsg; net_hash_entry_t entp, *hash_headp; ipc_port_t dest; @@ -722,27 +704,43 @@ net_filter(kmsg, send_list) queue_entry_t dead_entp = (queue_entry_t) 0; unsigned int ret_count; + queue_head_t *if_port_list; + int count = net_kmsg(kmsg)->net_rcv_msg_packet_count; ifp = (struct ifnet *) kmsg->ikm_header.msgh_remote_port; ipc_kmsg_queue_init(send_list); + if (net_kmsg(kmsg)->sent) + if_port_list = &ifp->if_snd_port_list; + else + if_port_list = &ifp->if_rcv_port_list; + /* * Unfortunately we can't allocate or deallocate memory - * while holding this lock. And we can't drop the lock - * while examining the filter list. + * while holding these locks. And we can't drop the locks + * while examining the filter lists. + * Both locks are hold in case a filter is removed from both + * queues. */ simple_lock(&ifp->if_rcv_port_list_lock); - FILTER_ITERATE(ifp, infp, nextfp) - { + simple_lock(&ifp->if_snd_port_list_lock); + FILTER_ITERATE(if_port_list, infp, nextfp, + net_kmsg(kmsg)->sent ? &infp->output : &infp->input) + { entp = (net_hash_entry_t) 0; - if (infp->filter[0] == NETF_BPF) { - ret_count = bpf_do_filter(infp, net_kmsg(kmsg)->packet, count, - net_kmsg(kmsg)->header, - &hash_headp, &entp); + if ((infp->filter[0] & NETF_TYPE_MASK) == NETF_BPF) { + ret_count = bpf_do_filter(infp, net_kmsg(kmsg)->packet + + sizeof(struct packet_header), + count - sizeof(struct packet_header), + net_kmsg(kmsg)->header, + ifp->if_header_size, &hash_headp, + &entp); if (entp == (net_hash_entry_t) 0) dest = infp->rcv_port; else dest = entp->rcv_port; + if (ret_count) + ret_count += sizeof(struct packet_header); } else { ret_count = net_do_filter(infp, net_kmsg(kmsg)->packet, count, net_kmsg(kmsg)->header); @@ -765,9 +763,15 @@ net_filter(kmsg, send_list) */ if (entp == (net_hash_entry_t) 0) { - queue_remove(&ifp->if_rcv_port_list, infp, - net_rcv_port_t, chain); - ENQUEUE_DEAD(dead_infp, infp); + if (infp->filter[0] & NETF_IN) + queue_remove(&ifp->if_rcv_port_list, infp, + net_rcv_port_t, input); + if (infp->filter[0] & NETF_OUT) + queue_remove(&ifp->if_snd_port_list, infp, + net_rcv_port_t, output); + + /* Use input only for queues of dead filters. */ + ENQUEUE_DEAD(dead_infp, infp, input); continue; } else { hash_ent_remove (ifp, @@ -798,13 +802,13 @@ net_filter(kmsg, send_list) break; } - bcopy( - net_kmsg(kmsg)->packet, + memcpy( net_kmsg(new_kmsg)->packet, + net_kmsg(kmsg)->packet, ret_count); - bcopy( - net_kmsg(kmsg)->header, + memcpy( net_kmsg(new_kmsg)->header, + net_kmsg(kmsg)->header, NET_HDW_HDR_MAX); } net_kmsg(new_kmsg)->net_rcv_msg_packet_count = ret_count; @@ -812,29 +816,34 @@ net_filter(kmsg, send_list) ipc_kmsg_enqueue(send_list, new_kmsg); { - register net_rcv_port_t prevfp; + net_rcv_port_t prevfp; int rcount = ++infp->rcv_count; /* * See if ordering of filters is wrong */ if (infp->priority >= NET_HI_PRI) { - prevfp = (net_rcv_port_t) queue_prev(&infp->chain); - /* - * If infp is not the first element on the queue, - * and the previous element is at equal priority - * but has a lower count, then promote infp to - * be in front of prevfp. - */ - if ((queue_t)prevfp != &ifp->if_rcv_port_list && - infp->priority == prevfp->priority) { - /* - * Threshold difference to prevent thrashing - */ - if (net_filter_queue_reorder - && (100 + prevfp->rcv_count < rcount)) - reorder_queue(&prevfp->chain, &infp->chain); +#define REORDER_PRIO(chain) \ + prevfp = (net_rcv_port_t) queue_prev(&infp->chain); \ + /* \ + * If infp is not the first element on the queue, \ + * and the previous element is at equal priority \ + * but has a lower count, then promote infp to \ + * be in front of prevfp. \ + */ \ + if ((queue_t)prevfp != if_port_list && \ + infp->priority == prevfp->priority) { \ + /* \ + * Threshold difference to prevent thrashing \ + */ \ + if (net_filter_queue_reorder \ + && (100 + prevfp->rcv_count < rcount)) \ + reorder_queue(&prevfp->chain, &infp->chain);\ } + + REORDER_PRIO(input); + REORDER_PRIO(output); + /* * High-priority filter -> no more deliveries */ @@ -844,7 +853,7 @@ net_filter(kmsg, send_list) } } FILTER_ITERATE_END - + simple_unlock(&ifp->if_snd_port_list_lock); simple_unlock(&ifp->if_rcv_port_list_lock); /* @@ -864,14 +873,14 @@ net_filter(kmsg, send_list) boolean_t net_do_filter(infp, data, data_count, header) net_rcv_port_t infp; - char * data; + const char * data; unsigned int data_count; - char * header; + const char * header; { int stack[NET_FILTER_STACK_DEPTH+1]; - register int *sp; - register filter_t *fp, *fpe; - register unsigned int op, arg; + int *sp; + filter_t *fp, *fpe; + unsigned int op, arg; /* * The filter accesses the header and data @@ -883,7 +892,7 @@ net_do_filter(infp, data, data_count, he #define header_word ((unsigned short *)header) sp = &stack[NET_FILTER_STACK_DEPTH]; - fp = &infp->filter[0]; + fp = &infp->filter[1]; /* filter[0] used for flags */ fpe = infp->filter_end; *sp = TRUE; @@ -1002,14 +1011,18 @@ net_do_filter(infp, data, data_count, he * Check filter for invalid operations or stack over/under-flow. */ boolean_t -parse_net_filter(filter, count) - register filter_t *filter; - unsigned int count; -{ - register int sp; - register filter_t *fpe = &filter[count]; - register filter_t op, arg; +parse_net_filter( + filter_t *filter, + unsigned int count) +{ + int sp; + filter_t *fpe = &filter[count]; + filter_t op, arg; + /* + * count is at least 1, and filter[0] is used for flags. + */ + filter++; sp = NET_FILTER_STACK_DEPTH; for (; filter < fpe; filter++) { @@ -1092,24 +1105,32 @@ parse_net_filter(filter, count) * If we are successful, we must consume that right. */ io_return_t -net_set_filter(ifp, rcv_port, priority, filter, filter_count) - struct ifnet *ifp; - ipc_port_t rcv_port; - int priority; - filter_t *filter; - unsigned int filter_count; +net_set_filter( + struct ifnet *ifp, + ipc_port_t rcv_port, + int priority, + filter_t *filter, + unsigned int filter_count) { int filter_bytes; bpf_insn_t match; - register net_rcv_port_t infp, my_infp; + net_rcv_port_t infp, my_infp; net_rcv_port_t nextfp; net_hash_header_t hhp; - register net_hash_entry_t entp, hash_entp; + net_hash_entry_t entp; net_hash_entry_t *head, nextentp; queue_entry_t dead_infp, dead_entp; int i; int ret, is_new_infp; io_return_t rval; + boolean_t in, out; + + /* Initialize hash_entp to NULL to quiet GCC + * warning about uninitialized variable. hash_entp is only + * used when match != 0; in that case it is properly initialized + * by kmem_cache_alloc(). + */ + net_hash_entry_t hash_entp = NULL; /* * Check the filter syntax. @@ -1118,13 +1139,19 @@ net_set_filter(ifp, rcv_port, priority, filter_bytes = CSPF_BYTES(filter_count); match = (bpf_insn_t) 0; - if (filter_count > 0 && filter[0] == NETF_BPF) { + if (filter_count == 0) { + return (D_INVALID_OPERATION); + } else if (!((filter[0] & NETF_IN) || (filter[0] & NETF_OUT))) { + return (D_INVALID_OPERATION); /* NETF_IN or NETF_OUT required */ + } else if ((filter[0] & NETF_TYPE_MASK) == NETF_BPF) { ret = bpf_validate((bpf_insn_t)filter, filter_bytes, &match); if (!ret) return (D_INVALID_OPERATION); - } else { + } else if ((filter[0] & NETF_TYPE_MASK) == 0) { if (!parse_net_filter(filter, filter_count)) return (D_INVALID_OPERATION); + } else { + return (D_INVALID_OPERATION); } rval = D_SUCCESS; /* default return value */ @@ -1135,17 +1162,17 @@ net_set_filter(ifp, rcv_port, priority, * If there is no match instruction, we allocate * a normal packet filter structure. */ - my_infp = (net_rcv_port_t) zalloc(net_rcv_zone); + my_infp = (net_rcv_port_t) kmem_cache_alloc(&net_rcv_cache); my_infp->rcv_port = rcv_port; is_new_infp = TRUE; } else { /* - * If there is a match instruction, we assume there will - * multiple session with a common substructure and allocate + * If there is a match instruction, we assume there will be + * multiple sessions with a common substructure and allocate * a hash table to deal with them. */ my_infp = 0; - hash_entp = (net_hash_entry_t) zalloc(net_hash_entry_zone); + hash_entp = (net_hash_entry_t) kmem_cache_alloc(&net_hash_entry_cache); is_new_infp = FALSE; } @@ -1154,70 +1181,87 @@ net_set_filter(ifp, rcv_port, priority, * Look for filters with dead ports (for GC). * Look for a filter with the same code except KEY insns. */ - - simple_lock(&ifp->if_rcv_port_list_lock); - - FILTER_ITERATE(ifp, infp, nextfp) + void check_filter_list(queue_head_t *if_port_list) { + FILTER_ITERATE(if_port_list, infp, nextfp, + (if_port_list == &ifp->if_rcv_port_list) + ? &infp->input : &infp->output) + { if (infp->rcv_port == MACH_PORT_NULL) { - if (match != 0 - && infp->priority == priority - && my_infp == 0 - && (infp->filter_end - infp->filter) == filter_count - && bpf_eq((bpf_insn_t)infp->filter, - filter, filter_bytes)) - { - my_infp = infp; - } - - for (i = 0; i < NET_HASH_SIZE; i++) { - head = &((net_hash_header_t) infp)->table[i]; - if (*head == 0) - continue; - - /* - * Check each hash entry to make sure the - * destination port is still valid. Remove - * any invalid entries. - */ - entp = *head; - do { - nextentp = (net_hash_entry_t) entp->he_next; + if (match != 0 + && infp->priority == priority + && my_infp == 0 + && (infp->filter_end - infp->filter) == filter_count + && bpf_eq((bpf_insn_t)infp->filter, + (bpf_insn_t)filter, filter_bytes)) + my_infp = infp; + + for (i = 0; i < NET_HASH_SIZE; i++) { + head = &((net_hash_header_t) infp)->table[i]; + if (*head == 0) + continue; + + /* + * Check each hash entry to make sure the + * destination port is still valid. Remove + * any invalid entries. + */ + entp = *head; + do { + nextentp = (net_hash_entry_t) entp->he_next; - /* checked without - ip_lock(entp->rcv_port) */ - if (entp->rcv_port == rcv_port - || !IP_VALID(entp->rcv_port) - || !ip_active(entp->rcv_port)) { - - ret = hash_ent_remove (ifp, - (net_hash_header_t)infp, - (my_infp == infp), - head, - entp, - &dead_entp); - if (ret) - goto hash_loop_end; - } + /* checked without + ip_lock(entp->rcv_port) */ + if (entp->rcv_port == rcv_port + || !IP_VALID(entp->rcv_port) + || !ip_active(entp->rcv_port)) { + ret = hash_ent_remove (ifp, + (net_hash_header_t)infp, + (my_infp == infp), + head, + entp, + &dead_entp); + if (ret) + goto hash_loop_end; + } - entp = nextentp; - /* While test checks head since hash_ent_remove - might modify it. - */ - } while (*head != 0 && entp != *head); - } + entp = nextentp; + /* While test checks head since hash_ent_remove + might modify it. + */ + } while (*head != 0 && entp != *head); + } + hash_loop_end: ; - } else if (infp->rcv_port == rcv_port || !IP_VALID(infp->rcv_port) || !ip_active(infp->rcv_port)) { - /* Remove the old filter from list */ - remqueue(&ifp->if_rcv_port_list, (queue_entry_t)infp); - ENQUEUE_DEAD(dead_infp, infp); + + /* Remove the old filter from lists */ + if (infp->filter[0] & NETF_IN) + queue_remove(&ifp->if_rcv_port_list, infp, + net_rcv_port_t, input); + if (infp->filter[0] & NETF_OUT) + queue_remove(&ifp->if_snd_port_list, infp, + net_rcv_port_t, output); + + ENQUEUE_DEAD(dead_infp, infp, input); } + } + FILTER_ITERATE_END } - FILTER_ITERATE_END + + in = (filter[0] & NETF_IN) != 0; + out = (filter[0] & NETF_OUT) != 0; + + simple_lock(&ifp->if_rcv_port_list_lock); + simple_lock(&ifp->if_snd_port_list_lock); + + if (in) + check_filter_list(&ifp->if_rcv_port_list); + if (out) + check_filter_list(&ifp->if_snd_port_list); if (my_infp == 0) { /* Allocate a dummy infp */ @@ -1228,11 +1272,13 @@ net_set_filter(ifp, rcv_port, priority, } if (i == N_NET_HASH) { simple_unlock(&net_hash_header_lock); + simple_unlock(&ifp->if_snd_port_list_lock); simple_unlock(&ifp->if_rcv_port_list_lock); ipc_port_release_send(rcv_port); if (match != 0) - zfree (net_hash_entry_zone, (vm_offset_t)hash_entp); + kmem_cache_free(&net_hash_entry_cache, + (vm_offset_t)hash_entp); rval = D_NO_MEMORY; goto clean_and_return; @@ -1256,8 +1302,7 @@ net_set_filter(ifp, rcv_port, priority, my_infp->rcv_count = 0; /* Copy filter program. */ - bcopy ((vm_offset_t)filter, (vm_offset_t)my_infp->filter, - filter_bytes); + memcpy (my_infp->filter, filter, filter_bytes); my_infp->filter_end = (filter_t *)((char *)my_infp->filter + filter_bytes); @@ -1268,16 +1313,26 @@ net_set_filter(ifp, rcv_port, priority, } /* Insert my_infp according to priority */ - queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, chain) - if (priority > infp->priority) - break; - enqueue_tail((queue_t)&infp->chain, (queue_entry_t)my_infp); + if (in) { + queue_iterate(&ifp->if_rcv_port_list, infp, net_rcv_port_t, input) + if (priority > infp->priority) + break; + + queue_enter(&ifp->if_rcv_port_list, my_infp, net_rcv_port_t, input); + } + + if (out) { + queue_iterate(&ifp->if_snd_port_list, infp, net_rcv_port_t, output) + if (priority > infp->priority) + break; + + queue_enter(&ifp->if_snd_port_list, my_infp, net_rcv_port_t, output); + } } if (match != 0) { /* Insert to hash list */ net_hash_entry_t *p; - int j; hash_entp->rcv_port = rcv_port; for (i = 0; i < match->jt; i++) /* match->jt is n_keys */ @@ -1287,17 +1342,17 @@ net_set_filter(ifp, rcv_port, priority, /* Not checking for the same key values */ if (*p == 0) { - queue_init ((queue_t) hash_entp); + queue_init (&hash_entp->chain); *p = hash_entp; } else { - enqueue_tail((queue_t)*p, hash_entp); + enqueue_tail(&(*p)->chain, &hash_entp->chain); } ((net_hash_header_t)my_infp)->ref_count++; hash_entp->rcv_qlimit = net_add_q_info(rcv_port); - } + simple_unlock(&ifp->if_snd_port_list_lock); simple_unlock(&ifp->if_rcv_port_list_lock); clean_and_return: @@ -1315,16 +1370,16 @@ clean_and_return: * Other network operations */ io_return_t -net_getstat(ifp, flavor, status, count) - struct ifnet *ifp; - dev_flavor_t flavor; - dev_status_t status; /* pointer to OUT array */ - natural_t *count; /* OUT */ +net_getstat( + struct ifnet *ifp, + dev_flavor_t flavor, + dev_status_t status, /* pointer to OUT array */ + natural_t *count) /* OUT */ { switch (flavor) { case NET_STATUS: { - register struct net_status *ns = (struct net_status *)status; + struct net_status *ns = (struct net_status *)status; if (*count < NET_STATUS_COUNT) return (D_INVALID_OPERATION); @@ -1342,9 +1397,9 @@ net_getstat(ifp, flavor, status, count) } case NET_ADDRESS: { - register int addr_byte_count; - register int addr_int_count; - register int i; + int addr_byte_count; + int addr_int_count; + int i; addr_byte_count = ifp->if_address_size; addr_int_count = (addr_byte_count + (sizeof(int)-1)) @@ -1358,16 +1413,14 @@ printf ("net_getstat: count: %d, addr_in return (D_INVALID_OPERATION); } - bcopy((char *)ifp->if_address, - (char *)status, - (unsigned) addr_byte_count); + memcpy(status, ifp->if_address, addr_byte_count); if (addr_byte_count < addr_int_count * sizeof(int)) - bzero((char *)status + addr_byte_count, - (unsigned) (addr_int_count * sizeof(int) + memset((char *)status + addr_byte_count, 0, + (addr_int_count * sizeof(int) - addr_byte_count)); for (i = 0; i < addr_int_count; i++) { - register int word; + int word; word = status[i]; status[i] = htonl(word); @@ -1382,10 +1435,10 @@ printf ("net_getstat: count: %d, addr_in } io_return_t -net_write(ifp, start, ior) - register struct ifnet *ifp; - int (*start)(); - io_req_t ior; +net_write( + struct ifnet *ifp, + int (*start)(), + io_req_t ior) { spl_t s; kern_return_t rc; @@ -1432,84 +1485,21 @@ net_write(ifp, start, ior) return (D_IO_QUEUED); } -#ifdef FIPC -/* This gets called by nefoutput for dev_ops->d_port_death ... */ - -io_return_t -net_fwrite(ifp, start, ior) - register struct ifnet *ifp; - int (*start)(); - io_req_t ior; -{ - spl_t s; - kern_return_t rc; - boolean_t wait; - - /* - * Reject the write if the interface is down. - */ - if ((ifp->if_flags & (IFF_UP|IFF_RUNNING)) != (IFF_UP|IFF_RUNNING)) - return (D_DEVICE_DOWN); - - /* - * Reject the write if the packet is too large or too small. - */ - if (ior->io_count < ifp->if_header_size || - ior->io_count > ifp->if_header_size + ifp->if_mtu) - return (D_INVALID_SIZE); - - /* - * DON'T Wire down the memory. - */ -#if 0 - rc = device_write_get(ior, &wait); - if (rc != KERN_SUCCESS) - return (rc); -#endif - /* - * Network interfaces can't cope with VM continuations. - * If wait is set, just panic. - */ - /* I'll have to figure out who was setting wait...*/ -#if 0 - if (wait) { - panic("net_write: VM continuation"); - } -#endif - /* - * Queue the packet on the output queue, and - * start the device. - */ - s = splimp(); - IF_ENQUEUE(&ifp->if_snd, ior); - (*start)(ifp->if_unit); - splx(s); - - return (D_IO_QUEUED); -} -#endif /* FIPC */ - /* * Initialize the whole package. */ void -net_io_init() +net_io_init(void) { - register vm_size_t size; + vm_size_t size; size = sizeof(struct net_rcv_port); - net_rcv_zone = zinit(size, - size * 1000, - PAGE_SIZE, - FALSE, - "net_rcv_port"); + kmem_cache_init(&net_rcv_cache, "net_rcv_port", size, 0, + NULL, NULL, NULL, 0); size = sizeof(struct net_hash_entry); - net_hash_entry_zone = zinit(size, - size * 100, - PAGE_SIZE, - FALSE, - "net_hash_entry"); + kmem_cache_init(&net_hash_entry_cache, "net_hash_entry", size, 0, + NULL, NULL, NULL, 0); size = ikm_plus_overhead(sizeof(struct net_rcv_msg)); net_kmsg_size = round_page(size); @@ -1556,10 +1546,6 @@ net_io_init() * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. @@ -1605,30 +1591,34 @@ net_io_init() */ int -bpf_do_filter(infp, p, wirelen, header, hash_headpp, entpp) - net_rcv_port_t infp; - char * p; /* packet data */ - unsigned int wirelen; /* data_count (in bytes) */ - char * header; - net_hash_entry_t **hash_headpp, *entpp; /* out */ -{ - register bpf_insn_t pc, pc_end; - register unsigned int buflen; - - register unsigned long A, X; - register int k; - long mem[BPF_MEMWORDS]; +bpf_do_filter( + net_rcv_port_t infp, + char * p, /* packet data */ + unsigned int wirelen, /* data_count (in bytes) */ + char * header, + unsigned int hlen, /* header len (in bytes) */ + net_hash_entry_t **hash_headpp, + net_hash_entry_t *entpp) /* out */ +{ + bpf_insn_t pc, pc_end; + unsigned int buflen; + + unsigned int A, X; + int k; + unsigned int mem[BPF_MEMWORDS]; + + /* Generic pointer to either HEADER or P according to the specified offset. */ + char *data = NULL; pc = ((bpf_insn_t) infp->filter) + 1; - /* filter[0].code is BPF_BEGIN */ + /* filter[0].code is (NETF_BPF | flags) */ pc_end = (bpf_insn_t)infp->filter_end; buflen = NET_RCV_MAX; *entpp = 0; /* default */ -#ifdef lint A = 0; X = 0; -#endif + for (; pc < pc_end; ++pc) { switch (pc->code) { @@ -1664,58 +1654,53 @@ bpf_do_filter(infp, p, wirelen, header, case BPF_LD|BPF_W|BPF_ABS: k = pc->k; - if ((u_int)k + sizeof(long) <= buflen) { -#ifdef BPF_ALIGN - if (((int)(p + k) & 3) != 0) - A = EXTRACT_LONG(&p[k]); - else -#endif - A = ntohl(*(long *)(p + k)); - continue; - } - k -= BPF_DLBASE; - if ((u_int)k + sizeof(long) <= NET_HDW_HDR_MAX) { + load_word: + if ((u_int)k + sizeof(int) <= hlen) + data = header; + else if ((u_int)k + sizeof(int) <= buflen) { + k -= hlen; + data = p; + } else + return 0; + #ifdef BPF_ALIGN - if (((int)(header + k) & 3) != 0) - A = EXTRACT_LONG(&header[k]); - else + if (((int)(data + k) & 3) != 0) + A = EXTRACT_LONG(&data[k]); + else #endif - A = ntohl(*(long *)(header + k)); - continue; - } else { - return 0; - } + A = ntohl(*(int *)(data + k)); + continue; case BPF_LD|BPF_H|BPF_ABS: k = pc->k; - if ((u_int)k + sizeof(short) <= buflen) { - A = EXTRACT_SHORT(&p[k]); - continue; - } - k -= BPF_DLBASE; - if ((u_int)k + sizeof(short) <= NET_HDW_HDR_MAX) { - A = EXTRACT_SHORT(&header[k]); - continue; - } else { - return 0; - } + load_half: + if ((u_int)k + sizeof(short) <= hlen) + data = header; + else if ((u_int)k + sizeof(short) <= buflen) { + k -= hlen; + data = p; + } else + return 0; + + A = EXTRACT_SHORT(&data[k]); + continue; case BPF_LD|BPF_B|BPF_ABS: - k = pc->k; - if ((u_int)k < buflen) { - A = p[k]; - continue; - } - - k -= BPF_DLBASE; - if ((u_int)k < NET_HDW_HDR_MAX) { - A = header[k]; - continue; - } else { - return 0; - } + k = pc->k; + + load_byte: + if ((u_int)k < hlen) + data = header; + else if ((u_int)k < buflen) { + data = p; + k -= hlen; + } else + return 0; + + A = data[k]; + continue; case BPF_LD|BPF_W|BPF_LEN: A = wirelen; @@ -1727,35 +1712,27 @@ bpf_do_filter(infp, p, wirelen, header, case BPF_LD|BPF_W|BPF_IND: k = X + pc->k; - if (k + sizeof(long) > buflen) - return 0; -#ifdef BPF_ALIGN - if (((int)(p + k) & 3) != 0) - A = EXTRACT_LONG(&p[k]); - else -#endif - A = ntohl(*(long *)(p + k)); - continue; - + goto load_word; + case BPF_LD|BPF_H|BPF_IND: k = X + pc->k; - if (k + sizeof(short) > buflen) - return 0; - A = EXTRACT_SHORT(&p[k]); - continue; + goto load_half; case BPF_LD|BPF_B|BPF_IND: k = X + pc->k; - if (k >= buflen) - return 0; - A = p[k]; - continue; + goto load_byte; case BPF_LDX|BPF_MSH|BPF_B: k = pc->k; - if (k >= buflen) - return 0; - X = (p[pc->k] & 0xf) << 2; + if (k < hlen) + data = header; + else if (k < buflen) { + data = p; + k -= hlen; + } else + return 0; + + X = (data[k] & 0xf) << 2; continue; case BPF_LD|BPF_IMM: @@ -1914,16 +1891,20 @@ bpf_do_filter(infp, p, wirelen, header, * Otherwise, a bogus program could easily crash the system. */ int -bpf_validate(f, bytes, match) - bpf_insn_t f; - int bytes; - bpf_insn_t *match; +bpf_validate( + bpf_insn_t f, + int bytes, + bpf_insn_t *match) { - register int i, j, len; - register bpf_insn_t p; + int i, j, len; + bpf_insn_t p; len = BPF_BYTES2LEN(bytes); - /* f[0].code is already checked to be BPF_BEGIN. So skip f[0]. */ + + /* + * f[0].code is already checked to be (NETF_BPF | flags). + * So skip f[0]. + */ for (i = 1; i < len; ++i) { /* @@ -1932,7 +1913,7 @@ bpf_validate(f, bytes, match) */ p = &f[i]; if (BPF_CLASS(p->code) == BPF_JMP) { - register int from = i + 1; + int from = i + 1; if (BPF_OP(p->code) == BPF_JA) { if (from + p->k >= len) @@ -1982,11 +1963,12 @@ bpf_validate(f, bytes, match) } int -bpf_eq (f1, f2, bytes) - register bpf_insn_t f1, f2; - register int bytes; +bpf_eq( + bpf_insn_t f1, + bpf_insn_t f2, + int bytes) { - register int count; + int count; count = BPF_BYTES2LEN(bytes); for (; count--; f1++, f2++) { @@ -2002,10 +1984,10 @@ bpf_eq (f1, f2, bytes) unsigned int bpf_hash (n, keys) - register int n; - register unsigned int *keys; + int n; + const unsigned int *keys; { - register unsigned int hval = 0; + unsigned int hval = 0; while (n--) { hval += *keys++; @@ -2017,12 +1999,12 @@ bpf_hash (n, keys) int bpf_match (hash, n_keys, keys, hash_headpp, entpp) net_hash_header_t hash; - register int n_keys; - register unsigned int *keys; + int n_keys; + const unsigned int *keys; net_hash_entry_t **hash_headpp, *entpp; { - register net_hash_entry_t head, entp; - register int i; + net_hash_entry_t head, entp; + int i; if (n_keys != hash->n_keys) return FALSE; @@ -2052,27 +2034,33 @@ bpf_match (hash, n_keys, keys, hash_head /* * Removes a hash entry (ENTP) from its queue (HEAD). * If the reference count of filter (HP) becomes zero and not USED, - * HP is removed from ifp->if_rcv_port_list and is freed. + * HP is removed from the corresponding port lists and is freed. */ int -hash_ent_remove (ifp, hp, used, head, entp, dead_p) - struct ifnet *ifp; - net_hash_header_t hp; - int used; - net_hash_entry_t *head, entp; - queue_entry_t *dead_p; +hash_ent_remove( + struct ifnet *ifp, + net_hash_header_t hp, + int used, + net_hash_entry_t *head, + net_hash_entry_t entp, + queue_entry_t *dead_p) { hp->ref_count--; if (*head == entp) { - if (queue_empty((queue_t) entp)) { *head = 0; - ENQUEUE_DEAD(*dead_p, entp); + ENQUEUE_DEAD(*dead_p, entp, chain); if (hp->ref_count == 0 && !used) { - remqueue((queue_t) &ifp->if_rcv_port_list, - (queue_entry_t)hp); + if (((net_rcv_port_t)hp)->filter[0] & NETF_IN) + queue_remove(&ifp->if_rcv_port_list, + (net_rcv_port_t)hp, + net_rcv_port_t, input); + if (((net_rcv_port_t)hp)->filter[0] & NETF_OUT) + queue_remove(&ifp->if_snd_port_list, + (net_rcv_port_t)hp, + net_rcv_port_t, output); hp->n_keys = 0; return TRUE; } @@ -2083,13 +2071,12 @@ hash_ent_remove (ifp, hp, used, head, en } remqueue((queue_t)*head, (queue_entry_t)entp); - ENQUEUE_DEAD(*dead_p, entp); + ENQUEUE_DEAD(*dead_p, entp, chain); return FALSE; } int -net_add_q_info (rcv_port) - ipc_port_t rcv_port; +net_add_q_info(ipc_port_t rcv_port) { mach_port_msgcount_t qlimit = 0; @@ -2113,8 +2100,8 @@ net_add_q_info (rcv_port) return (int)qlimit; } -net_del_q_info (qlimit) - int qlimit; +void +net_del_q_info(int qlimit) { simple_lock(&net_kmsg_total_lock); net_queue_free_min--; @@ -2130,17 +2117,17 @@ net_del_q_info (qlimit) * Deallocates dead net_rcv_port_t. * No locks should be held when called. */ -net_free_dead_infp (dead_infp) - queue_entry_t dead_infp; +void +net_free_dead_infp(queue_entry_t dead_infp) { - register net_rcv_port_t infp, nextfp; + net_rcv_port_t infp, nextfp; for (infp = (net_rcv_port_t) dead_infp; infp != 0; infp = nextfp) { - nextfp = (net_rcv_port_t) queue_next(&infp->chain); + nextfp = (net_rcv_port_t) queue_next(&infp->input); ipc_port_release_send(infp->rcv_port); net_del_q_info(infp->rcv_qlimit); - zfree(net_rcv_zone, (vm_offset_t) infp); + kmem_cache_free(&net_rcv_cache, (vm_offset_t) infp); } } @@ -2151,10 +2138,10 @@ net_free_dead_infp (dead_infp) * Deallocates dead net_hash_entry_t. * No locks should be held when called. */ -net_free_dead_entp (dead_entp) - queue_entry_t dead_entp; +void +net_free_dead_entp(queue_entry_t dead_entp) { - register net_hash_entry_t entp, nextentp; + net_hash_entry_t entp, nextentp; for (entp = (net_hash_entry_t)dead_entp; entp != 0; entp = nextentp) { @@ -2162,7 +2149,7 @@ net_free_dead_entp (dead_entp) ipc_port_release_send(entp->rcv_port); net_del_q_info(entp->rcv_qlimit); - zfree(net_hash_entry_zone, (vm_offset_t) entp); + kmem_cache_free(&net_hash_entry_cache, (vm_offset_t) entp); } }