--- Gnu-Mach/device/net_io.c 2020/09/02 04:43:01 1.1.1.2 +++ Gnu-Mach/device/net_io.c 2020/09/02 04:45:30 1.1.1.3 @@ -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 @@ -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 */ @@ -304,7 +303,7 @@ struct net_rcv_port { }; 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 @@ -326,7 +325,7 @@ struct net_hash_entry { }; 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. @@ -353,15 +352,15 @@ decl_simple_lock_data(,net_hash_header_l } 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); \ } @@ -369,6 +368,36 @@ decl_simple_lock_data(,net_hash_header_l extern boolean_t net_do_filter(); /* CSPF */ extern int bpf_do_filter(); /* BPF */ +int 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); + +void net_free_dead_infp (queue_entry_t dead_infp); +void net_free_dead_entp (queue_entry_t dead_entp); + +int bpf_validate( + bpf_insn_t f, + int bytes, + bpf_insn_t *match); + +int bpf_eq ( + bpf_insn_t f1, + bpf_insn_t f2, + register int bytes); + +int net_add_q_info (ipc_port_t rcv_port); + +int bpf_match ( + net_hash_header_t hash, + int n_keys, + unsigned int *keys, + net_hash_entry_t **hash_headpp, + net_hash_entry_t *entpp); + /* * ethernet_priority: @@ -480,8 +509,8 @@ 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) + - 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; @@ -647,12 +676,6 @@ net_packet(ifp, kmsg, count, 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. @@ -722,27 +745,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 +804,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 +843,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; @@ -819,22 +864,27 @@ net_filter(kmsg, send_list) * 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 +894,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); /* @@ -883,7 +933,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; @@ -1010,6 +1060,10 @@ parse_net_filter(filter, count) register filter_t *fpe = &filter[count]; register 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++) { @@ -1110,6 +1164,7 @@ net_set_filter(ifp, rcv_port, priority, int i; int ret, is_new_infp; io_return_t rval; + boolean_t in, out; /* * Check the filter syntax. @@ -1118,13 +1173,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 +1196,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 +1215,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 +1306,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 +1336,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 +1347,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 +1376,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: @@ -1358,12 +1447,10 @@ 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++) { @@ -1432,63 +1519,6 @@ 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. */ @@ -1498,18 +1528,12 @@ net_io_init() register 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 +1580,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 +1625,33 @@ net_io_init() */ int -bpf_do_filter(infp, p, wirelen, header, hash_headpp, entpp) +bpf_do_filter(infp, p, wirelen, header, hlen, hash_headpp, entpp) 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, *entpp; /* out */ { register bpf_insn_t pc, pc_end; register unsigned int buflen; - register unsigned long A, X; + register unsigned int A, X; register int k; - long mem[BPF_MEMWORDS]; + 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 +1687,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 +1745,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: @@ -1923,7 +1933,11 @@ bpf_validate(f, bytes, match) register 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) { /* @@ -2052,7 +2066,7 @@ 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 @@ -2066,13 +2080,18 @@ hash_ent_remove (ifp, hp, used, head, en 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,7 +2102,7 @@ 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; } @@ -2113,6 +2132,7 @@ net_add_q_info (rcv_port) return (int)qlimit; } +void net_del_q_info (qlimit) int qlimit; { @@ -2130,6 +2150,7 @@ net_del_q_info (qlimit) * Deallocates dead net_rcv_port_t. * No locks should be held when called. */ +void net_free_dead_infp (dead_infp) queue_entry_t dead_infp; { @@ -2137,10 +2158,10 @@ net_free_dead_infp (dead_infp) 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,6 +2172,7 @@ net_free_dead_infp (dead_infp) * Deallocates dead net_hash_entry_t. * No locks should be held when called. */ +void net_free_dead_entp (dead_entp) queue_entry_t dead_entp; { @@ -2162,7 +2184,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); } }