示例#1
0
static Boolean
ssh_driver_copy_and_send_wan(SshNdisIMAdapter adapter, 
                             PNDIS_WAN_PACKET pkt,
                             SshInterceptorProtocol protocol)
{
  SshNdisIMInterceptor interceptor;
  SshCpuContext cpu_ctx;
  SshInterceptorPacket ip;
  SshNdisPacket packet;
  LONG new_value;

  SSH_ASSERT(adapter != NULL);
  SSH_ASSERT(adapter->interceptor != NULL);
  SSH_ASSERT(pkt != NULL);

  interceptor = (SshNdisIMInterceptor)adapter->interceptor;
  SSH_ASSERT(MAXIMUM_PROCESSORS == 1);
  cpu_ctx = &interceptor->cpu_ctx[0];

  /* Allocate a new packet. */
  ip = ssh_interceptor_packet_alloc((SshInterceptor)interceptor, 
                                    SSH_PACKET_FROMADAPTER,
                                    protocol,
                                    adapter->ifnum,
                                    SSH_INTERCEPTOR_INVALID_IFNUM,
                                    pkt->CurrentLength);
  if (ip == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, 
                ("Adapter %@: Failed to allocate packet",
                 ssh_adapter_id_st_render, adapter));
      return FALSE;
    }

  /* Copy the data into the packet. */
  if (!ssh_interceptor_packet_copyin(ip, 0, pkt->CurrentBuffer,
                                     pkt->CurrentLength))
    {
      SSH_DEBUG(SSH_D_FAIL, 
                ("Adapter %@: Failed to copy WAN packet",
                 ssh_adapter_id_st_render, adapter));
      return FALSE;
    }

  packet = CONTAINING_RECORD(ip, SshNdisPacketStruct, ip);

  /* Set don't loopback flag. */
  NdisSetPacketFlags(packet->np, NDIS_FLAGS_DONT_LOOPBACK);

  NDIS_SET_PACKET_STATUS(packet->np, NDIS_STATUS_SUCCESS);
  SSH_ASSERT(packet->parent_complete_cb == NULL_FNPTR);

  packet->complete_cb = ssh_driver_send_complete_cb;
  packet->complete_cb_handle = adapter;
  packet->complete_cb_param = NULL;

  packet->f.flags.from_local_stack = 1;
  packet->ip.ifnum_in = adapter->ifnum;
  packet->ip.flags |= SSH_PACKET_FROMPROTOCOL;
  packet->adapter_in = (SshAdapter)adapter;

  new_value = InterlockedIncrement(&adapter->ref_count);
  SSH_ASSERT(new_value > 0);

  SSH_DUMP_PACKET(SSH_D_MY5, ("Cloned packet:"), packet);

  ssh_interceptor_send_to_engine(interceptor, adapter, packet);
  ssh_interceptor_process_enqueued_packets(interceptor, cpu_ctx);

  return TRUE;
}
示例#2
0
VOID
MPSendPackets(
    IN NDIS_HANDLE             MiniportAdapterContext,
    IN PPNDIS_PACKET           PacketArray,
    IN UINT                    NumberOfPackets
    )
/*++

Routine Description:

    Send Packet Array handler. Either this or our SendPacket handler is called
    based on which one is enabled in our Miniport Characteristics.

Arguments:

    MiniportAdapterContext     Pointer to our adapter
    PacketArray                Set of packets to send
    NumberOfPackets            Self-explanatory

Return Value:

    None

--*/
{
    PADAPT              pAdapt = (PADAPT)MiniportAdapterContext;
    NDIS_STATUS         Status;
    UINT                i;
    PVOID               MediaSpecificInfo = NULL;
    UINT                MediaSpecificInfoSize = 0;
	FILTER_STATUS		fStatus;
	PUCHAR				pBuffer;
	int					nBufLen;
    

    for (i = 0; i < NumberOfPackets; i++)
    {
        PNDIS_PACKET    Packet, MyPacket;

        Packet = PacketArray[i];

		//KdPrint(("微端口MPSendPackets方法,开始报文分析\n"));
		getMemoryCopyFromPacket(Packet, &pBuffer, &nBufLen);
		KdPrint(("\n==> 微端口MPSendPackets方法,开始分析报文\n"));
		fStatus = analyzeBuffer(pAdapt, pBuffer, &nBufLen, MODE_SEND);
		//fStatus = AnalysisPacket(Packet, FALSE);
		//fStatus = FILTER_STATUS_PASS;
		if (fStatus == FILTER_STATUS_DROP)
		{
			//丢弃
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_DROP模式\n"));
			freeMemory(pBuffer);
			// 在这个函数中,任何一个被放弃的包,都必须调用NdisMSendComplete。
			NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt), Packet, NDIS_STATUS_FAILURE);
			continue; 
		}
		/*
		else if (fStatus == FILTER_STATUS_MODIFY_REDIRECT)
		{
			//没有发送时接收转发这种情况
		}
		*/
		else if (fStatus == FILTER_STATUS_MODIFY_SEND)
		{
			//修改+发送
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_MODIFY_SEND模式\n"));
			MyPacket = createPacketFromMemory_SendPool(pAdapt, pBuffer, nBufLen);
			//freePacketBufferOnly(Packet);

			// The driver should fail the send if the virtual miniport is in low 
			// power state
			//
			if (pAdapt->MPDeviceState > NdisDeviceStateD0)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
					Packet,
					NDIS_STATUS_FAILURE);
				continue;
			}
			//这里原来有NDIS51的一个简化处理,放在此文件最下面了
			do 
			{
				PSEND_RSVD        SendRsvd;

				NdisAcquireSpinLock(&pAdapt->Lock);
				//
				// If the below miniport is going to low power state, stop sending down any packet.
				//
				if (pAdapt->PTDeviceState > NdisDeviceStateD0)
				{
					NdisReleaseSpinLock(&pAdapt->Lock);
					Status = NDIS_STATUS_FAILURE;
					break;
				}
				pAdapt->OutstandingSends++;
				NdisReleaseSpinLock(&pAdapt->Lock);
				
				//NdisAllocatePacket(&Status,
				//	&MyPacket,
				//	pAdapt->SendPacketPoolHandle);
				
				SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
				SendRsvd->OriginalPkt = Packet;
				
				NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
				NdisSetPacketFlags(MyPacket, NDIS_FLAGS_RESERVED4); //我们做个标记
				
				//现在我们自己构造buffer,所以不需要用原packet的buffer了
				//NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
				//NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);
				
				//
				// Copy the OOB data from the original packet to the new
				// packet.
				//
				NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
					NDIS_OOB_DATA_FROM_PACKET(Packet),
					sizeof(NDIS_PACKET_OOB_DATA));
				//
				// Copy relevant parts of the per packet info into the new packet
				//
				NdisIMCopySendPerPacketInfo(MyPacket, Packet);
				
				//
				// Copy the Media specific information
				//
				NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
					&MediaSpecificInfo,
					&MediaSpecificInfoSize);
				
				if (MediaSpecificInfo || MediaSpecificInfoSize)
				{
					NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
						MediaSpecificInfo,
						MediaSpecificInfoSize);
				}
				
				NdisSend(&Status,
					pAdapt->BindingHandle,
					MyPacket);
				
				if (Status != NDIS_STATUS_PENDING)
				{
					NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
					//NdisFreePacket(MyPacket);
					freePacketBufferAndMemory(MyPacket);
					ADAPT_DECR_PENDING_SENDS(pAdapt);
				}
			}
			while (FALSE);
			
			if (Status != NDIS_STATUS_PENDING)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
					Packet,
					Status);
			}
		}
		else //FILTER_STATUS_PASS
		{
			//按PASS处理
			KdPrint(("<== 微端口MPSendPackets方法,进入FILTER_STATUS_PASS模式\n"));
			freeMemory(pBuffer);
			//
			// The driver should fail the send if the virtual miniport is in low 
			// power state
			//
			if (pAdapt->MPDeviceState > NdisDeviceStateD0)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
								Packet,
								NDIS_STATUS_FAILURE);
				continue;
			}
			//这里原来有NDIS51的一个简化处理,放在此文件最下面了
			do 
			{
				NdisAcquireSpinLock(&pAdapt->Lock);
				//
				// If the below miniport is going to low power state, stop sending down any packet.
				//
				if (pAdapt->PTDeviceState > NdisDeviceStateD0)
				{
					NdisReleaseSpinLock(&pAdapt->Lock);
					Status = NDIS_STATUS_FAILURE;
					break;
				}
				pAdapt->OutstandingSends++;
				NdisReleaseSpinLock(&pAdapt->Lock);
            
				NdisAllocatePacket(&Status,
								   &MyPacket,
								   pAdapt->SendPacketPoolHandle);

				if (Status == NDIS_STATUS_SUCCESS)
				{
					PSEND_RSVD        SendRsvd;

					SendRsvd = (PSEND_RSVD)(MyPacket->ProtocolReserved);
					SendRsvd->OriginalPkt = Packet;

					NdisGetPacketFlags(MyPacket) = NdisGetPacketFlags(Packet);
					NdisClearPacketFlags(MyPacket, NDIS_FLAGS_RESERVED4); //防止和上面的包混淆

					NDIS_PACKET_FIRST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_FIRST_NDIS_BUFFER(Packet);
					NDIS_PACKET_LAST_NDIS_BUFFER(MyPacket) = NDIS_PACKET_LAST_NDIS_BUFFER(Packet);

					//
					// Copy the OOB data from the original packet to the new
					// packet.
					//
					NdisMoveMemory(NDIS_OOB_DATA_FROM_PACKET(MyPacket),
								NDIS_OOB_DATA_FROM_PACKET(Packet),
								sizeof(NDIS_PACKET_OOB_DATA));
					//
					// Copy relevant parts of the per packet info into the new packet
					//
					NdisIMCopySendPerPacketInfo(MyPacket, Packet);

					//
					// Copy the Media specific information
					//
					NDIS_GET_PACKET_MEDIA_SPECIFIC_INFO(Packet,
														&MediaSpecificInfo,
														&MediaSpecificInfoSize);

					if (MediaSpecificInfo || MediaSpecificInfoSize)
					{
						NDIS_SET_PACKET_MEDIA_SPECIFIC_INFO(MyPacket,
															MediaSpecificInfo,
															MediaSpecificInfoSize);
					}

					NdisSend(&Status,
							 pAdapt->BindingHandle,
							 MyPacket);

					if (Status != NDIS_STATUS_PENDING)
					{
						NdisIMCopySendCompletePerPacketInfo (Packet, MyPacket);
						NdisFreePacket(MyPacket);
						ADAPT_DECR_PENDING_SENDS(pAdapt);
					}
				}
				else
				{
					//
					// The driver cannot allocate a packet.
					// 
					ADAPT_DECR_PENDING_SENDS(pAdapt);
				}
			}
			while (FALSE);

			if (Status != NDIS_STATUS_PENDING)
			{
				NdisMSendComplete(ADAPT_MINIPORT_HANDLE(pAdapt),
								  Packet,
								  Status);
			}
		}
    }
}
示例#3
0
/*-------------------------------------------------------------------------
  ssh_driver_send_packets()

  Sends multiple NDIS packet into the network via virtual NIC. 
  The packets are copied and then saved into a queue. The interceptor
  thread then processes the packets later.

  Arguments:
  miniport_context - virtual NIC object
  packet_array - array of NDIS packets
  packet_cnt - number of packets in the array
        
  Returns:
        
  Notes:
  To ensure that the sequential ordering of packets is not changed in
  error conditions we interrupt processing packets in the array whenever 
  we notice that we cannot handle the packet. All the remaining packets in 
  the array are then completed with FAILURE status.

  If we are running low of NDIS_PACKET resources then return with failure
  so that upper layer notices our lack of resources and the traffic then
  decreases.

  Default IRQL: <= DISPATCH_LEVEL
  -------------------------------------------------------------------------*/
static Boolean
ssh_driver_copy_and_send(SshNdisIMAdapter adapter,
                         PNDIS_PACKET src)
{
  SshNdisIMInterceptor interceptor;
  SshCpuContext cpu_ctx;
  SshNdisPacket packet;
  ULONG new_value;
  UINT flags;
  SSH_IRQL old_irql;
  Boolean status = FALSE;

  SSH_ASSERT(adapter != NULL);
  SSH_ASSERT(src != NULL);

  SSH_RAISE_IRQL(DISPATCH_LEVEL, &old_irql);

  new_value = InterlockedIncrement(&adapter->ref_count);
  SSH_ASSERT(new_value > 0);

  if (!ssh_adapter_can_accept_send(adapter))
    {
      SSH_DEBUG(SSH_D_FAIL, 
                ("Adapter %@: not in running state!", 
                 ssh_adapter_id_st_render, adapter));
      InterlockedDecrement(&adapter->ref_count);
      goto end;
    }

  interceptor = (SshNdisIMInterceptor)adapter->interceptor;
#ifdef _WIN32_WCE
  ssh_kernel_critical_section_start(&interceptor->packet_pool_cs);
#endif /* _WIN32_WCE */
  cpu_ctx = &interceptor->cpu_ctx[ssh_kernel_get_cpu()];

  /* Try to clone the original packet's descriptors */
  packet = ssh_packet_clone((SshInterceptor)interceptor, 
                            &cpu_ctx->packet_pool, 
                            SSH_PROTOCOL_ETHERNET, 
                            src, 
                            FALSE);
#ifdef _WIN32_WCE
  ssh_kernel_critical_section_end(&interceptor->packet_pool_cs);
#endif /* _WIN32_WCE */

  if (packet == NULL)
    {
      SSH_DEBUG(SSH_D_FAIL, 
                ("Adapter %@: Failed to clone packet",
                 ssh_adapter_id_st_render, adapter));
      InterlockedDecrement(&adapter->ref_count);
      goto end;
    }

  NDIS_SET_PACKET_STATUS(src, NDIS_STATUS_PENDING);

  packet->complete_cb = ssh_driver_send_complete_cb;
  packet->complete_cb_handle = adapter;
  packet->complete_cb_param = NULL;

  packet->parent_complete_cb = ssh_driver_parent_send_complete_cb;
  packet->parent_complete_handle = adapter;
  packet->parent_complete_np = src;
  packet->parent_complete_param = (void *)NDIS_STATUS_SUCCESS;

  /* Set don't loopback flag and per packet info */
  flags = NdisGetPacketFlags(packet->np);
  flags |= NDIS_FLAGS_DONT_LOOPBACK;
  NdisSetPacketFlags(packet->np, flags);
  NdisIMCopySendPerPacketInfo(packet->np, src);

  /* Set the information that engine uses */
  SSH_DUMP_PACKET(SSH_D_MY5, "Cloned packet:", packet);

  packet->f.flags.from_local_stack = 1;
  packet->ip.ifnum_in = adapter->ifnum;
  packet->ip.flags |= SSH_PACKET_FROMPROTOCOL;
  packet->adapter_in = (SshAdapter)adapter;

  SSH_DEBUG(SSH_D_NICETOKNOW, 
            ("Adapter %@: %u operations pending", 
             ssh_adapter_id_st_render, adapter, new_value));

  ssh_interceptor_send_to_engine(interceptor, adapter, packet);
  ssh_interceptor_process_enqueued_packets(interceptor, cpu_ctx);

  status = TRUE;

end:
  if (old_irql < SSH_DISPATCH_LEVEL)
    SSH_LOWER_IRQL(old_irql);

  return status;
}
示例#4
0
/*--------------------------------------------------------------------------
  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);
}