void fastpath_fragmagic_uninit(SshFastpath fastpath) { SshFastpathFragEntry frag; ssh_kernel_mutex_lock(fastpath->frag_lock); if (fastpath->frag_timeout_scheduled) { ssh_kernel_timeout_cancel(ssh_fastpath_fragmagic_timeout, (void *)fastpath); fastpath->frag_timeout_scheduled = 0; } ssh_kernel_mutex_unlock(fastpath->frag_lock); /* Free fragments. */ for (frag = fastpath->frag_data_lru_head; frag; frag = frag->data_lru_next) { SshInterceptorPacket pp, pp_next; for (pp = frag->pp_chain; pp; pp = pp_next) { pp_next = pp->next; /* An exeption for using ssh_fastpath_fragmagic_packet_free. We are uninitialising here and we don't receive any more packets. */ ssh_interceptor_packet_free(pp); } } }
/*--------------------------------------------------------------------------*/ SshInterceptorPacket ssh_flat_packet_to_icept_packet(const SshInterceptor interceptor, const SshAdapter adapter, unsigned char * flat_packet, unsigned int flat_packet_size) { SshInterceptorPacket pp; pp = ssh_interceptor_packet_alloc(interceptor, SSH_PACKET_FROMPROTOCOL, SSH_PROTOCOL_ETHERNET, adapter->ifnum, SSH_INTERCEPTOR_INVALID_IFNUM, flat_packet_size); if (pp) { if (!ssh_interceptor_packet_copyin(pp, 0, flat_packet, flat_packet_size)) { ssh_interceptor_packet_free(pp); pp = NULL; } } else { SSH_DEBUG(SSH_D_ERROR, ("Can not allocate new packet")); } return pp; }
/* Send a packet to the IP stack like it was received by the virtual IP interface indexed by pp->ifnum_in. */ void ssh_virtual_adapter_send(SshInterceptor interceptor, SshInterceptorPacket pp) { SshInterceptorInternalPacket ipp; VxWorksVa *va; M_BLK_ID m; if (!(va = vxworks_va_find_va(pp->ifnum_out))) { SSH_TRACE( SSH_D_ERROR, ("trying to send to a nonexistent ifnum %d", (int)pp->ifnum_out)); ssh_interceptor_packet_free(pp); return; } if (pp->protocol != SSH_PROTOCOL_ETHERNET) { SSH_TRACE(SSH_D_ERROR, ("%s: dropping non-ethernet packet", va->name)); ssh_interceptor_packet_free(pp); return; } ipp = (void *)pp; m = ipp->head; ipp->head = NULL; ssh_interceptor_packet_free_header(ipp); SSH_DEBUG( SSH_D_LOWOK, ("feeding receive packet to %s, ifnum %d", va->name, (int)va->ifnum)); END_RCV_RTN_CALL(&va->end, m); }
static void ssh_fastpath_fragmagic_free_packet_list(SshInterceptorPacket frag_free_list) { SshInterceptorPacket pp; SSH_DEBUG(SSH_D_NICETOKNOW, ("Removing fragmagic free list %p.", frag_free_list)); while (frag_free_list) { pp = frag_free_list; frag_free_list = pp->next; ssh_interceptor_packet_free(pp); } }
Boolean ssh_engine_packet_start(SshEngine engine, SshInterceptorPacket pp, SshUInt32 tunnel_id, SshUInt32 prev_transform_index, SshUInt32 pc_flags) { SshEnginePacketContext pc; SshEngineTransformData trd; SSH_DEBUG(SSH_D_LOWOK, ("Sending packet to the fastpath pp=%p, " "tunnel_id=%d, prev_transform_index=%x", pp, (int) tunnel_id, (unsigned int) prev_transform_index)); if (pp->flags & SSH_PACKET_FROMADAPTER) pp->flags |= SSH_ENGINE_P_FROMADAPTER; /* Allocate a packet context for the new packet. */ if ((pc = ssh_engine_alloc_pc(engine)) == NULL) { ssh_interceptor_packet_free(pp); return FALSE; } /* Initialize the new pc. */ ssh_engine_init_pc(pc, engine, pp, tunnel_id, NULL); pc->flags = pc_flags; pc->prev_transform_index = prev_transform_index; /* Initialize transform_counter for outbound nested tunnel packets. */ if (pc->flags & SSH_ENGINE_PC_RESTARTED_OUT && pc->prev_transform_index != SSH_IPSEC_INVALID_INDEX) { ssh_kernel_mutex_lock(engine->flow_control_table_lock); trd = FASTPATH_GET_READ_ONLY_TRD(engine->fastpath, pc->prev_transform_index); SSH_ASSERT(trd != NULL); SSH_ASSERT(trd->nesting_level > 0); pc->transform_counter = trd->nesting_level - 1; FASTPATH_RELEASE_TRD(engine->fastpath, pc->prev_transform_index); ssh_kernel_mutex_unlock(engine->flow_control_table_lock); } /* Send the packet to the fastpath. This will handle the packet as if it had just been received from the network. */ engine_packet_continue(pc, SSH_ENGINE_RET_RESTART); return TRUE; }
/*------------------------------------------------------------------------- ssh_driver_return_packet() Previously indicated NDIS packet is returned so that it can be reused. Arguments: miniport_context - virtual NIC object pkt - NDIS packet Returns: Notes: NDIS calls this function when the protocol layer above has processed the received packet and the resources allocated for the packet can be freed (reused). Default IRQL: DISPATCH_LEVEL -------------------------------------------------------------------------*/ static void ssh_driver_return_packet(NDIS_HANDLE miniport_context, NDIS_PACKET *ndis_pkt) { SshNdisIMAdapter adapter = (SshNdisIMAdapter)miniport_context; SshNdisPacket packet; #ifndef _WIN32_WCE SSH_ASSERT(SSH_GET_IRQL() == SSH_DISPATCH_LEVEL); #endif /* _WIN32_WCE */ SSH_ASSERT(adapter != NULL); SSH_ASSERT(ndis_pkt != NULL); packet = SSH_PACKET_CTX(ndis_pkt); ssh_interceptor_packet_free(&packet->ip); }
void ssh_virtual_adapter_send(SshInterceptor interceptor, SshInterceptorPacket pp) { unsigned char *packet, *internal; size_t packet_len, internal_len; /* Linearize the packet. */ packet_len = ssh_interceptor_packet_len(pp); packet = ssh_xmalloc(packet_len); ssh_interceptor_packet_copyout(pp, 0, packet, packet_len); if (!ssh_interceptor_packet_export_internal_data(pp, &internal, &internal_len)) return; SSH_DEBUG(SSH_D_NICETOKNOW, ("sending send request for virtual adapter %d to forwarder.", (int) pp->ifnum_out)); /* Send the packet to the kernel forwarder module. */ ssh_usermode_interceptor_send_encode( interceptor, SSH_ENGINE_IPM_FORWARDER_VIRTUAL_ADAPTER_SEND, SSH_FORMAT_UINT32, pp->ifnum_in, SSH_FORMAT_UINT32, pp->ifnum_out, SSH_FORMAT_UINT32, pp->protocol, SSH_FORMAT_UINT32_STR, packet, packet_len, SSH_FORMAT_UINT32_STR, internal, internal_len, SSH_FORMAT_END); /* Free the linearized packet. */ ssh_xfree(packet); /* Free the original packet object. */ ssh_interceptor_packet_free(pp); }
/* Dummy function which packets get routed to after ssh_interceptor_stop() has been called. */ static void ssh_interceptor_dummy_packet_cb(SshInterceptorPacket pp, void *ctx) { ssh_interceptor_packet_free(pp); }
void ssh_virtual_adapter_send(SshInterceptor interceptor, SshInterceptorPacket pp) { SshVirtualAdapter adapter; SshInterceptorInternalPacket ipp = (SshInterceptorInternalPacket) pp; struct net_device_stats *stats; struct sk_buff *skb; local_bh_disable(); ssh_kernel_mutex_lock(interceptor->interceptor_lock); adapter = ssh_virtual_adapter_ifnum_to_adapter(interceptor, pp->ifnum_out); if (adapter == NULL) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); SSH_DEBUG(SSH_D_ERROR, ("Virtual adapter %d does not exist", (int)pp->ifnum_out)); goto error; } /* Check the type of the source packet. */ if (pp->protocol == SSH_PROTOCOL_ETHERNET) { /* We can send this directly. */ } else if (pp->protocol == SSH_PROTOCOL_IP4 #ifdef SSH_LINUX_INTERCEPTOR_IPV6 || pp->protocol == SSH_PROTOCOL_IP6 #endif /* SSH_LINUX_INTERCEPTOR_IPV6 */ ) { unsigned char ether_hdr[SSH_ETHERH_HDRLEN]; SshIpAddrStruct src; SshUInt16 ethertype = SSH_ETHERTYPE_IP; unsigned char *cp = NULL; size_t packet_len; /* Add ethernet framing. */ /* Destination is virtual adapter's ethernet address. */ memcpy(ether_hdr + SSH_ETHERH_OFS_DST, adapter->dev->dev_addr, SSH_ETHERH_ADDRLEN); /* Resolve packet's source and the ethernet type to use. */ packet_len = ssh_interceptor_packet_len(pp); /* IPv4 */ if (pp->protocol == SSH_PROTOCOL_IP4) { if (packet_len < SSH_IPH4_HDRLEN) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); SSH_DEBUG(SSH_D_ERROR, ("Packet is too short to contain IPv4 header")); goto error; } /* Pullup requests data from the header of a writable skb. */ if (likely(skb_headlen(ipp->skb) >= SSH_IPH4_HDRLEN && !skb_shared(ipp->skb) && SSH_SKB_WRITABLE(ipp->skb, SSH_IPH4_HDRLEN))) cp = ipp->skb->data; if (cp == NULL) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); goto error_already_freed; } SSH_IPH4_SRC(&src, cp); } #ifdef SSH_LINUX_INTERCEPTOR_IPV6 /* IPv6 */ else { if (packet_len < SSH_IPH6_HDRLEN) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); SSH_DEBUG(SSH_D_ERROR, ("Packet too short to contain IPv6 header")); goto error; } if (likely(skb_headlen(ipp->skb) >= SSH_IPH6_HDRLEN && !skb_shared(ipp->skb) && SSH_SKB_WRITABLE(ipp->skb, SSH_IPH6_HDRLEN))) cp = ipp->skb->data; if (cp == NULL) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); goto error_already_freed; } SSH_IPH6_SRC(&src, cp); ethertype = SSH_ETHERTYPE_IPv6; } #endif /* SSH_LINUX_INTERCEPTOR_IPV6 */ /* Finalize ethernet header. */ ssh_virtual_adapter_ip_ether_address(&src, ether_hdr + SSH_ETHERH_OFS_SRC); SSH_PUT_16BIT(ether_hdr + SSH_ETHERH_OFS_TYPE, ethertype); /* Insert header to the packet. */ cp = NULL; if (likely((skb_headroom(ipp->skb) >= (SSH_ETHERH_HDRLEN + SSH_INTERCEPTOR_PACKET_HARD_HEAD_ROOM)) && !skb_shared(ipp->skb) && SSH_SKB_WRITABLE(ipp->skb, 0))) cp = skb_push(ipp->skb, SSH_ETHERH_HDRLEN); if (cp == NULL) { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); goto error_already_freed; } memcpy(cp, ether_hdr, SSH_ETHERH_HDRLEN); /* Just to be pedantic. */ pp->protocol = SSH_PROTOCOL_ETHERNET; } else { ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); SSH_DEBUG(SSH_D_ERROR, ("Can not handle protocol %d", pp->protocol)); goto error; } /* Tear off the internal packet from the generic SshInterceptorPacket. */ skb = ipp->skb; ipp->skb = NULL; /* (re-)receive the packet via the interface; this should make the packet go back up the stack */ skb->protocol = eth_type_trans(skb, adapter->dev); skb->dev = adapter->dev; /* Update per virtual adapter statistics. */ stats = &adapter->low_level_stats; stats->rx_packets++; stats->rx_bytes += skb->len; ssh_kernel_mutex_unlock(interceptor->interceptor_lock); local_bh_enable(); /* Send the skb up towards stack. If it is IP (or ARP), it will be intercepted by ssh_interceptor_packet_in. */ netif_rx(skb); /* Put the packet header on freelist. */ ssh_interceptor_packet_free((SshInterceptorPacket) ipp); return; error: ssh_interceptor_packet_free(pp); error_already_freed: return; }
/*-------------------------------------------------------------------------- ssh_interceptor_send() Sends packet either down to the network or up to the protocol. --------------------------------------------------------------------------*/ void ssh_interceptor_send(SshInterceptor interceptor, SshInterceptorPacket ip, size_t media_header_len) { SshNdisPacket packet; ULONG first_buf_len = SSH_ETHERH_HDRLEN; SshNdisIMAdapter adapter; SshCpuContext cpu_ctx; Boolean use_one_buffer = FALSE; ULONG new_value; /* Sanity checks for arguments */ SSH_ASSERT(interceptor != NULL); SSH_ASSERT(ip != NULL); SSH_ASSERT((ip->flags & SSH_PACKET_FROMADAPTER) != (ip->flags & SSH_PACKET_FROMPROTOCOL)); #ifndef _WIN32_WCE SSH_ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); #endif /* _WIN32_WCE */ cpu_ctx = &interceptor->cpu_ctx[ssh_kernel_get_cpu()]; packet = CONTAINING_RECORD(ip, SshNdisPacketStruct, ip); #ifdef DEBUG_LIGHT packet->f.flags.in_engine = 0; #endif /* DEBUG_LIGHT */ adapter = (SshNdisIMAdapter)packet->adapter_in; /* Check if adapter where the packet should be sent is different where the packet originated from */ if (adapter && (adapter->ifnum == ip->ifnum_out)) { new_value = InterlockedIncrement(&adapter->ref_count); packet->adapter_out = (SshAdapter)adapter; } else { SshAdapter gen_adapter = NULL; if (ip->ifnum_out < SSH_INTERCEPTOR_MAX_ADAPTERS) { ssh_kernel_rw_mutex_lock_read(&interceptor->adapter_lock); gen_adapter = interceptor->adapter_table[ip->ifnum_out]; if (gen_adapter) { new_value = InterlockedIncrement(&gen_adapter->ref_count); packet->adapter_out = gen_adapter; } ssh_kernel_rw_mutex_unlock_read(&interceptor->adapter_lock); } if (gen_adapter == NULL) goto free_packet; adapter = (SshNdisIMAdapter)gen_adapter; } SSH_ASSERT(new_value > 0); /* Check that active adapter found and it supports the protocol */ if (!ssh_adapter_is_enabled((SshNdisIMAdapter)adapter)) { SSH_DEBUG(SSH_D_FAIL, ("active network connection not found")); goto free_packet; } #ifndef _WIN32_WCE /* Check if packet is plain IPv4 (IPv6) and then add ethernet framing */ if (ip->protocol == SSH_PROTOCOL_IP4 || ip->protocol == SSH_PROTOCOL_IP6) { if (!ssh_wan_packet_encapsulate((SshAdapter)adapter, ip)) { SSH_DEBUG(SSH_D_FAIL, ("packet framing failed")); goto free_packet; } /* Some dial-up drivers seem to expect to receive whole packet in one NDIS buffer. */ if (ip->flags & SSH_PACKET_FROMADAPTER) use_one_buffer = TRUE; } #endif /* _WIN32_WCE */ /* Add the VLAN tagging, if any */ if (packet->vlan_tag_count > 0) { if (adapter != (SshNdisIMAdapter)packet->adapter_in) { /* Engine forwards this packet to different interface. Check whether this is VLAN/QoS enabled interface and reconstruct tagging accordingly. */ switch (adapter->options & (NDIS_MAC_OPTION_8021Q_VLAN | NDIS_MAC_OPTION_8021P_PRIORITY)) { case 0: /* Adapter doesn't support IEEE 802.1q/p; drop VLAN tag(s). */ packet->vlan_tag_count = 0; break; case NDIS_MAC_OPTION_8021P_PRIORITY: /* Adapter supports only priority (QoS) tagging. */ packet->vlan_tags[0].vlan_id = 0; packet->vlan_tag_count = 1; break; default: /* Adapter supports also VLAN. Change the VLAN ID of the first tag to the one configued to this NIC driver. */ packet->vlan_tags[0].vlan_id = adapter->vlan_id; break; } } if (packet->vlan_tag_count) { unsigned char *vlan_tags; SshUInt16 i; vlan_tags = ssh_interceptor_packet_insert(ip, SSH_ETHERH_OFS_TYPE, packet->vlan_tag_count * 4); if (vlan_tags == NULL) { SSH_DEBUG(SSH_D_FAIL, ("Failed to add VLAN tags")); return; } for (i = 0; i < packet->vlan_tag_count; i++) { unsigned char *tag = vlan_tags + (i * 4); SSH_PUT_16BIT(tag, SSH_ETHERTYPE_VLAN); SSH_PUT_16BIT((tag + 2), (packet->vlan_tags[i].vlan_id << 4 | packet->vlan_tags[i].qos)); } } } NDIS_SET_PACKET_HEADER_SIZE(packet->np, SSH_ETHERH_HDRLEN); NDIS_SET_PACKET_STATUS(packet->np, NDIS_STATUS_SUCCESS); #ifdef _WIN32_WCE if (adapter->media == NdisMediumWan) { if (ip->flags & SSH_PACKET_FROMPROTOCOL) { if (!ssh_wan_send_to_adapter(adapter, packet, ip->protocol)) SSH_DEBUG(SSH_D_FAIL, ("Cannot send packet to WAN adapter")); } else if (ip->flags & SSH_PACKET_FROMADAPTER) { if (!ssh_wan_send_to_protocol(adapter, packet, ip->protocol)) SSH_DEBUG(SSH_D_FAIL, ("Cannot send packet to WAN protocol")); } else { SSH_DEBUG(SSH_D_ERROR, ("Dropping WAN packet without direction")); } ssh_interceptor_packet_free(&packet->ip); return; } #endif /* _WIN32_WCE */ if (ip->flags & SSH_PACKET_FROMPROTOCOL) { NDIS_STATUS status; /* Send packet to network */ NdisSetPacketFlags(packet->np, NDIS_FLAGS_DONT_LOOPBACK); if (cpu_ctx->in_packet_cb || cpu_ctx->in_route_cb || cpu_ctx->in_timeout_cb) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Risk for recursive call; enqueueing packet 0x%p", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_send_queue = 1; #endif /* DEBUG_LIGHT */ if (cpu_ctx->in_packet_cb) { ssh_net_packet_enqueue(&cpu_ctx->send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_send_queue = 1; } else if (cpu_ctx->in_route_cb) { ssh_net_packet_enqueue(&cpu_ctx->route_send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_route_send_queue = 1; } else if (cpu_ctx->in_timeout_cb) { ssh_net_packet_enqueue( &cpu_ctx->timeout_send_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_timeout_send_queue = 1; } } else { #ifdef DEBUG_LIGHT SSH_DEBUG(SSH_D_NICETOKNOW, ("Sending packet 0x%p to underlying driver", packet)); packet->f.flags.in_miniport = 1; #endif /* DEBUG_LIGHT */ NdisSend(&status, adapter->binding_handle, packet->np); if (status != NDIS_STATUS_PENDING) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Send operation completed synchronously; " "packet=0x%p, status=%@", ssh_ndis_status_render, status)); ssh_interceptor_packet_free(&packet->ip); } } } else if (ip->flags & SSH_PACKET_FROMADAPTER) { /* Packet is ready now so check packet consistency */ if (use_one_buffer) first_buf_len = packet->packet_len; else first_buf_len += adapter->lookahead_size; first_buf_len = MIN(first_buf_len, packet->packet_len); if (!ssh_packet_get_contiguous_data((SshNetDataPacket)packet, 0, first_buf_len, FALSE)) { SSH_DEBUG(SSH_D_FAIL, ("Invalid packet")); goto free_packet; } if (cpu_ctx->in_packet_cb || cpu_ctx->in_route_cb || cpu_ctx->in_timeout_cb) { SSH_DEBUG(SSH_D_NICETOKNOW, ("Risk for recursive call; enqueueing packet 0x%p", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_recv_queue = 1; #endif /* DEBUG_LIGHT */ if (cpu_ctx->in_packet_cb) { ssh_net_packet_enqueue(&cpu_ctx->recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_recv_queue = 1; } else if (cpu_ctx->in_route_cb) { ssh_net_packet_enqueue(&cpu_ctx->route_recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_route_recv_queue = 1; } else if (cpu_ctx->in_timeout_cb) { ssh_net_packet_enqueue( &cpu_ctx->timeout_recv_queue[adapter->ifnum], (SshNetDataPacket)packet); cpu_ctx->packets_in_timeout_recv_queue = 1; } } else { SSH_DEBUG(SSH_D_NICETOKNOW, ("Indicating packet 0x%p to upper layers", packet)); #ifdef DEBUG_LIGHT packet->f.flags.in_protocol = 1; #endif /* DEBUG_LIGHT */ NdisMIndicateReceivePacket(adapter->handle, &packet->np, 1); } } else { SSH_NOTREACHED; } return; free_packet: /* Otherwise just drop the packet */ SSH_DEBUG(SSH_D_FAIL, ("ssh_interceptor_send(): dropping packet")); ssh_interceptor_packet_free(&packet->ip); }
void ssh_engine_test_basic(SshEngine engine, SshUInt32 flags) { SshUInt32 pass, packetflags, proto, ifnum_in, ifnum_out, sum, offset; SshUInt32 i; size_t seglen, prevseglen, len, iterlen; unsigned char *seg, *prevseg; SshInterceptorPacket pp; engine->test = "basic"; SSH_DEBUG(0, ("testing basic packet processing functions")); for (pass = 0; pass < 1000; pass++) { if (pass % 100 == 0) SSH_DEBUG(0, ("pass=%d", (int)pass)); /* Compute packet length. We want to test all small values, and others at random. */ if (ssh_rand() % 2 == 0) packetflags = SSH_PACKET_FROMADAPTER; else packetflags = SSH_PACKET_FROMPROTOCOL; if (pass < 300) len = pass; else len = ssh_rand() % 100000; ifnum_in = ssh_rand() % ((SshInterceptorIfnum) 0xffffffff); ifnum_out = ssh_rand() % ((SshInterceptorIfnum) 0xffffffff); proto = SSH_PROTOCOL_IP4; SSH_DEBUG(1, ("packetflags 0x%lx, len %ld, proto %d", (long)packetflags, (long)len, (int)proto)); pp = ssh_interceptor_packet_alloc(engine->interceptor, packetflags, proto, ifnum_in, ifnum_out, len); if (pp == NULL) { ssh_engine_test_fail(engine, "packet_alloc returned NULL"); return; } if ((pp->flags & (0xffffff00|SSH_PACKET_FROMPROTOCOL|SSH_PACKET_FROMADAPTER)) != packetflags) { ssh_engine_test_fail(engine, "packet_alloc flags not properly set"); ssh_interceptor_packet_free(pp); return; } /* Add all flags reserved to the engine so that the interceptor cannot use them for anything. */ pp->flags |= 0xffffff00; /* Check protocol and ifnum. */ if (pp->protocol != proto) { ssh_engine_test_fail(engine, "packet_alloc proto not properly set"); ssh_interceptor_packet_free(pp); return; } if (pp->ifnum_in != ifnum_in) { ssh_engine_test_fail(engine, "packet_alloc ifnum_in not properly set"); ssh_interceptor_packet_free(pp); return; } if (pp->ifnum_out != ifnum_out) { ssh_engine_test_fail(engine, "packet_alloc ifnum_out not properly set"); ssh_interceptor_packet_free(pp); return; } /* Check that packet length is correctly returned. */ if (ssh_interceptor_packet_len(pp) != len) { ssh_engine_test_fail(engine, "packet_alloc returned wrong len %ld " "should have been %ld", (long)ssh_interceptor_packet_len(pp), (long)len); ssh_interceptor_packet_free(pp); return; } if (flags & SSH_INTERCEPTOR_TEST_BASIC_ITERATE) { SSH_DEBUG(1, ("iterating")); for (i = 0; i < 10; i++) { offset = ssh_rand() % (len + 1); iterlen = ssh_rand() % (len - offset + 1); SSH_ASSERT(offset + iterlen <= len); sum = 0; prevseg = NULL; prevseglen = 0; ssh_interceptor_packet_reset_iteration(pp, offset, iterlen); while (ssh_interceptor_packet_next_iteration(pp, &seg, &seglen)) { if (prevseg && prevseglen != 0) if (prevseg[0] != (prevseglen & 0xff)) { ssh_engine_test_fail(engine, "iter pointer not preserved"); ssh_interceptor_packet_free(pp); return; } sum += seglen; memset(seg, seglen & 0xff, seglen); prevseg = seg, prevseglen = seglen; } if (seg != NULL) { ssh_engine_test_fail(engine, "next iteration fails"); return; } if (sum != iterlen) { ssh_engine_test_fail(engine, "iteration test fails"); ssh_interceptor_packet_free(pp); return; } } } if (flags & SSH_INTERCEPTOR_TEST_BASIC_PREPEND) { SSH_DEBUG(1, ("inserting (prepend)")); seg = ssh_interceptor_packet_insert(pp, 0, 80); if (seg == NULL) { ssh_engine_test_fail(engine, "insert (prepend) 80 failed"); return; } memset(seg, 'I', 80); len += 80; for (i = 0; i < 10; i++) { seglen = ssh_rand() % (80 + 1); SSH_ASSERT(seglen <= 80); seg = ssh_interceptor_packet_insert(pp, 0, seglen); if (seg == NULL) { ssh_engine_test_fail(engine, "insert (prepend) failed"); return; } memset(seg, 'I', seglen); len += seglen; } if (len != ssh_interceptor_packet_len(pp)) { ssh_engine_test_fail(engine, "len mismatch after insert"); ssh_interceptor_packet_free(pp); return; } } if (flags & SSH_INTERCEPTOR_TEST_BASIC_PULLUP) { SSH_DEBUG(1, ("pullup")); for (i = 0; i < 10; i++) { seglen = ssh_rand() % (80 + 1); SSH_ASSERT(seglen <= 80); if (seglen > len) seglen = len; seg = ssh_interceptor_packet_pullup(pp, seglen); if (seg == NULL) { ssh_engine_test_fail(engine, "pullup failed"); return; } if (flags & SSH_INTERCEPTOR_TEST_BASIC_PREPEND) for (offset = 0; offset < seglen; offset++) if (seg[offset] != 'I') { ssh_engine_test_fail(engine, "pullup compare failed"); ssh_interceptor_packet_free(pp); return; } } if (len != ssh_interceptor_packet_len(pp)) { ssh_engine_test_fail(engine, "len mismatch after pullup"); ssh_interceptor_packet_free(pp); return; } } if (flags & SSH_INTERCEPTOR_TEST_BASIC_INSERT) { SSH_DEBUG(1, ("random inserts")); for (i = 0; i < 10; i++) { offset = ssh_rand() % (len + 1); seglen = ssh_rand() % (80 + 1); seg = ssh_interceptor_packet_insert(pp, offset, seglen); if (seg == NULL) { ssh_engine_test_fail(engine, "insert failed"); return; } memset(seg, 'i', seglen); len += seglen; } if (len != ssh_interceptor_packet_len(pp)) { ssh_engine_test_fail(engine, "len mismatch after pullup"); ssh_interceptor_packet_free(pp); return; } } if (flags & SSH_INTERCEPTOR_TEST_BASIC_DELETE) { SSH_DEBUG(1, ("random deletes")); for (i = 0; i < 10; i++) { offset = ssh_rand() % (len + 1); seglen = ssh_rand() % (len - offset + 1); if (!ssh_interceptor_packet_delete(pp, offset, seglen)) { ssh_engine_test_fail(engine, "packet_delete failed"); return; } len -= seglen; } if (len != ssh_interceptor_packet_len(pp)) { ssh_engine_test_fail(engine, "len mismatch after delete"); ssh_interceptor_packet_free(pp); return; } } if (flags & SSH_INTERCEPTOR_TEST_BASIC_ITERATE) { SSH_DEBUG(1, ("iterating again")); /* Again check that all iterations return correct total length. */ for (i = 0; i < 10; i++) { offset = ssh_rand() % (len + 1); iterlen = ssh_rand() % (len - offset + 1); SSH_ASSERT(offset + iterlen <= len); sum = 0; prevseg = NULL; prevseglen = 0; ssh_interceptor_packet_reset_iteration(pp, offset, iterlen); while (ssh_interceptor_packet_next_iteration(pp, &seg, &seglen)) { if (prevseg && prevseglen != 0) if (prevseg[0] != (prevseglen & 0xff)) { ssh_engine_test_fail(engine, "iter pointer not preserved"); ssh_interceptor_packet_free(pp); return; } sum += seglen; memset(seg, seglen & 0xff, seglen); prevseg = seg, prevseglen = seglen; } if (seg != NULL) { ssh_engine_test_fail(engine, "next iteration fails"); return; } if (sum != iterlen) { ssh_engine_test_fail(engine, "iteration (again) test fails"); ssh_interceptor_packet_free(pp); return; } } } SSH_DEBUG(1, ("freeing")); ssh_interceptor_packet_free(pp); } ssh_engine_test_ok(engine); }
/*------------------------------------------------------------------------ ssh_interceptor_send_to_engine() If interceptor is enabled then packets are sent to engine for post-processing otherwise the packet resources are freed. Arguments: interceptor - interceptor object adpater - adapter object pkt_cts - packet context Returns: Notes: ------------------------------------------------------------------------*/ void ssh_interceptor_send_to_engine(SshNdisIMInterceptor interceptor, SshNdisIMAdapter adapter, SshNdisPacket packet) { PNDIS_PACKET pkt = packet->np; size_t media_header_len = SSH_ETHERH_HDRLEN; SshCpuContext cpu_ctx; #ifdef _WIN32_WCE SSH_ASSERT(MAXIMUM_PROCESSORS == 1); #else SSH_ASSERT(SSH_GET_IRQL() == SSH_DISPATCH_LEVEL); #endif /* _WIN32_WCE */ /* Remove VLAN tagging before forwarding this packet to engine. This code supports also stacked VLANs. The maximum amount of VLAN encapsulation tags is defined by SSH_VLAN_MAX_VLAN_TAGS. */ if (packet->eth_type == SSH_ETHERTYPE_VLAN) { SshUInt16 tag_count = 0; while (packet->eth_type == SSH_ETHERTYPE_VLAN) { unsigned char temp[4]; SshUInt16 tag; if (tag_count == SSH_VLAN_MAX_VLAN_TAGS) { SSH_DEBUG(SSH_D_FAIL, ("Maximum number of stacked VLAN IDs edceeded; " "dropping packet.")); ssh_interceptor_packet_free(&packet->ip); return; } /* Copy next VLAN tag to packet context */ ssh_interceptor_packet_copyout(&packet->ip, media_header_len + tag_count * sizeof(temp), temp, sizeof(temp)); tag = SSH_GET_16BIT(temp); packet->vlan_tags[tag_count].qos = (tag & 0x0007); packet->vlan_tags[tag_count].vlan_id = (tag >> 4); packet->eth_type = SSH_GET_16BIT(&temp[2]); /* If we haven't seen OID_GEN_VLAN_ID query/set (this is the case in Windows 2000), we need to pick and store the VLAN ID from this packet. */ if ((tag_count == 0) && (adapter->vlan_id_known == 0)) adapter->vlan_id = packet->vlan_tags[0].vlan_id; tag_count++; } /* Delete VLAN tags from packet */ if (!ssh_interceptor_packet_delete(&packet->ip, SSH_ETHERH_OFS_TYPE, tag_count * 4)) { SSH_DEBUG(SSH_D_FAIL, ("Failed to remove VLAN tags")); return; } packet->vlan_tag_count = tag_count; }