Example #1
0
NTSTATUS
LfsSvrDatagramRecvHandler (
	IN PVOID	TdiEventContext,
	IN LONG		SourceAddressLength,
	IN PVOID	SourceAddress,
	IN LONG		OptionsLength,
	IN PVOID	Options,
	IN ULONG	ReceiveDatagramFlags,
	IN ULONG	BytesIndicated,
	IN ULONG	BytesAvailable,
	OUT ULONG   *BytesTaken,
	IN PVOID	Tsdu,
	OUT PIRP	*IoRequestPacket
	)
{
	PLFSDGRAMSVR_CTX	SvrCtx = (PLFSDGRAMSVR_CTX)TdiEventContext;
	PTRANSPORT_ADDRESS	ClientAddr = (PTRANSPORT_ADDRESS)SourceAddress;
	PLPX_ADDRESS		ClientLpxAddr = (PLPX_ADDRESS)ClientAddr->Address[0].Address;
	PLFSDG_PKT			Pkt;
	BOOLEAN				bRet;
	static UCHAR		Protocol[4] = NDFT_PROTOCOL;

	UNREFERENCED_PARAMETER( SourceAddressLength );
	UNREFERENCED_PARAMETER( OptionsLength );
	UNREFERENCED_PARAMETER( Options );
	UNREFERENCED_PARAMETER( ReceiveDatagramFlags );
	UNREFERENCED_PARAMETER( BytesTaken );
	UNREFERENCED_PARAMETER( IoRequestPacket );

#if !DBG
	UNREFERENCED_PARAMETER(BytesIndicated);
#endif

	// BytesIndicated, BytesAvailable, BytesTaken
	
	SPY_LOG_PRINT( LFS_DEBUG_LIB_NOISE, 
				   ("[LFS] LfsSvrDatagramRecvHandler: BytesIndicated : %d BytesAvailable : %d\n",
					BytesIndicated, BytesAvailable) );

	if (BytesAvailable < sizeof(NDFT_HEADER) ) {
		
		SPY_LOG_PRINT( LFS_DEBUG_LIB_INFO, ( "[LFS] LfsSvrDatagramRecvHandler: too small bytes.\n" ) );
		goto not_accepted;
	}

	bRet = LfsAllocDGPkt( &Pkt, MAX_DATAGRAM_DATA_SIZE );
	
	if (FALSE == bRet) {
	
		SPY_LOG_PRINT( LFS_DEBUG_LIB_INFO, ( "[LFS] LfsSvrDatagramRecvHandler: LfsAllocDGPkt() failed.\n") );
		goto not_accepted;
	}

	//	read the head

	RtlCopyMemory( &Pkt->RawHeadDG, Tsdu, sizeof(Pkt->RawHeadDG) );

	//	validation check

	SPY_LOG_PRINT( LFS_DEBUG_LIB_NOISE, 
					("[LFS] LfsSvrDatagramRecvHandler: Protocol:%lx Ver:%x.%x TotalSize:%ld"
					 " Type:%x\n",
					 *((ULONG *)Pkt->RawHeadDG.Protocol), 
					 NTOHS(Pkt->RawHeadDG.NdfsMajorVersion2), 
					 NTOHS(Pkt->RawHeadDG.NdfsMinorVersion2),
					 NTOHL(Pkt->RawHeadDG.MessageSize4), 
					 NTOHS(Pkt->RawHeadDG.Type2)) );

	if (RtlCompareMemory(Pkt->RawHeadDG.Protocol, Protocol, 4) != 4 ||
		NTOHS(Pkt->RawHeadDG.NdfsMajorVersion2) != NDFT_MAJVER		||
		NTOHS(Pkt->RawHeadDG.NdfsMinorVersion2) != NDFT_MINVER		||
		(NTOHS(Pkt->RawHeadDG.Type2) & LFSPKTTYPE_PREFIX) != (LFSPKTTYPE_DATAGRAM | LFSPKTTYPE_REQUEST) ) {

		LfsDereferenceDGPkt(Pkt);

		SPY_LOG_PRINT( LFS_DEBUG_LIB_NOISE, ("[LFS] LfsSvrDatagramRecvHandler: Invalid reply header.\n") );
		goto not_accepted;
	}

	Pkt->PacketSize	= NTOHL(Pkt->RawHeadDG.MessageSize4);
	Pkt->DataSize	= NTOHL(Pkt->RawHeadDG.MessageSize4) - sizeof(NDFT_HEADER);

	if (Pkt->PacketSize != sizeof(NDFT_HEADER) + Pkt->DataSize ) {

		LfsDereferenceDGPkt(Pkt);
		SPY_LOG_PRINT( LFS_DEBUG_LIB_INFO, ("[LFS] LfsSvrDatagramRecvHandler: Invalid reply packet size.\n") );
		goto not_accepted;
	}

	if (BytesAvailable < Pkt->PacketSize) {
	
		LfsDereferenceDGPkt(Pkt);
		SPY_LOG_PRINT( LFS_DEBUG_LIB_INFO, ("[LFS] LfsSvrDatagramRecvHandler: wrong message size contained.\n") );
		goto not_accepted;
	}

	//	retrieve the source address.
	//	Do not trust Owner's address in the packet.

	RtlCopyMemory(&Pkt->SourceAddr, ClientLpxAddr, sizeof(LPX_ADDRESS));

	SPY_LOG_PRINT( LFS_DEBUG_LIB_NOISE, 
				  ("[LFS] LfsSvrDatagramRecvHandler:"
				   " received a datagram packet from %02X:%02X:%02X:%02X:%02X:%02X/%d\n",
				   ClientLpxAddr->Node[0],ClientLpxAddr->Node[1],ClientLpxAddr->Node[2],
				   ClientLpxAddr->Node[3],ClientLpxAddr->Node[4],ClientLpxAddr->Node[5],
				   (int)ClientLpxAddr->Port) );

	//	read the data

	RtlCopyMemory( &Pkt->RawDataDG, (PUCHAR)Tsdu + sizeof(Pkt->RawHeadDG), Pkt->DataSize );

	//	insert to the packet queue

	InitializeListHead( &Pkt->PktListEntry );

	ExInterlockedInsertTailList( &SvrCtx->RecvDGPktQueue,
								 &Pkt->PktListEntry,
								 &SvrCtx->RecvDGPktQSpinLock );

	KeSetEvent( &SvrCtx->DatagramRecvEvent, IO_NO_INCREMENT, FALSE );

	return STATUS_SUCCESS;

not_accepted:

	SPY_LOG_PRINT( LFS_DEBUG_LIB_NOISE, 
				   ("[LFS] LfsSvrDatagramRecvHandler: a datagram packet rejected.\n") );

	return STATUS_DATA_NOT_ACCEPTED;
}
Example #2
0
/*
 * Send trap, SNMP v1 (RFC 1157).
 * SEQUENCE {
 *	version: INTEGER [=0]
 *	community: STRING
 *	pdu: SEQUENCE [=TRAP] {
 *		enterprise: OBJECT IDENTIFIER
 *		agent-addr: NetworkAddress
 *		generic-trap: INTEGER
 *		specific-trap: INTEGER
 *		time-stamp: INTEGER
 *		varlist: SEQUENCE {
 *			var1: SEQUENCE {
 *				name: OID
 *				value: ...
 *			}
 *			...
 * }	}	}
 */
bool_t
snmp_trap_v1 (snmp_t *snmp, udp_socket_t *sock, unsigned char *local_ip,
	unsigned trap_type, asn_t *oid, asn_t *value)
{
	asn_t *pdu, *trap, *varlist, *var1;
	buf_t *pkt;
	unsigned char *output, status;
	unsigned long santisec;

	/*debug_printf ("snmp_trap(%#x)\n", traptype);*/
	if (oid) {
		var1 = asn_make_seq (snmp->pool, 2, ASN_SEQUENCE);
		if (! var1) {
			asn_free (oid);
			asn_free (value);
			return 0;
		}
		var1->seq.count = 2;
		var1->seq.arr[0] = oid;
		var1->seq.arr[1] = value;
	} else
		var1 = 0;

	/*
	 * List of variables.
	 */
	varlist = asn_make_seq (snmp->pool, 1, ASN_SEQUENCE);
	if (! varlist) {
		asn_free (var1);
		return 0;
	}
	varlist->seq.count = var1 ? 1 : 0;
	varlist->seq.arr[0] = var1;

	/*
	 * Protocol data unit.
	 */
	pdu = asn_make_seq (snmp->pool, 6, ASN_TRAP);
	if (! pdu) {
		asn_free (varlist);
		return 0;
	}
	pdu->seq.count = 6;
	pdu->seq.arr[5] = varlist;

	/* Enterprise */
	pdu->seq.arr[0] = asn_make_oid (snmp->pool, "1.3.6.1.4.1.20520");
	pdu->seq.arr[0]->oid.id[6] = snmp->enterprise;

	/* Agent IP address */
	pdu->seq.arr[1] = asn_make_int (snmp->pool,
		NTOHL (*(unsigned long*) local_ip), ASN_IP_ADDRESS);

	/* Generic trap code */
	pdu->seq.arr[2] = asn_make_int (snmp->pool, trap_type & 0xff,
		ASN_INTEGER);

	/* Specific trap code */
	pdu->seq.arr[3] = asn_make_int (snmp->pool, trap_type >> 8,
		ASN_INTEGER);

	/* Timestamp */
	santisec = 0;
	if (snmp->ip && snmp->ip->timer) {
		unsigned long msec;
		unsigned days = timer_days (snmp->ip->timer, &msec);
		santisec = msec / 10 + days * 24L * 60 * 60 * 100;
	}
	pdu->seq.arr[4] = asn_make_int (snmp->pool, santisec, ASN_TIME_TICKS);

	/*
	 * Trap.
	 */
	trap = asn_make_seq (snmp->pool, 3, ASN_SEQUENCE);
	if (! trap) {
		asn_free (pdu);
		return 0;
	}
	trap->seq.count = 3;
	trap->seq.arr[2] = pdu;

	/* Version */
	trap->seq.arr[0] = asn_make_int (snmp->pool, 0, ASN_INTEGER);

	/* Community */
	trap->seq.arr[1] = asn_make_string (snmp->pool, snmp->trap_community);

	/* Encode and send */
	status = 0;
	pkt = buf_alloc (snmp->pool, TRAP_PACKET_SIZE, 50);
	if (pkt) {
		output = asn_encode (trap, pkt->payload + pkt->len, pkt->len);
		if (! output) {
			buf_free (pkt);
		} else {
			/* Send */
			assert (output >= pkt->payload);
			buf_add_header (pkt, - (output - pkt->payload));
			/* debug_dump ("trap-v1", pkt->payload, pkt->len); */
			status = udp_sendto (sock, pkt, snmp->trap_addr, 162);
			++snmp->out_traps;
			++snmp->out_pkts;
		}
	}
	asn_free (trap);
	return status;
}
/**
  This function is called to provide results data to the driver.
  This data consists of a unique key that is used to identify
  which data is either being passed back or being asked for.

  @param[in]  This               Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
  @param[in]  Action             Specifies the type of action taken by the browser.
  @param[in]  QuestionId         A unique value which is sent to the original
                                 exporting driver so that it can identify the type
                                 of data to expect. The format of the data tends to
                                 vary based on the opcode that enerated the callback.
  @param[in]  Type               The type of value for the question.
  @param[in]  Value              A pointer to the data being sent to the original
                                 exporting driver.
  @param[out] ActionRequest      On return, points to the action requested by the
                                 callback function.

  @retval EFI_SUCCESS            The callback successfully handled the action.
  @retval EFI_OUT_OF_RESOURCES   Not enough storage is available to hold the
                                 variable and its data.
  @retval EFI_DEVICE_ERROR       The variable could not be saved.
  @retval EFI_UNSUPPORTED        The specified Action is not supported by the
                                 callback.Currently not implemented.
  @retval EFI_INVALID_PARAMETERS Passing in wrong parameter.
  @retval Others                 Other errors as indicated.

**/
EFI_STATUS
EFIAPI
Ip4FormCallback (
  IN  CONST EFI_HII_CONFIG_ACCESS_PROTOCOL   *This,
  IN  EFI_BROWSER_ACTION                     Action,
  IN  EFI_QUESTION_ID                        QuestionId,
  IN  UINT8                                  Type,
  IN  EFI_IFR_TYPE_VALUE                     *Value,
  OUT EFI_BROWSER_ACTION_REQUEST             *ActionRequest
  )
{
  EFI_STATUS                Status;
  IP4_CONFIG2_INSTANCE      *Instance;
  IP4_CONFIG2_IFR_NVDATA    *IfrFormNvData;
  IP4_FORM_CALLBACK_INFO    *Private;

  EFI_IP_ADDRESS            StationAddress;
  EFI_IP_ADDRESS            SubnetMask;
  EFI_IP_ADDRESS            Gateway;
  IP4_ADDR                  Ip;
  EFI_IPv4_ADDRESS          *DnsAddress;
  UINTN                     DnsCount;
  UINTN                     Index;
  EFI_INPUT_KEY             Key;

  IfrFormNvData = NULL;
  DnsCount      = 0;
  DnsAddress    = NULL;

  if (Action == EFI_BROWSER_ACTION_CHANGED) {
    Private = IP4_FORM_CALLBACK_INFO_FROM_CONFIG_ACCESS(This);
    Instance = IP4_CONFIG2_INSTANCE_FROM_FORM_CALLBACK(Private);

    IfrFormNvData = AllocateZeroPool (sizeof (IP4_CONFIG2_IFR_NVDATA));
    if (IfrFormNvData == NULL) {
      return EFI_OUT_OF_RESOURCES;
    }

    //
    // Retrieve uncommitted data from Browser
    //
    if (!HiiGetBrowserData (&gIp4Config2NvDataGuid, mIp4Config2StorageName, sizeof (IP4_CONFIG2_IFR_NVDATA), (UINT8 *) IfrFormNvData)) {
      FreePool (IfrFormNvData);
      return EFI_NOT_FOUND;
    }

    Status = EFI_SUCCESS;

    switch (QuestionId) {
    case KEY_LOCAL_IP:
      Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
      if (EFI_ERROR (Status) || IP4_IS_UNSPECIFIED (NTOHL (StationAddress.Addr[0])) || IP4_IS_LOCAL_BROADCAST (NTOHL (StationAddress.Addr[0]))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_SUBNET_MASK:
      Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
      if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_GATE_WAY:
      Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
      if (EFI_ERROR (Status) || IP4_IS_LOCAL_BROADCAST(NTOHL(Gateway.Addr[0]))) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
        Status = EFI_INVALID_PARAMETER;
      }
      break;

    case KEY_DNS:
      Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
      if (!EFI_ERROR (Status) && DnsCount > 0) {
        for (Index = 0; Index < DnsCount; Index ++) {
          CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
          if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
            CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
            Status = EFI_INVALID_PARAMETER;
            break;
          }
        }
      } else {
        if (EFI_ERROR (Status)) {
          CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
        }
      }

      if(DnsAddress != NULL) {
        FreePool(DnsAddress);
      }
      break;

    case KEY_SAVE_CHANGES:
      Status = Ip4Config2ConvertIfrNvDataToConfigNvData (IfrFormNvData, Instance);
      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
      break;

    default:
      break;
    }

    FreePool (IfrFormNvData);

    return Status;
  }

  //
  // All other action return unsupported.
  //
  return EFI_UNSUPPORTED;
}
Example #4
0
static int
ip6_fw_chk(struct ip6_hdr **pip6,
	struct ifnet *oif, struct mbuf **m)
{
	struct ip6_fw_chain *chain;
	struct ip6_fw *rule = NULL;
	struct ip6_hdr *ip6 = *pip6;
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
	u_short offset = 0;
	int off = sizeof(struct ip6_hdr), nxt = ip6->ip6_nxt;
	u_short src_port, dst_port;
#ifdef	IP6FW_DIVERT_RESTART
	u_int16_t skipto = 0;
#else
	u_int16_t ignport = 0;
#endif

	/*
	 * Go down the chain, looking for enlightment
	 * #ifdef IP6FW_DIVERT_RESTART
	 * If we've been asked to start at a given rule immediatly, do so.
	 * #endif
	 */
	chain = LIST_FIRST(&ip6_fw_chain);
#ifdef IP6FW_DIVERT_RESTART
	if (skipto) {
		if (skipto >= 65535)
			goto dropit;
		while (chain && (chain->rule->fw_number <= skipto)) {
			chain = LIST_NEXT(chain, chain);
		}
		if (! chain) goto dropit;
	}
#endif /* IP6FW_DIVERT_RESTART */
	for (; chain; chain = LIST_NEXT(chain, chain)) {
		struct ip6_fw *const f = chain->rule;

		if (oif) {
			/* Check direction outbound */
			if (!(f->fw_flg & IPV6_FW_F_OUT))
				continue;
		} else {
			/* Check direction inbound */
			if (!(f->fw_flg & IPV6_FW_F_IN))
				continue;
		}

#define IN6_ARE_ADDR_MASKEQUAL(x,y,z) (\
	(((x)->s6_addr32[0] & (y)->s6_addr32[0]) == (z)->s6_addr32[0]) && \
	(((x)->s6_addr32[1] & (y)->s6_addr32[1]) == (z)->s6_addr32[1]) && \
	(((x)->s6_addr32[2] & (y)->s6_addr32[2]) == (z)->s6_addr32[2]) && \
	(((x)->s6_addr32[3] & (y)->s6_addr32[3]) == (z)->s6_addr32[3]))

		/* If src-addr doesn't match, not this rule. */
		if (((f->fw_flg & IPV6_FW_F_INVSRC) != 0) ^
			(!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_src,&f->fw_smsk,&f->fw_src)))
			continue;

		/* If dest-addr doesn't match, not this rule. */
		if (((f->fw_flg & IPV6_FW_F_INVDST) != 0) ^
			(!IN6_ARE_ADDR_MASKEQUAL(&ip6->ip6_dst,&f->fw_dmsk,&f->fw_dst)))
			continue;

#undef IN6_ARE_ADDR_MASKEQUAL
		/* Interface check */
		if ((f->fw_flg & IF6_FW_F_VIAHACK) == IF6_FW_F_VIAHACK) {
			struct ifnet *const iface = oif ? oif : rif;

			/* Backwards compatibility hack for "via" */
			if (!iface || !iface_match(iface,
			    &f->fw_in_if, f->fw_flg & IPV6_FW_F_OIFNAME))
				continue;
		} else {
			/* Check receive interface */
			if ((f->fw_flg & IPV6_FW_F_IIFACE)
			    && (!rif || !iface_match(rif,
			      &f->fw_in_if, f->fw_flg & IPV6_FW_F_IIFNAME)))
				continue;
			/* Check outgoing interface */
			if ((f->fw_flg & IPV6_FW_F_OIFACE)
			    && (!oif || !iface_match(oif,
			      &f->fw_out_if, f->fw_flg & IPV6_FW_F_OIFNAME)))
				continue;
		}

		/* Check IP options */
		if (!ip6opts_match(&ip6, f, m, &off, &nxt, &offset))
			continue;

		/* Fragments */
		if ((f->fw_flg & IPV6_FW_F_FRAG) && !offset)
			continue;

		/* Check protocol; if wildcard, match */
		if (f->fw_prot == IPPROTO_IPV6)
			goto got_match;

		/* If different, don't match */
		if (nxt != f->fw_prot)
			continue;

#define PULLUP_TO(len)	do {						\
			    if ((*m)->m_len < (len)			\
				&& (*m = m_pullup(*m, (len))) == 0) {	\
				    goto dropit;			\
			    }						\
			    *pip6 = ip6 = mtod(*m, struct ip6_hdr *);	\
			} while (0)

		/* Protocol specific checks */
		switch (nxt) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp6;

			if (offset == 1) {	/* cf. RFC 1858 */
				PULLUP_TO(off + 4); /* XXX ? */
				goto bogusfrag;
			}
			if (offset != 0) {
				/*
				 * TCP flags and ports aren't available in this
				 * packet -- if this rule specified either one,
				 * we consider the rule a non-match.
				 */
				if (f->fw_nports != 0 ||
				    f->fw_tcpf != f->fw_tcpnf)
					continue;

				break;
			}
			PULLUP_TO(off + 14);
			tcp6 = (struct tcphdr *) ((caddr_t)ip6 + off);
			if (((f->fw_tcpf != f->fw_tcpnf) ||
			   (f->fw_ipflg & IPV6_FW_IF_TCPEST))  &&
			   !tcp6flg_match(tcp6, f))
				continue;
			src_port = ntohs(tcp6->th_sport);
			dst_port = ntohs(tcp6->th_dport);
			goto check_ports;
		    }

		case IPPROTO_UDP:
		    {
			struct udphdr *udp;

			if (offset != 0) {
				/*
				 * Port specification is unavailable -- if this
				 * rule specifies a port, we consider the rule
				 * a non-match.
				 */
				if (f->fw_nports != 0)
					continue;

				break;
			}
			PULLUP_TO(off + 4);
			udp = (struct udphdr *) ((caddr_t)ip6 + off);
			src_port = ntohs(udp->uh_sport);
			dst_port = ntohs(udp->uh_dport);
check_ports:
			if (!port_match6(&f->fw_pts[0],
			    IPV6_FW_GETNSRCP(f), src_port,
			    f->fw_flg & IPV6_FW_F_SRNG))
				continue;
			if (!port_match6(&f->fw_pts[IPV6_FW_GETNSRCP(f)],
			    IPV6_FW_GETNDSTP(f), dst_port,
			    f->fw_flg & IPV6_FW_F_DRNG))
				continue;
			break;
		    }

		case IPPROTO_ICMPV6:
		    {
			struct icmp6_hdr *icmp;

			if (offset != 0)	/* Type isn't valid */
				break;
			PULLUP_TO(off + 2);
			icmp = (struct icmp6_hdr *) ((caddr_t)ip6 + off);
			if (!icmp6type_match(icmp, f))
				continue;
			break;
		    }
#undef PULLUP_TO

bogusfrag:
			if (fw6_verbose)
				ip6fw_report(NULL, ip6, rif, oif, off, nxt);
			goto dropit;
		}

got_match:
#ifndef IP6FW_DIVERT_RESTART
		/* Ignore divert/tee rule if socket port is "ignport" */
		switch (f->fw_flg & IPV6_FW_F_COMMAND) {
		case IPV6_FW_F_DIVERT:
		case IPV6_FW_F_TEE:
			if (f->fw_divert_port == ignport)
				continue;       /* ignore this rule */
			break;
		}

#endif /* IP6FW_DIVERT_RESTART */
		/* Update statistics */
		f->fw_pcnt += 1;
		f->fw_bcnt += ntohs(ip6->ip6_plen);
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
		f->timestamp = time_second;
#else
		f->timestamp = time.tv_sec;
#endif

		/* Log to console if desired */
		if ((f->fw_flg & IPV6_FW_F_PRN) && fw6_verbose)
			ip6fw_report(f, ip6, rif, oif, off, nxt);

		/* Take appropriate action */
		switch (f->fw_flg & IPV6_FW_F_COMMAND) {
		case IPV6_FW_F_ACCEPT:
			return(0);
		case IPV6_FW_F_COUNT:
			continue;
		case IPV6_FW_F_DIVERT:
			return(f->fw_divert_port);
		case IPV6_FW_F_TEE:
			/*
			 * XXX someday tee packet here, but beware that you
			 * can't use m_copym() or m_copypacket() because
			 * the divert input routine modifies the mbuf
			 * (and these routines only increment reference
			 * counts in the case of mbuf clusters), so need
			 * to write custom routine.
			 */
			continue;
		case IPV6_FW_F_SKIPTO:
#ifdef DIAGNOSTIC
			while (chain->chain.le_next
			    && chain->chain.le_next->rule->fw_number
				< f->fw_skipto_rule)
#else
			while (chain->chain.le_next->rule->fw_number
			    < f->fw_skipto_rule)
#endif
				chain = chain->chain.le_next;
			continue;
		}

		/* Deny/reject this packet using this rule */
		rule = f;
		break;
	}

#ifdef DIAGNOSTIC
	/* Rule 65535 should always be there and should always match */
	if (!chain)
		panic("ip6_fw: chain");
#endif

	/*
	 * At this point, we're going to drop the packet.
	 * Send a reject notice if all of the following are true:
	 *
	 * - The packet matched a reject rule
	 * - The packet is not an ICMP packet, or is an ICMP query packet
	 * - The packet is not a multicast or broadcast packet
	 */
	if ((rule->fw_flg & IPV6_FW_F_COMMAND) == IPV6_FW_F_REJECT
	    && (nxt != IPPROTO_ICMPV6 || is_icmp6_query(ip6, off))
	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
	    && !IN6_IS_ADDR_MULTICAST(&ip6->ip6_dst)) {
		switch (rule->fw_reject_code) {
		case IPV6_FW_REJECT_RST:
#if 1	/* not tested */
		  {
			struct tcphdr *const tcp =
				(struct tcphdr *) ((caddr_t)ip6 + off);
			struct {
				struct ip6_hdr ip6;
				struct tcphdr th;
			} ti;
			tcp_seq ack, seq;
			int flags;

			if (offset != 0 || (tcp->th_flags & TH_RST))
				break;

			ti.ip6 = *ip6;
			ti.th = *tcp;
			NTOHL(ti.th.th_seq);
			NTOHL(ti.th.th_ack);
			ti.ip6.ip6_nxt = IPPROTO_TCP;
			if (ti.th.th_flags & TH_ACK) {
				ack = 0;
				seq = ti.th.th_ack;
				flags = TH_RST;
			} else {
				ack = ti.th.th_seq;
				if (((*m)->m_flags & M_PKTHDR) != 0) {
					ack += (*m)->m_pkthdr.len - off
						- (ti.th.th_off << 2);
				} else if (ip6->ip6_plen) {
					ack += ntohs(ip6->ip6_plen) + sizeof(*ip6)
						- off - (ti.th.th_off << 2);
				} else {
					m_freem(*m);
					*m = 0;
					break;
				}
				seq = 0;
				flags = TH_RST|TH_ACK;
			}
			bcopy(&ti, ip6, sizeof(ti));
#ifdef TCP6
			tcp6_respond(NULL, ip6, (struct tcp6hdr *)(ip6 + 1),
				*m, ack, seq, flags);
#elif defined(__NetBSD__)
			tcp_respond(NULL, NULL, *m, (struct tcphdr *)(ip6 + 1),
				ack, seq, flags);
#elif defined(__FreeBSD__) && __FreeBSD__ >= 4
			tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
				*m, ack, seq, flags);
#elif defined(__FreeBSD__) && __FreeBSD__ >= 3
			tcp_respond(NULL, ip6, (struct tcphdr *)(ip6 + 1),
				*m, ack, seq, flags, 1);
#else
			m_freem(*m);
#endif
			*m = NULL;
			break;
		  }
#endif
		default:	/* Send an ICMP unreachable using code */
			if (oif)
				(*m)->m_pkthdr.rcvif = oif;
			icmp6_error(*m, ICMP6_DST_UNREACH,
			    rule->fw_reject_code, 0);
			*m = NULL;
			break;
		}
	}

dropit:
	/*
	 * Finally, drop the packet.
	 */
	if (*m) {
		m_freem(*m);
		*m = NULL;
	}
	return(0);
}
Example #5
0
NTSTATUS
NTAPI
USBSTOR_CSWCompletionRoutine(
    PDEVICE_OBJECT DeviceObject,
    PIRP Irp,
    PVOID Ctx)
{
    PIRP_CONTEXT Context;
    PIO_STACK_LOCATION IoStack;
    PSCSI_REQUEST_BLOCK Request;
    PCDB pCDB;
    PREAD_CAPACITY_DATA_EX CapacityDataEx;
    PREAD_CAPACITY_DATA CapacityData;
    PUFI_CAPACITY_RESPONSE Response;

    NTSTATUS Status;
    PURB Urb;

    //
    // access context
    //
    Context = (PIRP_CONTEXT)Ctx;

    //
    // is there a mdl
    //
    if (Context->TransferBufferMDL)
    {
        //
        // is there an irp associated
        //
        if (Context->Irp)
        {
            //
            // did we allocate the mdl
            //
            if (Context->TransferBufferMDL != Context->Irp->MdlAddress)
            {
                //
                // free mdl
                //
                IoFreeMdl(Context->TransferBufferMDL);
            }
        }
        else
        {
            //
            // free mdl
            //
            IoFreeMdl(Context->TransferBufferMDL);
        }
    }

    DPRINT("USBSTOR_CSWCompletionRoutine Status %x\n", Irp->IoStatus.Status);

    if (!NT_SUCCESS(Irp->IoStatus.Information))
    {
        if (Context->ErrorIndex == 0)
        {
            //
            // increment error index
            //
            Context->ErrorIndex = 1;

            //
            // clear stall and resend cbw
            //
            Status = USBSTOR_QueueWorkItem(Context, Irp);
            ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
            return STATUS_MORE_PROCESSING_REQUIRED;
        }

        //
        // perform reset recovery
        //
        Context->ErrorIndex = 2;
        IoFreeIrp(Irp);
        Status = USBSTOR_QueueWorkItem(Context, NULL);
        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
        return STATUS_MORE_PROCESSING_REQUIRED;
    }

    if (!USBSTOR_IsCSWValid(Context))
    {
        //
        // perform reset recovery
        //
        Context->ErrorIndex = 2;
        IoFreeIrp(Irp);
        Status = USBSTOR_QueueWorkItem(Context, NULL);
        ASSERT(Status == STATUS_MORE_PROCESSING_REQUIRED);
        return STATUS_MORE_PROCESSING_REQUIRED;
    }


    //
    // get current stack location
    //
    IoStack = IoGetCurrentIrpStackLocation(Context->Irp);

    //
    // get request block
    //
    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;
    ASSERT(Request);

    Status = Irp->IoStatus.Status;
    Urb = &Context->Urb;

    //
    // get SCSI command data block
    //
    pCDB = (PCDB)Request->Cdb;
    Request->SrbStatus = SRB_STATUS_SUCCESS;

    //
    // read capacity needs special work
    //
    if (pCDB->AsByte[0] == SCSIOP_READ_CAPACITY)
    {
        //
        // get output buffer
        //
        Response = (PUFI_CAPACITY_RESPONSE)Context->TransferData;

        //
        // store in pdo
        //
        Context->PDODeviceExtension->BlockLength = NTOHL(Response->BlockLength);
        Context->PDODeviceExtension->LastLogicBlockAddress = NTOHL(Response->LastLogicalBlockAddress);

        if (Request->DataTransferLength == sizeof(READ_CAPACITY_DATA_EX))
        {
            //
            // get input buffer
            //
            CapacityDataEx = (PREAD_CAPACITY_DATA_EX)Request->DataBuffer;

            //
            // set result
            //
            CapacityDataEx->BytesPerBlock = Response->BlockLength;
            CapacityDataEx->LogicalBlockAddress.QuadPart = Response->LastLogicalBlockAddress;
            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA_EX);
       }
       else
       {
            //
            // get input buffer
            //
            CapacityData = (PREAD_CAPACITY_DATA)Request->DataBuffer;

            //
            // set result
            //
            CapacityData->BytesPerBlock = Response->BlockLength;
            CapacityData->LogicalBlockAddress = Response->LastLogicalBlockAddress;
            Irp->IoStatus.Information = sizeof(READ_CAPACITY_DATA);
       }

       //
       // free response
       //
       FreeItem(Context->TransferData);
    }

    //
    // free cbw
    //
    FreeItem(Context->cbw);

    //
    // FIXME: check status
    //
    Context->Irp->IoStatus.Status = Irp->IoStatus.Status;
    Context->Irp->IoStatus.Information = Context->TransferDataLength;

    //
    // terminate current request
    //
    USBSTOR_QueueTerminateRequest(Context->PDODeviceExtension->LowerDeviceObject, Context->Irp);

    //
    // complete request
    //
    IoCompleteRequest(Context->Irp, IO_NO_INCREMENT);

    //
    // start next request
    //
    USBSTOR_QueueNextRequest(Context->PDODeviceExtension->LowerDeviceObject);

    //
    // free our allocated irp
    //
    IoFreeIrp(Irp);

    //
    // free context
    //
    FreeItem(Context);

    //
    // done
    //
    return STATUS_MORE_PROCESSING_REQUIRED;
}
NTSTATUS
DispatchRequest (
	IN PPRIMARY_SESSION	PrimarySession
	)
{
	NTSTATUS				status;
	IN PNDFS_REQUEST_HEADER	ndfsRequestHeader;


	ASSERT( NTOHS(PrimarySession->Thread.NdfsRequestHeader.Mid2) < PrimarySession->SessionContext.SessionSlotCount );
	ASSERT( PrimarySession->Thread.SessionSlot[NTOHS(PrimarySession->Thread.NdfsRequestHeader.Mid2)].State == SLOT_WAIT );
	ASSERT( PrimarySession->Thread.ReceiveOverlapped.Request[0].IoStatusBlock.Information == sizeof(NDFS_REQUEST_HEADER) );

	RtlCopyMemory( PrimarySession->Thread.SessionSlot[NTOHS(PrimarySession->Thread.NdfsRequestHeader.Mid2)].RequestMessageBuffer,
				   &PrimarySession->Thread.NdfsRequestHeader,
				   sizeof(NDFS_REQUEST_HEADER) );

	ndfsRequestHeader = (PNDFS_REQUEST_HEADER)PrimarySession->Thread.SessionSlot[NTOHS(PrimarySession->Thread.NdfsRequestHeader.Mid2)].RequestMessageBuffer;
   
    DebugTrace2( 0, Dbg,
				("DispatchRequest: ndfsRequestHeader->Command = %d\n", 
				ndfsRequestHeader->Command) );

	switch (ndfsRequestHeader->Command) {

	case NDFS_COMMAND_LOGOFF: {

		PNDFS_REQUEST_LOGOFF	ndfsRequestLogoff;
		PNDFS_REPLY_HEADER		ndfsReplyHeader;
		PNDFS_REPLY_LOGOFF		ndfsReplyLogoff;
		

		if (PrimarySession->Thread.SessionState != SESSION_TREE_CONNECT) {

			ASSERT(NDASNTFS_BUG);
			status = STATUS_UNSUCCESSFUL;
			break;
		}

		if (!(NTOHS(ndfsRequestHeader->Uid2) == PrimarySession->SessionContext.Uid && 
			 NTOHS(ndfsRequestHeader->Tid2) == PrimarySession->SessionContext.Tid)) {

			ASSERT(NDASNTFS_BUG);
			status = STATUS_UNSUCCESSFUL;
			break;
		}
		
		ASSERT( NTOHL(ndfsRequestHeader->MessageSize4) == sizeof(NDFS_REQUEST_HEADER) + sizeof(NDFS_REQUEST_LOGOFF) );

		ndfsRequestLogoff = (PNDFS_REQUEST_LOGOFF)(ndfsRequestHeader+1);
		
		status = RecvMessage( PrimarySession->ConnectionFileObject,
							  &PrimarySession->RecvNdasFcStatistics,
							  NULL,
							  (UINT8 *)ndfsRequestLogoff,
							  sizeof(NDFS_REQUEST_LOGOFF) );
	
		if (status != STATUS_SUCCESS) {

			ASSERT(NDASNTFS_BUG);
			break;
		}

		ndfsReplyHeader = (PNDFS_REPLY_HEADER)(ndfsRequestLogoff+1);

		RtlCopyMemory( ndfsReplyHeader->Protocol, NDFS_PROTOCOL, sizeof(ndfsReplyHeader->Protocol) );
		ndfsReplyHeader->Status		= NDFS_SUCCESS;
		ndfsReplyHeader->Flags	    = 0;
		ndfsReplyHeader->Uid2		= HTONS(PrimarySession->SessionContext.Uid);
		ndfsReplyHeader->Tid2		= 0;
		ndfsReplyHeader->Mid2		= 0;
		ndfsReplyHeader->MessageSize4 = HTONL((UINT32)(sizeof(NDFS_REPLY_HEADER)+sizeof(NDFS_REPLY_LOGOFF)));

		ndfsReplyLogoff = (PNDFS_REPLY_LOGOFF)(ndfsReplyHeader+1);

		if (NTOHL(ndfsRequestLogoff->SessionKey4) != PrimarySession->SessionContext.SessionKey) {

			ndfsReplyLogoff->Status = NDFS_LOGOFF_UNSUCCESSFUL;
		
		} else {

			ndfsReplyLogoff->Status = NDFS_LOGOFF_SUCCESS;
		}

		status = SendMessage( PrimarySession->ConnectionFileObject,
							  &PrimarySession->SendNdasFcStatistics,
							  NULL,
							  (UINT8 *)ndfsReplyHeader,
							  NTOHL(ndfsReplyHeader->MessageSize4) );

		if (status != STATUS_SUCCESS) {

			break;
		}

		PrimarySession->Thread.SessionState = SESSION_CLOSED;

		status = STATUS_SUCCESS;

		break;
	}

	case NDFS_COMMAND_EXECUTE: {

		UINT16	mid;

		if(PrimarySession->SessionContext.NdfsMinorVersion == NDFS_PROTOCOL_MINOR_0) {

			if (PrimarySession->Thread.SessionState != SESSION_TREE_CONNECT) {

				ASSERT( NDASNTFS_BUG );
				status = STATUS_UNSUCCESSFUL;
				break;
			}
		}

		if (!(NTOHS(ndfsRequestHeader->Uid2) == PrimarySession->SessionContext.Uid && 
			NTOHS(ndfsRequestHeader->Tid2) == PrimarySession->SessionContext.Tid)) {

			ASSERT( NDASNTFS_BUG );
			status = STATUS_UNSUCCESSFUL;

			break;
		}

		mid = NTOHS(ndfsRequestHeader->Mid2);

		PrimarySession->Thread.SessionSlot[mid].RequestMessageBufferLength = sizeof(NDFS_REQUEST_HEADER) + sizeof(NDFS_WINXP_REQUEST_HEADER) + DEFAULT_NDAS_MAX_DATA_SIZE;
		RtlZeroMemory( &PrimarySession->Thread.SessionSlot[mid].RequestMessageBuffer[sizeof(NDFS_REQUEST_HEADER)], 
					   PrimarySession->Thread.SessionSlot[mid].RequestMessageBufferLength - sizeof(NDFS_REQUEST_HEADER) );

		PrimarySession->Thread.SessionSlot[mid].ReplyMessageBufferLength = sizeof(NDFS_REPLY_HEADER) + sizeof(NDFS_WINXP_REPLY_HEADER) + DEFAULT_NDAS_MAX_DATA_SIZE;
		RtlZeroMemory( PrimarySession->Thread.SessionSlot[mid].ReplyMessageBuffer, 
					   PrimarySession->Thread.SessionSlot[mid].ReplyMessageBufferLength );

		ASSERT( NTOHL(ndfsRequestHeader->MessageSize4) >= sizeof(NDFS_REQUEST_HEADER) + sizeof(NDFS_WINXP_REQUEST_HEADER) );

		status = ReceiveNdfsWinxpMessage( PrimarySession, mid );

		if (status != STATUS_SUCCESS)
			break;

		if (PrimarySession->Thread.SessionSlot[mid].State != SLOT_WAIT) {

			break;
		}
	
		PrimarySession->Thread.SessionSlot[mid].State = SLOT_EXECUTING;
		PrimarySession->Thread.IdleSlotCount --;

		if (PrimarySession->SessionContext.SessionSlotCount == 1) {

			ASSERT( mid == 0 );

			DispatchWinXpRequestWorker( PrimarySession, mid );

			PrimarySession->Thread.SessionSlot[mid].State = SLOT_WAIT;
			PrimarySession->Thread.IdleSlotCount ++;

			if (PrimarySession->Thread.SessionSlot[mid].Status == STATUS_SUCCESS) {

				PNDFS_REPLY_HEADER		ndfsReplyHeader;

				ndfsReplyHeader = (PNDFS_REPLY_HEADER)PrimarySession->Thread.SessionSlot[mid].ReplyMessageBuffer;
				
				PrimarySession->Thread.SessionSlot[mid].Status = 
					SendNdfsWinxpMessage( PrimarySession,
										  ndfsReplyHeader,
										  PrimarySession->Thread.SessionSlot[mid].NdfsWinxpReplyHeader,
										  PrimarySession->Thread.SessionSlot[mid].ReplyDataSize,
										  mid );

			}
	
			if (PrimarySession->Thread.SessionSlot[mid].ExtendWinxpRequestMessagePool) {

				ExFreePool( PrimarySession->Thread.SessionSlot[mid].ExtendWinxpRequestMessagePool );	
				PrimarySession->Thread.SessionSlot[mid].ExtendWinxpRequestMessagePool = NULL;
				PrimarySession->Thread.SessionSlot[mid].ExtendWinxpReplyMessagePoolLength = 0;
			}
		
			if (PrimarySession->Thread.SessionSlot[mid].ExtendWinxpReplyMessagePool) {

				ExFreePool( PrimarySession->Thread.SessionSlot[mid].ExtendWinxpReplyMessagePool );	
				PrimarySession->Thread.SessionSlot[mid].ExtendWinxpReplyMessagePool = NULL;
				PrimarySession->Thread.SessionSlot[mid].ExtendWinxpReplyMessagePoolLength = 0;
			}

			NDAS_ASSERT( PrimarySession->Thread.SessionSlot[mid].Status != STATUS_PENDING );
			
			if (PrimarySession->Thread.SessionSlot[mid].Status != STATUS_SUCCESS) {

				SetFlag( PrimarySession->Thread.Flags, PRIMARY_SESSION_THREAD_FLAG_ERROR );
										
				status = PrimarySession->Thread.SessionSlot[mid].Status;
				break;		
			}
				
			status = STATUS_SUCCESS;
			break;
		}

		if (mid == 0)
			ExInitializeWorkItem( &PrimarySession->Thread.SessionSlot[mid].WorkQueueItem,
								  DispatchWinXpRequestWorker0,
								  PrimarySession );
		
		if (mid == 1)
			ExInitializeWorkItem( &PrimarySession->Thread.SessionSlot[mid].WorkQueueItem,
								  DispatchWinXpRequestWorker1,
								  PrimarySession );
		
		if (mid == 2)
			ExInitializeWorkItem( &PrimarySession->Thread.SessionSlot[mid].WorkQueueItem,
								  DispatchWinXpRequestWorker2,
								  PrimarySession );

		
		if (mid == 3)
			ExInitializeWorkItem( &PrimarySession->Thread.SessionSlot[mid].WorkQueueItem,
								  DispatchWinXpRequestWorker3,
								  PrimarySession );

		ExQueueWorkItem( &PrimarySession->Thread.SessionSlot[mid].WorkQueueItem, DelayedWorkQueue );	

		status = STATUS_PENDING;
		break;
	}

	default:

		NDAS_ASSERT( FALSE );			
		status = STATUS_UNSUCCESSFUL;
		
		break;
	}

	return status;
}
Example #7
0
/*
 * TCP input routine, follows pages 65-76 of the
 * protocol specification dated September, 1981 very closely.
 */
void
tcp_input(usn_mbuf_t *m, int iphlen)
{
	struct tcpiphdr *ti;
	struct inpcb *inp;
	u_char *optp = NULL;
	int optlen;
	int len, tlen, off;
	struct tcpcb *tp = 0;
	int tiflags;
	struct usn_socket *so = 0;
	int todrop, acked, ourfinisacked;
   int needoutput = 0;
	short ostate;
	struct usn_in_addr laddr;
	int dropsocket = 0;
	int iss = 0;
	u_long tiwin, ts_val, ts_ecr;
	int ts_present = 0;

   (void)needoutput;
	g_tcpstat.tcps_rcvtotal++;
 
	// Get IP and TCP header together in first mbuf.
	// Note: IP leaves IP header in first mbuf.
	ti = mtod(m, struct tcpiphdr *);
	if (iphlen > sizeof (usn_ip_t))
		ip_stripoptions(m, (usn_mbuf_t *)0);
	if (m->mlen < sizeof (struct tcpiphdr)) {
		if ((m = m_pullup(m, sizeof (struct tcpiphdr))) == 0) {
			g_tcpstat.tcps_rcvshort++;
			return;
		}
		ti = mtod(m, struct tcpiphdr *);
	}

#ifdef DUMP_PAYLOAD
   dump_chain(m,"tcp");
#endif

   /*
	 * Checksum extended TCP header and data.
    */
	tlen = ntohs(((usn_ip_t *)ti)->ip_len);
	len = sizeof (usn_ip_t) + tlen;
	ti->ti_next = ti->ti_prev = 0;
	ti->ti_x1 = 0;
	ti->ti_len = (u_short)tlen;
	HTONS(ti->ti_len);
   ti->ti_sum = in_cksum(m, len);
	if (ti->ti_sum) {
		g_tcpstat.tcps_rcvbadsum++;
		goto drop;
	}
   /*
	 * Check that TCP offset makes sense,
	 * pull out TCP options and adjust length. XXX
    */
	off = ti->ti_off << 2;
	if (off < sizeof (struct tcphdr) || off > tlen) {
		g_tcpstat.tcps_rcvbadoff++;
		goto drop;
	}
	tlen -= off;
	ti->ti_len = tlen;
	if (off > sizeof (struct tcphdr)) {
		if (m->mlen < sizeof(usn_ip_t) + off) {
			if ((m = m_pullup(m, sizeof (usn_ip_t) + off)) == 0) {
				g_tcpstat.tcps_rcvshort++;
				return;
			}
			ti = mtod(m, struct tcpiphdr *);
		}
		optlen = off - sizeof (struct tcphdr);
		optp = mtod(m, u_char *) + sizeof (struct tcpiphdr);

      //	Do quick retrieval of timestamp options ("options
      // prediction?"). If timestamp is the only option and it's
      // formatted as recommended in RFC 1323 appendix A, we
      // quickly get the values now and not bother calling
      // tcp_dooptions(), etc.
		if ((optlen == TCPOLEN_TSTAMP_APPA ||
		     (optlen > TCPOLEN_TSTAMP_APPA &&
			optp[TCPOLEN_TSTAMP_APPA] == TCPOPT_EOL)) &&
		     *(u_int *)optp == htonl(TCPOPT_TSTAMP_HDR) &&
		     (ti->ti_flags & TH_SYN) == 0) {
			ts_present = 1;
			ts_val = ntohl(*(u_long *)(optp + 4));
			ts_ecr = ntohl(*(u_long *)(optp + 8));
			optp = NULL;	// we've parsed the options
		}
	}
	tiflags = ti->ti_flags;

	// Convert TCP protocol specific fields to host format.
	NTOHL(ti->ti_seq);
	NTOHL(ti->ti_ack);
	NTOHS(ti->ti_win);
	NTOHS(ti->ti_urp);

	// Locate pcb for segment.
findpcb:
	inp = g_tcp_last_inpcb;
	if (inp->inp_lport != ti->ti_dport ||
	    inp->inp_fport != ti->ti_sport ||
	    inp->inp_faddr.s_addr != ti->ti_src.s_addr ||
	    inp->inp_laddr.s_addr != ti->ti_dst.s_addr) {
		inp = in_pcblookup(&g_tcb, ti->ti_src, ti->ti_sport,
		    ti->ti_dst, ti->ti_dport, INPLOOKUP_WILDCARD);
		if (inp)
			g_tcp_last_inpcb = inp;
		++g_tcpstat.tcps_pcbcachemiss;
	}

	// If the state is CLOSED (i.e., TCB does not exist) then
	// all data in the incoming segment is discarded.
	// If the TCB exists but is in CLOSED state, it is embryonic,
	// but should either do a listen or a connect soon.
	if (inp == 0)
		goto dropwithreset;

	tp = intotcpcb(inp);

   DEBUG("found inp cb, laddr=%x, lport=%d, faddr=%x,"
         " fport=%d, tp_state=%d, tp_flags=%d",
         inp->inp_laddr.s_addr,
         inp->inp_lport,
         inp->inp_faddr.s_addr,
         inp->inp_fport, tp->t_state, tp->t_flags);

	if (tp == 0)
		goto dropwithreset;
	if (tp->t_state == TCPS_CLOSED)
		goto drop;
	
	// Unscale the window into a 32-bit value. 
	if ((tiflags & TH_SYN) == 0)
		tiwin = ti->ti_win << tp->snd_scale;
	else
		tiwin = ti->ti_win;

	so = inp->inp_socket;
   DEBUG("socket info, options=%x", so->so_options);

	if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
		if (so->so_options & SO_DEBUG) {
			ostate = tp->t_state;
			g_tcp_saveti = *ti;
		}
		if (so->so_options & SO_ACCEPTCONN) {
			if ((tiflags & (TH_RST|TH_ACK|TH_SYN)) != TH_SYN) {
				// Note: dropwithreset makes sure we don't
				// send a reset in response to a RST.
				if (tiflags & TH_ACK) {
					g_tcpstat.tcps_badsyn++;
					goto dropwithreset;
				}
            DEBUG("SYN is expected, tiflags=%d", tiflags);
				goto drop;
			}
			so = sonewconn(so, 0);
			if (so == 0) {
            DEBUG("failed to create new connection, tiflags=%d", tiflags);
				goto drop;
         }

			// Mark socket as temporary until we're
			// committed to keeping it.  The code at
			// ``drop'' and ``dropwithreset'' check the
			// flag dropsocket to see if the temporary
			// socket created here should be discarded.
			// We mark the socket as discardable until
			// we're committed to it below in TCPS_LISTEN.
			dropsocket++;
			inp = (struct inpcb *)so->so_pcb;
			inp->inp_laddr = ti->ti_dst;
			inp->inp_lport = ti->ti_dport;

         // BSD >= 4.3
			inp->inp_options = ip_srcroute();

			tp = intotcpcb(inp);
			tp->t_state = TCPS_LISTEN;

			// Compute proper scaling value from buffer space
			while (tp->request_r_scale < TCP_MAX_WINSHIFT &&
			   TCP_MAXWIN << tp->request_r_scale < so->so_rcv->sb_hiwat)
				tp->request_r_scale++;
		}
	}

	// Segment received on connection.
	// Reset idle time and keep-alive timer.
	tp->t_idle = 0;
	tp->t_timer[TCPT_KEEP] = g_tcp_keepidle;

	// Process options if not in LISTEN state,
	// else do it below (after getting remote address).
	if (optp && tp->t_state != TCPS_LISTEN)
		tcp_dooptions(tp, optp, optlen, ti,
			&ts_present, &ts_val, &ts_ecr);

	// Header prediction: check for the two common cases
	// of a uni-directional data xfer.  If the packet has
	// no control flags, is in-sequence, the window didn't
	// change and we're not retransmitting, it's a
	// candidate.  If the length is zero and the ack moved
	// forward, we're the sender side of the xfer.  Just
	// free the data acked & wake any higher level process
	// that was blocked waiting for space.  If the length
	// is non-zero and the ack didn't move, we're the
	// receiver side.  If we're getting packets in-order
	// (the reassembly queue is empty), add the data to
	// the socket buffer and note that we need a delayed ack.
	if (tp->t_state == TCPS_ESTABLISHED &&
	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
	    (!ts_present || TSTMP_GEQ(ts_val, tp->ts_recent)) &&
	    ti->ti_seq == tp->rcv_nxt &&
	    tiwin && tiwin == tp->snd_wnd &&
	    tp->snd_nxt == tp->snd_max) {
		// If last ACK falls within this segment's sequence numbers,
		// record the timestamp.
      if ( ts_present && TSTMP_GEQ(ts_val, tp->ts_recent) &&
            SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) ){
			tp->ts_recent_age = g_tcp_now;
			tp->ts_recent = ts_val;
		}

		if (ti->ti_len == 0) {
			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
			    tp->snd_cwnd >= tp->snd_wnd) {
				// this is a pure ack for outstanding data.
				++g_tcpstat.tcps_predack;
				if (ts_present)
					tcp_xmit_timer(tp, g_tcp_now-ts_ecr+1);
				else if (tp->t_rtt &&
					    SEQ_GT(ti->ti_ack, tp->t_rtseq))
					tcp_xmit_timer(tp, tp->t_rtt);

				acked = ti->ti_ack - tp->snd_una;
				g_tcpstat.tcps_rcvackpack++;
				g_tcpstat.tcps_rcvackbyte += acked;
            TRACE("drop so_snd buffer, drop_bytes=%d, len=%d", 
                  acked, so->so_snd.sb_cc);

				sbdrop(so->so_snd, acked);
				tp->snd_una = ti->ti_ack;
				usn_free_cmbuf(m);

				// If all outstanding data are acked, stop
				// retransmit timer, otherwise restart timer
				// using current (possibly backed-off) value.
				// If process is waiting for space,
				// wakeup/selwakeup/signal.  If data
				// are ready to send, let tcp_output
				// decide between more output or persist.
				if (tp->snd_una == tp->snd_max)
					tp->t_timer[TCPT_REXMT] = 0;
				else if (tp->t_timer[TCPT_PERSIST] == 0)
					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

	         if (so->so_options & SO_DEBUG)
             	tcp_trace(TA_INPUT, ostate, tp, &g_tcp_saveti, 0);

				//if (so->so_snd->sb_flags & SB_NOTIFY) {
            //   usnet_tcpin_wwakeup(so, USN_TCP_IN, usn_tcpev_sbnotify, 0);
				//	sowwakeup(so);
            //}

            // send buffer is available for app thread. 
            usnet_tcpin_wwakeup(so, USN_TCP_IN, USN_TCPEV_WRITE, 0);

				if (so->so_snd->sb_cc)
					tcp_output(tp);
				return;
			}
		} else if (ti->ti_ack == tp->snd_una &&
		    tp->seg_next == (struct tcpiphdr *)tp &&
		    ti->ti_len <= sbspace(so->so_rcv)) {

			// this is a pure, in-sequence data packet
			// with nothing on the reassembly queue and
			// we have enough buffer space to take it.
			++g_tcpstat.tcps_preddat;
			tp->rcv_nxt += ti->ti_len;
			g_tcpstat.tcps_rcvpack++;
			g_tcpstat.tcps_rcvbyte += ti->ti_len;

			// Drop TCP, IP headers and TCP options then add data
			// to socket buffer.
			m->head += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
			m->mlen -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

         TRACE("add data to rcv buf");
			sbappend(so->so_rcv, m);
			sorwakeup(so);

         // new data is available for app threads.
         usnet_tcpin_rwakeup(so, USN_TCP_IN, USN_TCPEV_READ, m);

	      if (so->so_options & SO_DEBUG) {
            TRACE("tcp trace, so_options=%d", so->so_options);
          	tcp_trace(TA_INPUT, ostate, tp, &g_tcp_saveti, 0);
         }

			tp->t_flags |= TF_DELACK;
			return;
		}
	}

	// Drop TCP, IP headers and TCP options.
	m->head += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	m->mlen -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

	// Calculate amount of space in receive window,
	// and then do TCP input processing.
	// Receive window is amount of space in rcv queue,
	// but not less than advertised window.
   {
	   int win;
	   win = sbspace(so->so_rcv);
	   if (win < 0)
	      win = 0;
  	   tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
	}

	switch (tp->t_state) {
	// If the state is LISTEN then ignore segment if it contains an RST.
	// If the segment contains an ACK then it is bad and send a RST.
	// If it does not contain a SYN then it is not interesting; drop it.
	// Don't bother responding if the destination was a broadcast.
	// Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
	// tp->iss, and send a segment:
	//     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
	// Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
	// Fill in remote peer address fields if not previously specified.
	// Enter SYN_RECEIVED state, and process any other fields of this
	// segment in this state.
	case TCPS_LISTEN: {
		usn_mbuf_t *am;
		struct usn_sockaddr_in *sin;

		if (tiflags & TH_RST)
			goto drop;
		if (tiflags & TH_ACK)
			goto dropwithreset;
		if ((tiflags & TH_SYN) == 0)
			goto drop;

		// RFC1122 4.2.3.10, p. 104: discard bcast/mcast SYN
		// in_broadcast() should never return true on a received
		// packet with M_BCAST not set.

		//if (m->m_flags & (M_BCAST|M_MCAST) ||
		//    IN_MULTICAST(ntohl(ti->ti_dst.s_addr)))
		//	goto drop;

		am = usn_get_mbuf(0, BUF_MSIZE, 0);	// XXX: the size!
		if (am == NULL)
			goto drop;
		am->mlen = sizeof (struct usn_sockaddr_in);
		sin = mtod(am, struct usn_sockaddr_in *);
		sin->sin_family = AF_INET;
		sin->sin_len = sizeof(*sin);
		sin->sin_addr = ti->ti_src;
		sin->sin_port = ti->ti_sport;
		bzero((caddr_t)sin->sin_zero, sizeof(sin->sin_zero));

		laddr = inp->inp_laddr;
		if (inp->inp_laddr.s_addr == USN_INADDR_ANY)
			inp->inp_laddr = ti->ti_dst;

		if (in_pcbconnect(inp, am)) {
			inp->inp_laddr = laddr;
			usn_free_mbuf(am);
			goto drop;
		}
		usn_free_mbuf(am);
		tp->t_template = tcp_template(tp);
		if (tp->t_template == 0) {
			tp = tcp_drop(tp, ENOBUFS);
			dropsocket = 0;		// socket is already gone
			goto drop;
		}
		if (optp)
			tcp_dooptions(tp, optp, optlen, ti,
				&ts_present, &ts_val, &ts_ecr);
		if (iss)
			tp->iss = iss;
		else
			tp->iss = g_tcp_iss;
		g_tcp_iss += TCP_ISSINCR/4;
		tp->irs = ti->ti_seq;
		tcp_sendseqinit(tp);
		tcp_rcvseqinit(tp);
		tp->t_flags |= TF_ACKNOW;
      TRACE("change tcp state to TCPS_SYN_RECEIVED, state=%d, tp_flags=%d",
            tp->t_state, tp->t_flags);
		tp->t_state = TCPS_SYN_RECEIVED;

      // tcp event
      usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_SYN_RECEIVED, 0);

		tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
		dropsocket = 0;		// committed to socket
		g_tcpstat.tcps_accepts++;
		goto trimthenstep6;
	}


	// If the state is SYN_SENT:
	//	if seg contains an ACK, but not for our SYN, drop the input.
	//	if seg contains a RST, then drop the connection.
	//	if seg does not contain SYN, then drop it.
	// Otherwise this is an acceptable SYN segment
	//	initialize tp->rcv_nxt and tp->irs
	//	if seg contains ack then advance tp->snd_una
	//	if SYN has been acked change to ESTABLISHED else SYN_RCVD state
	//	arrange for segment to be acked (eventually)
	//	continue processing rest of data/controls, beginning with URG
	case TCPS_SYN_SENT:
		if ((tiflags & TH_ACK) &&
		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||
		     SEQ_GT(ti->ti_ack, tp->snd_max)))
			goto dropwithreset;
		if (tiflags & TH_RST) {
			if (tiflags & TH_ACK)
				tp = tcp_drop(tp, ECONNREFUSED);
			goto drop;
		}
		if ((tiflags & TH_SYN) == 0)
			goto drop;
		if (tiflags & TH_ACK) {
			tp->snd_una = ti->ti_ack;
			if (SEQ_LT(tp->snd_nxt, tp->snd_una))
				tp->snd_nxt = tp->snd_una;
		   tp->t_timer[TCPT_REXMT] = 0; 
		}
		
		tp->irs = ti->ti_seq;
		tcp_rcvseqinit(tp);
		tp->t_flags |= TF_ACKNOW;
      TRACE("ack now, tp flags=%d", tp->t_flags);

      // XXX: remove second test.
		if (tiflags & TH_ACK /*&& SEQ_GT(tp->snd_una, tp->iss)*/) {
			g_tcpstat.tcps_connects++;
			soisconnected(so);
         TRACE("change tcp state to TCPS_ESTABLISHED,"
               " state=%d, tp_flags=%d", tp->t_state, tp->t_flags);
			tp->t_state = TCPS_ESTABLISHED;

			// Do window scaling on this connection?
			if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
				(TF_RCVD_SCALE|TF_REQ_SCALE)) {
				tp->snd_scale = tp->requested_s_scale;
				tp->rcv_scale = tp->request_r_scale;
			}
			tcp_reass(tp, (struct tcpiphdr *)0, (usn_mbuf_t *)0);

			// if we didn't have to retransmit the SYN,
			// use its rtt as our initial srtt & rtt var.
			if (tp->t_rtt)
				tcp_xmit_timer(tp, tp->t_rtt);
		} else {
         TRACE("change tcp state to TCPS_SYN_RECEIVED, state=%d, tp_flags=%d", 
               tp->t_state, tp->t_flags);
			tp->t_state = TCPS_SYN_RECEIVED;
         // tcp event
         usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_SYN_RECEIVED, 0);
      }

trimthenstep6:

		// Advance ti->ti_seq to correspond to first data byte.
		// If data, trim to stay within window,
		// dropping FIN if necessary.
		ti->ti_seq++;
		if (ti->ti_len > tp->rcv_wnd) {
			todrop = ti->ti_len - tp->rcv_wnd;
			m_adj(m, -todrop);
			ti->ti_len = tp->rcv_wnd;
			tiflags &= ~TH_FIN;
			g_tcpstat.tcps_rcvpackafterwin++;
			g_tcpstat.tcps_rcvbyteafterwin += todrop;
		}
		tp->snd_wl1 = ti->ti_seq - 1;
		tp->rcv_up = ti->ti_seq;
		goto step6;
	}

	// States other than LISTEN or SYN_SENT.
	// First check timestamp, if present.
	// Then check that at least some bytes of segment are within 
	// receive window.  If segment begins before rcv_nxt,
	// drop leading data (and SYN); if nothing left, just ack.
	// 
	// RFC 1323 PAWS: If we have a timestamp reply on this segment
	// and it's less than ts_recent, drop it.
	if (ts_present && (tiflags & TH_RST) == 0 && tp->ts_recent &&
	    TSTMP_LT(ts_val, tp->ts_recent)) {
		// Check to see if ts_recent is over 24 days old.
		if ((int)(g_tcp_now - tp->ts_recent_age) > TCP_PAWS_IDLE) {
			// Invalidate ts_recent.  If this segment updates
			// ts_recent, the age will be reset later and ts_recent
			// will get a valid value.  If it does not, setting
			// ts_recent to zero will at least satisfy the
			// requirement that zero be placed in the timestamp
			// echo reply when ts_recent isn't valid.  The
			// age isn't reset until we get a valid ts_recent
			// because we don't want out-of-order segments to be
			// dropped when ts_recent is old.
			tp->ts_recent = 0;
		} else {
			g_tcpstat.tcps_rcvduppack++;
			g_tcpstat.tcps_rcvdupbyte += ti->ti_len;
			g_tcpstat.tcps_pawsdrop++;
			goto dropafterack;
		}
	}

	todrop = tp->rcv_nxt - ti->ti_seq;
	if (todrop > 0) {
		if (tiflags & TH_SYN) {
			tiflags &= ~TH_SYN;
			ti->ti_seq++;
			if (ti->ti_urp > 1) 
				ti->ti_urp--;
			else
				tiflags &= ~TH_URG;
			todrop--;
		}
      if ( todrop >= ti->ti_len || 
           ( todrop == ti->ti_len && (tiflags & TH_FIN ) == 0 ) ) {
         // Any valid FIN must be to the left of the window.
         // At this point the FIN must be a duplicate or
         // out of sequence; drop it.
         tiflags &= ~TH_FIN;
         // Send an ACK to resynchronize and drop any data
         // But keep on processing for RST or ACK.
         tp->t_flags |= TF_ACKNOW;
         TRACE("send ack now to resync, tp_flags=%d", tp->t_flags);
         todrop = ti->ti_len;
         g_tcpstat.tcps_rcvdupbyte += ti->ti_len;
         g_tcpstat.tcps_rcvduppack++;
      } else {
         g_tcpstat.tcps_rcvpartduppack++;
         g_tcpstat.tcps_rcvpartdupbyte += ti->ti_len;
      }

		m_adj(m, todrop);
		ti->ti_seq += todrop;
		ti->ti_len -= todrop;
		if (ti->ti_urp > todrop)
			ti->ti_urp -= todrop;
		else {
			tiflags &= ~TH_URG;
			ti->ti_urp = 0;
		}
	}

	// If new data are received on a connection after the
	// user processes are gone, then RST the other end.
	if ((so->so_state & USN_NOFDREF) && 
	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
		tp = tcp_close(tp);
		g_tcpstat.tcps_rcvafterclose++;
		goto dropwithreset;
	}


	// If segment ends after window, drop trailing data
	// (and PUSH and FIN); if nothing left, just ACK.
	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
	if (todrop > 0) {
		g_tcpstat.tcps_rcvpackafterwin++;
		if (todrop >= ti->ti_len) {
			g_tcpstat.tcps_rcvbyteafterwin += ti->ti_len;

			// If a new connection request is received
			// while in TIME_WAIT, drop the old connection
			// and start over if the sequence numbers
			// are above the previous ones.
			if (tiflags & TH_SYN &&
			    tp->t_state == TCPS_TIME_WAIT &&
			    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
				iss = tp->snd_nxt + TCP_ISSINCR;
				tp = tcp_close(tp);
				goto findpcb;
			}

			// If window is closed can only take segments at
			// window edge, and have to drop data and PUSH from
			// incoming segments.  Continue processing, but
			// remember to ack.  Otherwise, drop segment
			// and ack.
			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
				tp->t_flags |= TF_ACKNOW;
				g_tcpstat.tcps_rcvwinprobe++;
			} else
				goto dropafterack;
		} else
			g_tcpstat.tcps_rcvbyteafterwin += todrop;
		m_adj(m, -todrop);
		ti->ti_len -= todrop;
		tiflags &= ~(TH_PUSH|TH_FIN);
	}

   // check valid timestamp. Replace code above.
   if (ts_present && TSTMP_GEQ(ts_val, tp->ts_recent) &&
         SEQ_LEQ(ti->ti_seq, tp->last_ack_sent) ) {
		tp->ts_recent_age = g_tcp_now;
		tp->ts_recent = ts_val;
   }

	// If the RST bit is set examine the state:
	//    SYN_RECEIVED STATE:
	//	If passive open, return to LISTEN state.
	//	If active open, inform user that connection was refused.
	//    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
	//	Inform user that connection was reset, and close tcb.
	//    CLOSING, LAST_ACK, TIME_WAIT STATES
	//	Close the tcb.
	if (tiflags&TH_RST) switch (tp->t_state) {

	case TCPS_SYN_RECEIVED:
		so->so_error = ECONNREFUSED;
		goto close;

	case TCPS_ESTABLISHED:
	case TCPS_FIN_WAIT_1:
	case TCPS_FIN_WAIT_2:
	case TCPS_CLOSE_WAIT:
		so->so_error = ECONNRESET;
close:
      DEBUG("change tcp state to TCPS_CLOSED, state=%d", tp->t_state);
		tp->t_state = TCPS_CLOSED;
      // tcp event
      usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_CLOSED, 0);
		g_tcpstat.tcps_drops++;
		tp = tcp_close(tp);
		goto drop;

	case TCPS_CLOSING:
	case TCPS_LAST_ACK:
	case TCPS_TIME_WAIT:
		tp = tcp_close(tp);
		goto drop;
	}

	// If a SYN is in the window, then this is an
	// error and we send an RST and drop the connection.
	if (tiflags & TH_SYN) {
		tp = tcp_drop(tp, ECONNRESET);
		goto dropwithreset;
	}

	// If the ACK bit is off we drop the segment and return.
	if ((tiflags & TH_ACK) == 0)
		goto drop;

	// Ack processing.
	switch (tp->t_state) {

	// In SYN_RECEIVED state if the ack ACKs our SYN then enter
	// ESTABLISHED state and continue processing, otherwise
	// send an RST.
	case TCPS_SYN_RECEIVED:
		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
		    SEQ_GT(ti->ti_ack, tp->snd_max))
			goto dropwithreset;
		g_tcpstat.tcps_connects++;

      DEBUG("change tcp state to TCPS_ESTABLISHED, state=%d", tp->t_state);
		tp->t_state = TCPS_ESTABLISHED;
		soisconnected(so);

		// Do window scaling?
		if ((tp->t_flags & (TF_RCVD_SCALE|TF_REQ_SCALE)) ==
			(TF_RCVD_SCALE|TF_REQ_SCALE)) {
			tp->snd_scale = tp->requested_s_scale;
			tp->rcv_scale = tp->request_r_scale;
		}
		tcp_reass(tp, (struct tcpiphdr *)0, (usn_mbuf_t *)0);
		tp->snd_wl1 = ti->ti_seq - 1;
		// fall into ...

	// In ESTABLISHED state: drop duplicate ACKs; ACK out of range
	// ACKs.  If the ack is in the range
	//	tp->snd_una < ti->ti_ack <= tp->snd_max
	// then advance tp->snd_una to ti->ti_ack and drop
	// data from the retransmission queue.  If this ACK reflects
	// more up to date window information we update our window information.
	case TCPS_ESTABLISHED:
	case TCPS_FIN_WAIT_1:
	case TCPS_FIN_WAIT_2:
	case TCPS_CLOSE_WAIT:
	case TCPS_CLOSING:
	case TCPS_LAST_ACK:
	case TCPS_TIME_WAIT:

		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
				g_tcpstat.tcps_rcvdupack++;
				// If we have outstanding data (other than
				// a window probe), this is a completely
				// duplicate ack (ie, window info didn't
				// change), the ack is the biggest we've
				// seen and we've seen exactly our rexmt
				// threshhold of them, assume a packet
				// has been dropped and retransmit it.
				// Kludge snd_nxt & the congestion
				// window so we send only this one
				// packet.
				//
				// We know we're losing at the current
				// window size so do congestion avoidance
				// (set ssthresh to half the current window
				// and pull our congestion window back to
				// the new ssthresh).
				//
				// Dup acks mean that packets have left the
				// network (they're now cached at the receiver) 
				// so bump cwnd by the amount in the receiver
				// to keep a constant cwnd packets in the
				// network.
				if (tp->t_timer[TCPT_REXMT] == 0 ||
				    ti->ti_ack != tp->snd_una)
					tp->t_dupacks = 0;
				else if (++tp->t_dupacks == g_tcprexmtthresh) {
               // congestion avoidance
					tcp_seq onxt = tp->snd_nxt;
					u_int win =
					    min(tp->snd_wnd, tp->snd_cwnd) / 2 / tp->t_maxseg;

					if (win < 2)
						win = 2;
					tp->snd_ssthresh = win * tp->t_maxseg;
					tp->t_timer[TCPT_REXMT] = 0;
					tp->t_rtt = 0;
					tp->snd_nxt = ti->ti_ack;
					tp->snd_cwnd = tp->t_maxseg;
					tcp_output(tp);
					tp->snd_cwnd = tp->snd_ssthresh +
					       tp->t_maxseg * tp->t_dupacks;
					if (SEQ_GT(onxt, tp->snd_nxt))
						tp->snd_nxt = onxt;
					goto drop;
				} else if (tp->t_dupacks > g_tcprexmtthresh) {
					tp->snd_cwnd += tp->t_maxseg;
					tcp_output(tp);
					goto drop;
				}
			} else
				tp->t_dupacks = 0;
			break;
		}

		// If the congestion window was inflated to account
		// for the other side's cached packets, retract it.
		if (tp->t_dupacks > g_tcprexmtthresh &&
		    tp->snd_cwnd > tp->snd_ssthresh)
			tp->snd_cwnd = tp->snd_ssthresh;
		tp->t_dupacks = 0;
		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
			g_tcpstat.tcps_rcvacktoomuch++;
			goto dropafterack;
		}
		acked = ti->ti_ack - tp->snd_una;
		g_tcpstat.tcps_rcvackpack++;
		g_tcpstat.tcps_rcvackbyte += acked;

		// If we have a timestamp reply, update smoothed
		// round trip time.  If no timestamp is present but
		// transmit timer is running and timed sequence
		// number was acked, update smoothed round trip time.
		// Since we now have an rtt measurement, cancel the
		// timer backoff (cf., Phil Karn's retransmit alg.).
		// Recompute the initial retransmit timer.
		if (ts_present)
			tcp_xmit_timer(tp, g_tcp_now-ts_ecr+1);
		else if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
			tcp_xmit_timer(tp,tp->t_rtt);

		// If all outstanding data is acked, stop retransmit
		// timer and remember to restart (more output or persist).
		// If there is more data to be acked, restart retransmit
		// timer, using current (possibly backed-off) value.
		if (ti->ti_ack == tp->snd_max) {
			tp->t_timer[TCPT_REXMT] = 0;
         DEBUG("change needoutput to 1");
			needoutput = 1;
         tp->t_flags |= TF_NEEDOUTPUT;
		} else if (tp->t_timer[TCPT_PERSIST] == 0)
			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

		// When new data is acked, open the congestion window.
		// If the window gives us less than ssthresh packets
		// in flight, open exponentially (maxseg per packet).
		// Otherwise open linearly: maxseg per window
		// (maxseg * (maxseg / cwnd) per packet).
		{
		   u_int cw = tp->snd_cwnd;
	   	u_int incr = tp->t_maxseg;

	   	if (cw > tp->snd_ssthresh)
	   		incr = incr * incr / cw;
   		tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
		}

		if (acked > so->so_snd->sb_cc) {
			tp->snd_wnd -= so->so_snd->sb_cc;
         DEBUG("drop all so_snd buffer, drop_bytes=%d, acked=%d", 
               so->so_snd->sb_cc, acked);
			sbdrop(so->so_snd, (int)so->so_snd->sb_cc);
			ourfinisacked = 1;
		} else {
         DEBUG("drop so_snd buffer, drop_bytes=%d, len=%d", acked, so->so_snd->sb_cc);
			sbdrop(so->so_snd, acked);
			tp->snd_wnd -= acked;
			ourfinisacked = 0;
		}
		//if (so->so_snd->sb_flags & SB_NOTIFY) {
			sowwakeup(so);
         usnet_tcpin_wwakeup(so, USN_TCP_IN, USN_TCPEV_WRITE, 0);
      //}

		tp->snd_una = ti->ti_ack;
		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
			tp->snd_nxt = tp->snd_una;

		switch (tp->t_state) {

		// In FIN_WAIT_1 STATE in addition to the processing
		// for the ESTABLISHED state if our FIN is now acknowledged
		// then enter FIN_WAIT_2.
		case TCPS_FIN_WAIT_1:
			if (ourfinisacked) {
				// If we can't receive any more
				// data, then closing user can proceed.
				// Starting the timer is contrary to the
				// specification, but if we don't get a FIN
				// we'll hang forever.
				if (so->so_state & USN_CANTRCVMORE) {
					soisdisconnected(so);
					tp->t_timer[TCPT_2MSL] = g_tcp_maxidle;
				}
            DEBUG("change tcp state to TCPS_FIN_WAIT_2, state=%d", tp->t_state);
				tp->t_state = TCPS_FIN_WAIT_2;
            usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_FIN_WAIT2, 0);
			}
			break;

		// In CLOSING STATE in addition to the processing for
		// the ESTABLISHED state if the ACK acknowledges our FIN
		// then enter the TIME-WAIT state, otherwise ignore
		// the segment.
		case TCPS_CLOSING:
			if (ourfinisacked) {
            DEBUG("change tcp state to TCPS_TIME_WAIT, state=%d", tp->t_state);
				tp->t_state = TCPS_TIME_WAIT;
            usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_TIME_WAIT, 0);
				tcp_canceltimers(tp);
				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
				soisdisconnected(so);
			}
			break;
		
		// In LAST_ACK, we may still be waiting for data to drain
		// and/or to be acked, as well as for the ack of our FIN.
		// If our FIN is now acknowledged, delete the TCB,
		// enter the closed state and return.
		case TCPS_LAST_ACK:
			if (ourfinisacked) {
				tp = tcp_close(tp);
				goto drop;
			}
			break;


		// In TIME_WAIT state the only thing that should arrive
		// is a retransmission of the remote FIN.  Acknowledge
		// it and restart the finack timer.
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			goto dropafterack;
		}
	}

step6:

	// Update window information.
	// Don't look at window if no ACK: TAC's send garbage on first SYN.
	if ((tiflags & TH_ACK) &&
	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) || 
        (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
	     (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd) ))  )) {
		// keep track of pure window updates
		if (ti->ti_len == 0 &&
		    tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd)
			g_tcpstat.tcps_rcvwinupd++;
		tp->snd_wnd = tiwin;
		tp->snd_wl1 = ti->ti_seq;
		tp->snd_wl2 = ti->ti_ack;
		if (tp->snd_wnd > tp->max_sndwnd)
			tp->max_sndwnd = tp->snd_wnd;
      DEBUG("change needoutput to 1");
      tp->t_flags |= TF_NEEDOUTPUT;
		needoutput = 1;
	}

	
	// Process segments with URG.
	if ((tiflags & TH_URG) && ti->ti_urp &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {

		// This is a kludge, but if we receive and accept
		// random urgent pointers, we'll crash in
		// soreceive.  It's hard to imagine someone
		// actually wanting to send this much urgent data.
		if (ti->ti_urp + so->so_rcv->sb_cc > g_sb_max) {
			ti->ti_urp = 0;			// XXX
			tiflags &= ~TH_URG;		// XXX
			goto dodata;			// XXX
		}

		// If this segment advances the known urgent pointer,
		// then mark the data stream.  This should not happen
		// in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
		// a FIN has been received from the remote side. 
		// In these states we ignore the URG.
		//
		// According to RFC961 (Assigned Protocols),
		// the urgent pointer points to the last octet
		// of urgent data.  We continue, however,
		// to consider it to indicate the first octet
		// of data past the urgent section as the original 
		// spec states (in one of two places).
		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
			tp->rcv_up = ti->ti_seq + ti->ti_urp;
			so->so_oobmark = so->so_rcv->sb_cc +
			    (tp->rcv_up - tp->rcv_nxt) - 1;
			if (so->so_oobmark == 0)
				so->so_state |= USN_RCVATMARK;
			sohasoutofband(so);
         // send async event to app threads.
         usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPEV_OUTOFBOUND, 0);
			tp->t_oobflags &= ~(TCPOOB_HAVEDATA | TCPOOB_HADDATA);
		}

		// Remove out of band data so doesn't get presented to user.
		// This can happen independent of advancing the URG pointer,
		// but if two URG's are pending at once, some out-of-band
		// data may creep in... ick.
		if (ti->ti_urp <= ti->ti_len
#ifdef SO_OOBINLINE
		     && (so->so_options & SO_OOBINLINE) == 0
#endif
		     )
			tcp_pulloutofband(so, ti, m);
	} else
		// If no out of band data is expected,
		// pull receive urgent pointer along
		// with the receive window.
		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
			tp->rcv_up = tp->rcv_nxt;
dodata:							// XXX
#ifdef DUMP_PAYLOAD
   DEBUG("Handle data");
   dump_chain(m,"tcp");
#endif

	// Process the segment text, merging it into the TCP sequencing queue,
	// and arranging for acknowledgment of receipt if necessary.
	// This process logically involves adjusting tp->rcv_wnd as data
	// is presented to the user (this happens in tcp_usrreq.c,
	// case PRU_RCVD).  If a FIN has already been received on this
	// connection then we just ignore the text.
	if ((ti->ti_len || (tiflags&TH_FIN)) &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
		TCP_REASS(tp, ti, m, so, tiflags);
		// Note the amount of data that peer has sent into
		// our window, in order to estimate the sender's
		// buffer size.
		len = so->so_rcv->sb_hiwat - (tp->rcv_adv - tp->rcv_nxt);
	} else {
		usn_free_cmbuf(m);
		tiflags &= ~TH_FIN;
	}

	// If FIN is received ACK the FIN and let the user know
	// that the connection is closing.
	if (tiflags & TH_FIN) {
		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
			socantrcvmore(so);
			tp->t_flags |= TF_ACKNOW;
         TRACE("ack FIN now, tp flags=%d", tp->t_flags);
			tp->rcv_nxt++;
		}
		switch (tp->t_state) {

		// In SYN_RECEIVED and ESTABLISHED STATES
		// enter the CLOSE_WAIT state.
		case TCPS_SYN_RECEIVED:
		case TCPS_ESTABLISHED:
         TRACE("change tcp state to TCPS_CLOSE_WAIT, state=%d", tp->t_state);
			tp->t_state = TCPS_CLOSE_WAIT;
         soewakeup(so, 0);
         usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_CLOSE_WAIT, 0);
			break;

		// If still in FIN_WAIT_1 STATE FIN has not been acked so
		// enter the CLOSING state.
		case TCPS_FIN_WAIT_1:
         TRACE("change tcp state to TCPS_CLOSING, state=%d", tp->t_state);
			tp->t_state = TCPS_CLOSING;
         usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_CLOSING, 0);
			break;

		// In FIN_WAIT_2 state enter the TIME_WAIT state,
		// starting the time-wait timer, turning off the other 
		// standard timers.
		case TCPS_FIN_WAIT_2:
         TRACE("change tcp state to TCPS_TIME_WAIT, state=%d", tp->t_state);
			tp->t_state = TCPS_TIME_WAIT;
			tcp_canceltimers(tp);
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			soisdisconnected(so);
         usnet_tcpin_ewakeup(so, USN_TCP_IN, USN_TCPST_TIME_WAIT, 0);
			break;

		// In TIME_WAIT state restart the 2 MSL time_wait timer.
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			break;
		}
	}
	if (so->so_options & SO_DEBUG) {
      TRACE("tcp trace, so_options=%d", so->so_options);
		tcp_trace(TA_INPUT, ostate, tp, &g_tcp_saveti, 0);
   }

	// Return any desired output.
	//if (needoutput || (tp->t_flags & TF_ACKNOW)){
	if (tp->t_flags & TF_NEEDOUTPUT || (tp->t_flags & TF_ACKNOW)){
      TRACE("ack now or need to ouput, tp->t_flags=%d", tp->t_flags);
		tcp_output(tp);
   }
	return;

dropafterack:
   TRACE("dropafterack");
	// Generate an ACK dropping incoming segment if it occupies
	// sequence space, where the ACK reflects our state.
	if (tiflags & TH_RST)
		goto drop;
	usn_free_cmbuf(m);
	tp->t_flags |= TF_ACKNOW;
   TRACE("ack now, tp flags=%d", tp->t_flags);
	tcp_output(tp);
	return;

dropwithreset:
   TRACE("dropwithreset");
	// Generate a RST, dropping incoming segment.
	// Make ACK acceptable to originator of segment.
	// Don't bother to respond if destination was broadcast/multicast.
#define USN_MULTICAST(i) (((u_int)(i) & 0xf0000000) == 0xe0000000)
	if ((tiflags & TH_RST) || m->flags & (BUF_BCAST|BUF_MCAST) ||
	    USN_MULTICAST(ntohl(ti->ti_dst.s_addr)))
		goto drop;
   
	if (tiflags & TH_ACK)
		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
	else {
		if (tiflags & TH_SYN)
			ti->ti_len++;
		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
		    TH_RST|TH_ACK);
	}
	// destroy temporarily created socket
	if (dropsocket)
		soabort(so);
	return;

drop:
   TRACE("drop");
	// Drop space held by incoming segment and return.
	if (tp && (tp->t_inpcb->inp_socket->so_options & SO_DEBUG)) {
      TRACE("tcp trace: drop a socket");
		tcp_trace(TA_DROP, ostate, tp, &g_tcp_saveti, 0);
   }
	usn_free_cmbuf(m);
	// destroy temporarily created socket
	if (dropsocket)
		soabort(so);
	return;
}
Example #8
0
int arp_send(in_addr_t ipaddr)
{
    FAR struct net_driver_s *dev;
    struct arp_notify_s notify;
    struct timespec delay;
    struct arp_send_s state;
    net_lock_t save;
    int ret;

    /* First check if destination is a local broadcast. */

    if (ipaddr == INADDR_BROADCAST)
    {
        /* We don't need to send the ARP request */

        return OK;
    }

#ifdef CONFIG_NET_IGMP
    /* Check if the destination address is a multicast address
     *
     * - IPv4: multicast addresses lie in the class D group -- The address range
     *   224.0.0.0 to 239.255.255.255 (224.0.0.0/4)
     *
     * - IPv6 multicast addresses are have the high-order octet of the
     *   addresses=0xff (ff00::/8.)
     */

    if (NTOHL(ipaddr) >= 0xe0000000 && NTOHL(ipaddr) <= 0xefffffff)
    {
        /* We don't need to send the ARP request */

        return OK;
    }
#endif

    /* Get the device that can route this request */

#ifdef CONFIG_NETDEV_MULTINIC
    dev = netdev_findby_ipv4addr(g_ipv4_allzeroaddr, ipaddr);
#else
    dev = netdev_findby_ipv4addr(ipaddr);
#endif
    if (!dev)
    {
        ndbg("ERROR: Unreachable: %08lx\n", (unsigned long)ipaddr);
        ret = -EHOSTUNREACH;
        goto errout;
    }

#ifdef CONFIG_NET_MULTILINK
    /* ARP support is only built if the Ethernet data link is supported.
     * However, if we are supporting multiple network devices and using
     * different link level protocols then we can get here for other
     * link protocols as well.  Continue and send the ARP request only
     * if this device uses the Ethernet data link protocol.
     */

    if (dev->d_lltype != NET_LL_ETHERNET)
    {
        return OK;
    }
#endif

    /* Check if the destination address is on the local network. */

    if (!net_ipv4addr_maskcmp(ipaddr, dev->d_ipaddr, dev->d_netmask))
    {
        in_addr_t dripaddr;

        /* Destination address is not on the local network */

#ifdef CONFIG_NET_ROUTE

        /* We have a routing table.. find the correct router to use in
         * this case (or, as a fall-back, use the device's default router
         * address).  We will use the router IP address instead of the
         * destination address when determining the MAC address.
         */

        netdev_ipv4_router(dev, ipaddr, &dripaddr);
#else
        /* Use the device's default router IP address instead of the
         * destination address when determining the MAC address.
         */

        net_ipv4addr_copy(dripaddr, dev->d_draddr);
#endif
        ipaddr = dripaddr;
    }

    /* Allocate resources to receive a callback.  This and the following
     * initialization is performed with the network lock because we don't
     * want anything to happen until we are ready.
     */

    save = net_lock();
    state.snd_cb = arp_callback_alloc(&g_arp_conn);
    if (!state.snd_cb)
    {
        ndbg("ERROR: Failed to allocate a cllback\n");
        ret = -ENOMEM;
        goto errout_with_lock;
    }

    /* Initialize the state structure. This is done with interrupts
     * disabled
     */

    (void)sem_init(&state.snd_sem, 0, 0); /* Doesn't really fail */
    state.snd_retries   = 0;              /* No retries yet */
    state.snd_ipaddr    = ipaddr;         /* IP address to query */

#ifdef CONFIG_NETDEV_MULTINIC
    /* Remember the routing device name */

    strncpy((FAR char *)state.snd_ifname, (FAR const char *)dev->d_ifname, IFNAMSIZ);
#endif

    /* Now loop, testing if the address mapping is in the ARP table and re-sending the ARP request if it is not.
     */

    ret = -ETIMEDOUT; /* Assume a timeout failure */

    while (state.snd_retries < CONFIG_ARP_SEND_MAXTRIES)
    {
        /* Check if the address mapping is present in the ARP table.  This
         * is only really meaningful on the first time through the loop.
         *
         * NOTE: If the ARP table is large than this could be a performance
         * issue.
         */

        if (arp_find(ipaddr))
        {
            /* We have it!  Break out with success */

            ret = OK;
            break;
        }

        /* Set up the ARP response wait BEFORE we send the ARP request */

        arp_wait_setup(ipaddr, &notify);

        /* Arm/re-arm the callback */

        state.snd_sent      = false;
        state.snd_cb->flags = ARP_POLL;
        state.snd_cb->priv  = (FAR void *)&state;
        state.snd_cb->event = arp_send_interrupt;

        /* Notify the device driver that new TX data is available.
         * NOTES: This is in essence what netdev_ipv4_txnotify() does, which
         * is not possible to call since it expects a in_addr_t as
         * its single argument to lookup the network interface.
         */

        dev->d_txavail(dev);

        /* Wait for the send to complete or an error to occur: NOTES: (1)
         * net_lockedwait will also terminate if a signal is received, (2)
         * interrupts may be disabled! They will be re-enabled while the
         * task sleeps and automatically re-enabled when the task restarts.
         */

        do
        {
            (void)net_lockedwait(&state.snd_sem);
        }
        while (!state.snd_sent);

        /* Now wait for response to the ARP response to be received.  The
         * optimal delay would be the work case round trip time.
         * NOTE: The network is locked.
         */

        delay.tv_sec  = CONFIG_ARP_SEND_DELAYSEC;
        delay.tv_nsec = CONFIG_ARP_SEND_DELAYNSEC;

        ret = arp_wait(&notify, &delay);

        /* arp_wait will return OK if and only if the matching ARP response
         * is received.  Otherwise, it will return -ETIMEDOUT.
         */

        if (ret == OK)
        {
            break;
        }

        /* Increment the retry count */

        state.snd_retries++;
    }

    sem_destroy(&state.snd_sem);
    arp_callback_free(&g_arp_conn, state.snd_cb);
errout_with_lock:
    net_unlock(save);
errout:
    return ret;
}
Example #9
0
static PF_FORWARD_ACTION filter_cb(unsigned char *header, unsigned char *packet, unsigned int len, unsigned int recvindex, unsigned int sendindex, IPAddr nextrecvhop, IPAddr nextsendhop)
{
	PBNOTIFICATION pbn= {0};
	const IP_HEADER *iph=(IP_HEADER*)header;
	const PBIPRANGE *range=NULL;
	const ULONG src=NTOHL(iph->ipSource);
	const ULONG dest=NTOHL(iph->ipDestination);
	USHORT srcport=0;
	USHORT destport=0;
	int opening=1;
	int http = 0;

	// TCP = 6 (http://www.iana.org/assignments/protocol-numbers/)
	if(iph->ipProtocol == IPPROTO_TCP) {
		const TCP_HEADER *tcp=(TCP_HEADER*)packet;
		srcport=NTOHS(tcp->sourcePort);
		destport=NTOHS(tcp->destinationPort);

		opening = (tcp->ack==0);

		// XP needs this as the port which comes back is the same
		// as the port going out and therefore it will be blocked
		if (DestinationPortAllowed(destport) || DestinationPortAllowed(srcport) ||
				SourcePortAllowed(destport) || SourcePortAllowed(srcport)
		   ) {
			http = 1;
		}
	}

	if(!http) {
		KIRQL irq;

		KeAcquireSpinLock(&g_internal->rangeslock, &irq);

		//TODO: test allowed ranges.
		if(g_internal->allowedcount) {
			range = inranges(g_internal->allowedranges, g_internal->allowedcount, src);
			if(!range) range = inranges(g_internal->allowedranges, g_internal->allowedcount, dest);

			if(range) {
				pbn.label = range->label;
				pbn.labelsid = g_internal->allowedlabelsid;
				pbn.action = 1;
			}
		}

		if(!range && g_internal->blockedcount) {
			range=inranges(g_internal->blockedranges, g_internal->blockedcount, src);
			if(!range) range=inranges(g_internal->blockedranges, g_internal->blockedcount, dest);

			if(range) {
				pbn.label = range->label;
				pbn.labelsid = g_internal->blockedlabelsid;
				pbn.action = 0;
			}
		}

		KeReleaseSpinLock(&g_internal->rangeslock, irq);
	}

	if(!range) {
		pbn.action = 2;
	}

	if(range || opening) {
		pbn.protocol=iph->ipProtocol;

		pbn.source.addr4.sin_family = AF_INET;
		pbn.source.addr4.sin_addr.s_addr = iph->ipSource;
		pbn.source.addr4.sin_port = HTONS(srcport);

		pbn.dest.addr4.sin_family = AF_INET;
		pbn.dest.addr4.sin_addr.s_addr = iph->ipDestination;
		pbn.dest.addr4.sin_port = HTONS(destport);

		Notification_Send(&g_internal->queue, &pbn);

		return pbn.action ? PF_FORWARD : PF_DROP;
	}

	return PF_FORWARD;
}
/*===========================================================================
FUNCTION DSMBIT_PACK32_TAIL

DESCRIPTION
  Packs a given value (up to thirty-two bits) into a given dsm item at a
  specified offset.  

DEPENDENCIES
  Data must be packed into the last used byte or the byte immediately
  following it.

  item_ptr can not be NULL.
  
PARAMETERS
  item_ptr  - Pointer to dsm item where packed data should be placed.
  pack_data - Data to be packed
  offset    - Number of bits to skip before placing this data
  len       - Number of bits of pack_data to pack (LSB of the variable)

RETURN VALUE
  Number of bits successfully packed

SIDE_EFFECTS
  A new dsm item may be acquired and linked.

===========================================================================*/
uint16 dsmbiti_pack32_tail
(
  dsm_item_type * item_ptr,
  uint32 pack_data,
  uint16 offset,
  uint16 len,
  dsm_mempool_id_type pool_id,
  const char * file,
  uint32 line
)
{
  uint32 bit_pack_data;          /* data to bit_pack into last byte */

  uint16 byte_offset;            /* Position in terms of bytes of reqd field */

  uint16 num_pushed_bits = 0;    /* stores number of bits pushed */

  uint16 length_packet;          /* stores the length of the passed packet */

  uint16 pushdown_bytes;          /* number of bytes to push down */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
  byte_offset = (uint16) offset / 8;
  offset = offset % 8;

  /* have to be writing bits into the last used byte, or to the byte
     immediately following.
     dsm_length_packet starts counting at 1, byte_offset starts counting at 0,
     thus the apparent off-by-1 discrepancy. */

  DSM_ASSERT (NULL != item_ptr);

  length_packet = (uint16)dsm_length_packet(item_ptr);

  if (offset == 0)
  {
    DSM_ASSERT( length_packet == byte_offset);
  }
  else //offset != 0
  {
    DSM_ASSERT (length_packet == (byte_offset + 1));
  }

  /* if we are packing some bits into the last used byte, go to it directly
     and pack those bits in */
  if (offset != 0)
  {
    while (item_ptr->pkt_ptr != NULL)
    {
      byte_offset -= item_ptr->used;
      item_ptr = item_ptr->pkt_ptr;
    }

    /* move the bits to be packed into the LSB of the temporary variable */
    bit_pack_data = pack_data >> MAX((len + offset - 8), 0);

    /* pack the bits into the last used byte */
    b_packd (bit_pack_data, (item_ptr->data_ptr + byte_offset),
             offset, (word) MIN(8-offset, len));

    /* count the number of pushed bits */
    num_pushed_bits += MIN(8 - offset, len);

    /* decrease the remaining length by the number of bits pushed */
    len = MAX((len + offset - 8), 0);
  }

  /* len is number of bits to pushdown_tail.  It may have changed from
     the top of the function, as a result of packing some bits directly */
  if (len != 0)
  {
    /* shift out the bits that have already been packed */
    pack_data = pack_data << (32 - len);

    /* swap big-endian to little-endian in 16-bit and 32-bit values
       before pushing down */
    pack_data = NTOHL(pack_data);

    pushdown_bytes = 1 + ((len - 1) / 8);

    /* if the pushdown was successful */
    if (dsmi_pushdown_tail(&item_ptr, &pack_data, pushdown_bytes, pool_id, file, line) ==
        pushdown_bytes)
    {
      /* assume all bits were pushed and increment the counter */
      num_pushed_bits += len;
    }
  }

  return num_pushed_bits;
} /* dsmbit_pack32_tail() */
Example #11
0
NTSTATUS
NdasFatCommonFlushBuffers (
    IN PIRP_CONTEXT IrpContext,
    IN PIRP Irp
    )

/*++

Routine Description:

    This is the common routine for flushing a buffer.

Arguments:

    Irp - Supplies the Irp to process

Return Value:

    NTSTATUS - The return status for the operation

--*/

{
    NTSTATUS Status;

    PIO_STACK_LOCATION IrpSp;

    PFILE_OBJECT FileObject;

    TYPE_OF_OPEN TypeOfOpen;
    PVCB Vcb;
    PFCB Fcb;
    PCCB Ccb;

    BOOLEAN VcbAcquired = FALSE;
    BOOLEAN FcbAcquired = FALSE;

    PDIRENT Dirent;
    PBCB DirentBcb = NULL;

	PVOLUME_DEVICE_OBJECT		volDo = CONTAINING_RECORD( IrpContext->Vcb, VOLUME_DEVICE_OBJECT, Vcb );
	BOOLEAN						secondarySessionResourceAcquired = FALSE;

	PSECONDARY_REQUEST			secondaryRequest = NULL;

	PNDFS_REQUEST_HEADER		ndfsRequestHeader;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	PNDFS_WINXP_REPLY_HEADER	ndfsWinxpReplytHeader;

	LARGE_INTEGER				timeOut;


    PAGED_CODE();

    IrpSp = IoGetCurrentIrpStackLocation( Irp );

    DebugTrace(+1, Dbg, "FatCommonFlushBuffers\n", 0);
    DebugTrace( 0, Dbg, "Irp           = %08lx\n", Irp);
    DebugTrace( 0, Dbg, "->FileObject  = %08lx\n", IrpSp->FileObject);

    //
    //  Extract and decode the file object
    //

    FileObject = IrpSp->FileObject;
    TypeOfOpen = FatDecodeFileObject( FileObject, &Vcb, &Fcb, &Ccb );

    //
    //  CcFlushCache is always synchronous, so if we can't wait enqueue
    //  the irp to the Fsp.
    //

    if ( !FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) ) {

        Status = FatFsdPostRequest( IrpContext, Irp );

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status );
        return Status;
    }

    Status = STATUS_SUCCESS;

    try {

		if (!FlagOn(Ccb->NdasFatFlags, ND_FAT_CCB_FLAG_UNOPENED)) {

			do {
			
				secondarySessionResourceAcquired 
					= SecondaryAcquireResourceExclusiveLite( IrpContext, 
															 &volDo->SessionResource, 
															 BooleanFlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );

				if (FlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED) ) {

					PrintIrp( Dbg2, "SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED", NULL, IrpContext->OriginatingIrp );
					NDAS_BUGON( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
					SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );	
				}

				secondaryRequest = AllocateWinxpSecondaryRequest( volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				if (secondaryRequest == NULL) {
	
					NDAS_BUGON( NDAS_BUGON_INSUFFICIENT_RESOURCES );
					Status = STATUS_INSUFFICIENT_RESOURCES;
					break;
				}

				ndfsRequestHeader = &secondaryRequest->NdfsRequestHeader;

				INITIALIZE_NDFS_REQUEST_HEADER( ndfsRequestHeader, NDFS_COMMAND_EXECUTE, volDo->Secondary, IRP_MJ_FLUSH_BUFFERS, 0 );

				ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
				ASSERT( ndfsWinxpRequestHeader == (PNDFS_WINXP_REQUEST_HEADER)secondaryRequest->NdfsRequestData );

				INITIALIZE_NDFS_WINXP_REQUEST_HEADER( ndfsWinxpRequestHeader, 
													  IrpContext->OriginatingIrp, 
													  IoGetCurrentIrpStackLocation(IrpContext->OriginatingIrp), 
													  Ccb->PrimaryFileHandle );
				
				ASSERT( !ExIsResourceAcquiredSharedLite(&IrpContext->Vcb->Resource) );	

				secondaryRequest->RequestType = SECONDARY_REQ_SEND_MESSAGE;
				QueueingSecondaryRequest( volDo->Secondary, secondaryRequest );

				timeOut.QuadPart = -NDASFAT_TIME_OUT;		
				Status = KeWaitForSingleObject( &secondaryRequest->CompleteEvent, Executive, KernelMode, FALSE, &timeOut );
			
				if (Status != STATUS_SUCCESS) {

					ASSERT( NDASFAT_BUG );
					break;
				}

				KeClearEvent (&secondaryRequest->CompleteEvent);

				if (BooleanFlagOn(volDo->Secondary->Thread.Flags, SECONDARY_THREAD_FLAG_REMOTE_DISCONNECTED)) {

					NDAS_BUGON( FlagOn(IrpContext->Flags, IRP_CONTEXT_FLAG_WAIT) );
					SetFlag( IrpContext->NdasFatFlags, NDAS_FAT_IRP_CONTEXT_FLAG_DONT_POST_REQUEST );
					FatRaiseStatus( IrpContext, STATUS_CANT_WAIT );
				}

				if (secondaryRequest->ExecuteStatus == STATUS_SUCCESS) {

					ndfsWinxpReplytHeader = (PNDFS_WINXP_REPLY_HEADER)secondaryRequest->NdfsReplyData;
					ASSERT(NTOHL(ndfsWinxpReplytHeader->Status4) == STATUS_SUCCESS);
				}

				if (secondaryRequest) {

					DereferenceSecondaryRequest( secondaryRequest );
					secondaryRequest = NULL;
				}

				if ( secondarySessionResourceAcquired == TRUE ) {
					
					SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource );		
					secondarySessionResourceAcquired = FALSE;
				}

				break;

			} while(0);
		} 

		Status = STATUS_SUCCESS;

        //
        //  Case on the type of open that we are trying to flush
        //

        switch (TypeOfOpen) {

        case VirtualVolumeFile:
        case EaFile:
        case DirectoryFile:

            DebugTrace(0, Dbg, "Flush that does nothing\n", 0);
            break;

        case UserFileOpen:

            DebugTrace(0, Dbg, "Flush User File Open\n", 0);

            (VOID)FatAcquireExclusiveFcb( IrpContext, Fcb );

            FcbAcquired = TRUE;

            FatVerifyFcb( IrpContext, Fcb );

            //
            //  If the file is cached then flush its cache
            //

            Status = FatFlushFile( IrpContext, Fcb, Flush );

            //
            //  Also update and flush the file's dirent in the parent directory if the
            //  file flush worked.
            //

            if (NT_SUCCESS( Status )) {

                //
                //  Insure that we get the filesize to disk correctly.  This is
                //  benign if it was already good.
                //
                //  (why do we need to do this?)
                //

                SetFlag(FileObject->Flags, FO_FILE_SIZE_CHANGED);

#if 0
                FatUpdateDirentFromFcb( IrpContext, FileObject, Fcb, Ccb );
#endif                
                
                //
                //  Flush the volume file to get any allocation information
                //  updates to disk.
                //

                if (FlagOn(Fcb->FcbState, FCB_STATE_FLUSH_FAT)) {

                    Status = FatFlushFat( IrpContext, Vcb );

                    ClearFlag(Fcb->FcbState, FCB_STATE_FLUSH_FAT);
                }

                //
                //  Set the write through bit so that these modifications
                //  will be completed with the request.
                //

                SetFlag(IrpContext->Flags, IRP_CONTEXT_FLAG_WRITE_THROUGH);
            }

            break;

        case UserDirectoryOpen:

            //
            //  If the user had opened the root directory then we'll
            //  oblige by flushing the volume.
            //

            if (NodeType(Fcb) != FAT_NTC_ROOT_DCB) {

                DebugTrace(0, Dbg, "Flush a directory does nothing\n", 0);
                break;
            }

        case UserVolumeOpen:

            DebugTrace(0, Dbg, "Flush User Volume Open, or root dcb\n", 0);

            //
            //  Acquire exclusive access to the Vcb.
            //

            {
                BOOLEAN Finished;
                Finished = FatAcquireExclusiveVcb( IrpContext, Vcb );
                ASSERT( Finished );
            }

            VcbAcquired = TRUE;

            //
            //  Mark the volume clean and then flush the volume file,
            //  and then all directories
            //

            Status = FatFlushVolume( IrpContext, Vcb, Flush );

            //
            //  If the volume was dirty, do the processing that the delayed
            //  callback would have done.
            //

            if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY)) {

                //
                //  Cancel any pending clean volumes.
                //

                (VOID)KeCancelTimer( &Vcb->CleanVolumeTimer );
                (VOID)KeRemoveQueueDpc( &Vcb->CleanVolumeDpc );

                //
                //  The volume is now clean, note it.
                //

                if (!FlagOn(Vcb->VcbState, VCB_STATE_FLAG_MOUNTED_DIRTY)) {

                    FatMarkVolume( IrpContext, Vcb, VolumeClean );
                    ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_VOLUME_DIRTY );
                }

                //
                //  Unlock the volume if it is removable.
                //

                if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_REMOVABLE_MEDIA) &&
                    !FlagOn(Vcb->VcbState, VCB_STATE_FLAG_BOOT_OR_PAGING_FILE)) {

                    FatToggleMediaEjectDisable( IrpContext, Vcb, FALSE );
                }
            }

            break;

        default:

            FatBugCheck( TypeOfOpen, 0, 0 );
        }

        FatUnpinBcb( IrpContext, DirentBcb );

        FatUnpinRepinnedBcbs( IrpContext );

    } finally {

        DebugUnwind( FatCommonFlushBuffers );

		if (secondaryRequest)
			DereferenceSecondaryRequest( secondaryRequest );

		if (secondarySessionResourceAcquired) {

			SecondaryReleaseResourceLite( IrpContext, &volDo->SessionResource );		
		}

        FatUnpinBcb( IrpContext, DirentBcb );

        if (VcbAcquired) { FatReleaseVcb( IrpContext, Vcb ); }

        if (FcbAcquired) { FatReleaseFcb( IrpContext, Fcb ); }

        //
        //  If this is a normal termination then pass the request on
        //  to the target device object.
        //

        if (!AbnormalTermination()) {

            NTSTATUS DriverStatus;
            PIO_STACK_LOCATION NextIrpSp;

            //
            //  Get the next stack location, and copy over the stack location
            //

            NextIrpSp = IoGetNextIrpStackLocation( Irp );

            *NextIrpSp = *IrpSp;

            //
            //  Set up the completion routine
            //

            IoSetCompletionRoutine( Irp,
                                    FatFlushCompletionRoutine,
                                    ULongToPtr( Status ),
                                    TRUE,
                                    TRUE,
                                    TRUE );

            //
            //  Send the request.
            //

            DriverStatus = IoCallDriver(Vcb->TargetDeviceObject, Irp);

            Status = (DriverStatus == STATUS_INVALID_DEVICE_REQUEST) ?
                     Status : DriverStatus;

            //
            //  Free the IrpContext and return to the caller.
            //

            FatCompleteRequest( IrpContext, FatNull, STATUS_SUCCESS );
        }

        DebugTrace(-1, Dbg, "FatCommonFlushBuffers -> %08lx\n", Status);
    }

    return Status;
}
Example #12
0
socket_internal_t *decompress_tcp_packet(ipv6_hdr_t *temp_ipv6_header)
{
    uint8_t *packet_buffer = ((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN;
    uint16_t tcp_hc_header;
    socket_internal_t *current_socket = NULL;
    uint16_t packet_size = 0;

    /* Full header TCP segment */
    if (*(((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN) == 0x01) {
        switch_tcp_packet_byte_order(((tcp_hdr_t *)(((uint8_t *)temp_ipv6_header) +
                                      IPV6_HDR_LEN + 3)));
        current_socket = get_tcp_socket(temp_ipv6_header,
                                        ((tcp_hdr_t *)(((uint8_t *)temp_ipv6_header) +
                                                IPV6_HDR_LEN + 3)));

        if (current_socket != NULL) {
            if (current_socket->socket_values.tcp_control.state == LISTEN) {
                memcpy(&current_socket->socket_values.tcp_control.tcp_context.context_id,
                       ((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN + 1, 2);
                current_socket->socket_values.tcp_control.tcp_context.context_id =
                    NTOHS(current_socket->socket_values.tcp_control.tcp_context.context_id);
            }

            memmove(((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN,
                    (((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN + 3),
                    temp_ipv6_header->length - 3);
            temp_ipv6_header->length -= 3;
            return current_socket;
        }
        else {
            printf("Socket Null!\n");
            /* Found no matching socket for this packet -> Drop it */
            return NULL;
        }
    }
    /* Compressed header TCP segment */
    else {
        /* Temporary TCP Header */
        tcp_hdr_t full_tcp_header;
        memset(&full_tcp_header, 0, sizeof(tcp_hdr_t));

        /* Current context ID */
        uint16_t current_context;
        memcpy(&current_context, (packet_buffer + 2), 2);
        current_context = NTOHS(current_context);

        /* Copy TCP_HC header into local variable
         * (1,0,0,1|SEQ,SEQ,0)(1,0,0,1|0,0,0,0) */
        memcpy(&tcp_hc_header, packet_buffer, 2);
        tcp_hc_header = NTOHS(tcp_hc_header);

        uint8_t header_type = UNDEFINED;

        if (BITSET(tcp_hc_header, 15) && !BITSET(tcp_hc_header, 14) &&
            !BITSET(tcp_hc_header, 13)) {
            header_type = MOSTLY_COMPRESSED_HEADER;
        }
        else if (BITSET(tcp_hc_header, 15) && BITSET(tcp_hc_header, 14) &&
                 !BITSET(tcp_hc_header, 13)) {
            header_type = COMPRESSED_HEADER;
        }

        /* Setting pointer to first tcp_hc field */
        packet_buffer += 4;
        packet_size += 4;

        /* Current socket */
        socket_internal_t *current_socket =
            get_tcp_socket_by_context(temp_ipv6_header, current_context);

        if (current_socket == NULL) {
            printf("Current Socket == NULL!\n");
            return NULL;
        }

        /* Current TCP Context values */
        tcp_hc_context_t *current_tcp_context =
            &current_socket->socket_values.tcp_control.tcp_context;

        /*----------------------------------*/
        /*|     Sequence number handling   |*/
        /*----------------------------------*/
        if (!BITSET(tcp_hc_header, 11) && !BITSET(tcp_hc_header, 10)) {
            /* Seq = (0|0), sequence number didn't change, copy old value */
            memcpy(&full_tcp_header.seq_nr, &current_tcp_context->seq_rcv, 4);
        }
        /* The 24 most significant bits haven't changed from previous packet */
        else if (!BITSET(tcp_hc_header, 11) && BITSET(tcp_hc_header, 10)) {
            /* Seq = (0|1), copy 1 byte of tcp_hc packet and 3 bytes from
             * previous packet */
            full_tcp_header.seq_nr |= *packet_buffer;
            full_tcp_header.seq_nr |= ((current_tcp_context->seq_rcv) &
                                       0xFFFFFF00);
            packet_buffer += 1;
            packet_size += 1;
        }
        /* If the 16 most significant bits haven't changed from previous packet */
        else if (BITSET(tcp_hc_header, 11) && !BITSET(tcp_hc_header, 10)) {
            /* Seq = (1|0), copy 2 bytes of tcp_hc packet and 2 bytes from
             * previous packet */
            full_tcp_header.seq_nr |= NTOHS(*((uint16_t *)packet_buffer));
            full_tcp_header.seq_nr |= ((current_tcp_context->seq_rcv) & 0xFFFF0000);
            packet_buffer += 2;
            packet_size += 2;
        }
        /* Sending uncompressed sequence number */
        else {
            /* Seq = (1|1), copy 4 bytes of tcp_hc packet */
            memcpy(&full_tcp_header.seq_nr, packet_buffer, 4);
            full_tcp_header.seq_nr = NTOHL(full_tcp_header.seq_nr);
            packet_buffer += 4;
            packet_size += 4;
        }

        /*----------------------------------*/
        /*| Acknowledgment number handling |*/
        /*----------------------------------*/
        if (!BITSET(tcp_hc_header, 9) && !BITSET(tcp_hc_header, 8)) {
            /* Ack = (0|0), acknowledgment number didn't change, copy old value */
            memcpy(&full_tcp_header.ack_nr, &current_tcp_context->ack_rcv, 4);
        }
        /* The 24 most significant bits haven't changed from previous packet */
        else if (!BITSET(tcp_hc_header, 9) && BITSET(tcp_hc_header, 8)) {
            /* Ack = (0|1), copy 1 byte of tcp_hc packet and 3 bytes from
             * previous packet */
            full_tcp_header.ack_nr |= *packet_buffer;
            full_tcp_header.ack_nr |= ((current_tcp_context->ack_rcv) & 0xFFFFFF00);
            packet_buffer += 1;
            packet_size += 1;
            SET_TCP_ACK(full_tcp_header.reserved_flags);
        }
        /* If the 16 most significant bits haven't changed from previous packet */
        else if (BITSET(tcp_hc_header, 9) && !BITSET(tcp_hc_header, 8)) {
            /* Ack = (1|0), copy 2 bytes of tcp_hc packet and 2 bytes from
             * previous packet */
            full_tcp_header.ack_nr |= NTOHS(*((uint16_t *)packet_buffer));
            full_tcp_header.ack_nr |= ((current_tcp_context->ack_rcv) & 0xFFFF0000);
            packet_buffer += 2;
            packet_size += 2;
            SET_TCP_ACK(full_tcp_header.reserved_flags);
        }
        /* Sending uncompressed acknowledgment number */
        else {
            /* Ack = (1|1), copy 4 bytes of tcp_hc packet */
            memcpy(&full_tcp_header.ack_nr, packet_buffer, 4);
            full_tcp_header.ack_nr = NTOHL(full_tcp_header.ack_nr);
            packet_buffer += 4;
            packet_size += 4;

            if (header_type == COMPRESSED_HEADER) {
                SET_TCP_ACK(full_tcp_header.reserved_flags);
            }
        }

        /*----------------------------------*/
        /*|         Window handling        |*/
        /*----------------------------------*/
        if (!BITSET(tcp_hc_header, 7) && !BITSET(tcp_hc_header, 6)) {
            /* Wnd = (0|0), copy old value */
            memcpy(&full_tcp_header.window, &current_tcp_context->wnd_rcv, 2);
        }
        /* The 8 most significant bits haven't changed from previous packet */
        else if (!BITSET(tcp_hc_header, 7) && BITSET(tcp_hc_header, 6)) {
            /* Wnd = (0|1), copy 1 byte of tcp_hc packet and 1 byte from
             * previous packet */
            full_tcp_header.window |= *packet_buffer;
            full_tcp_header.window |= ((current_tcp_context->wnd_rcv) & 0xFF00);
            packet_buffer += 1;
            packet_size += 1;
        }
        /* If the 8 less significant bits haven't changed from previous packet */
        else if (BITSET(tcp_hc_header, 7) && !BITSET(tcp_hc_header, 6)) {
            /* Wnd = (1|0), copy 1 byte of tcp_hc packet and 1 byte from previous packet */
            full_tcp_header.window |= ((*((uint16_t *)packet_buffer)) & 0xFF00);
            full_tcp_header.window |= ((current_tcp_context->wnd_rcv) & 0x00FF);
            packet_buffer += 1;
            packet_size += 1;
        }
        /* Sending uncompressed window size */
        else {
            /* Wnd = (1|1), copy 2 bytes of tcp_hc packet */
            memcpy(&full_tcp_header.window, packet_buffer, 2);
            full_tcp_header.window = NTOHS(full_tcp_header.window);
            packet_buffer += 2;
            packet_size += 2;
        }

        /* FIN flag */
        if (BITSET(tcp_hc_header, 3)) {
            /* F = (1) */
            if (IS_TCP_ACK(full_tcp_header.reserved_flags)) {
                SET_TCP_FIN_ACK(full_tcp_header.reserved_flags);
            }
            else {
                SET_TCP_FIN(full_tcp_header.reserved_flags);
            }
        }

        /* Copy checksum into into tcp header */
        memcpy(&full_tcp_header.checksum, packet_buffer, 2);
        full_tcp_header.checksum = NTOHS(full_tcp_header.checksum);
        packet_buffer += 2;
        packet_size += 2;

        /* Copy dest. and src. port into tcp header */
        memcpy(&full_tcp_header.dst_port,
               &current_socket->socket_values.local_address.sin6_port, 2);
        memcpy(&full_tcp_header.src_port,
               &current_socket->socket_values.foreign_address.sin6_port, 2);

        /* Ordinary TCP header length */
        full_tcp_header.data_offset = TCP_HDR_LEN / 4;

        /* Move payload to end of tcp header */
        memmove(((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN + TCP_HDR_LEN,
                packet_buffer, temp_ipv6_header->length - packet_size);

        /* Copy TCP uncompressed header in front of payload */
        memcpy(((uint8_t *)temp_ipv6_header) + IPV6_HDR_LEN, &full_tcp_header,
               TCP_HDR_LEN);

        /* Set IPV6 header length */
        temp_ipv6_header->length = temp_ipv6_header->length - packet_size +
                                   TCP_HDR_LEN;
        return current_socket;
    }
}
Example #13
0
//
// Wait for registration message and forward proper arbiter.
//
VOID
DraidReceptionThreadProc(
	IN PVOID Param
) {
	PDRAID_REMOTE_CLIENT_CONNECTION Connection = Param;
	LARGE_INTEGER Timeout;
	NTSTATUS status;
	DRIX_REGISTER RegMsg;
	DRIX_HEADER Reply = {0};
	PDRAID_ARBITER_INFO Arbiter;
	KIRQL	oldIrql;
	PLIST_ENTRY listEntry;
	BOOLEAN Disconnect = TRUE;
	BOOLEAN MatchFound;
	ULONG		result;
	
	Connection->TdiReceiveContext.Irp = NULL;
	KeInitializeEvent(&Connection->TdiReceiveContext.CompletionEvent, NotificationEvent, FALSE) ;
	
	// Wait for network event or short timeout
	status = LpxTdiRecvWithCompletionEvent(
					Connection->ConnectionFileObject,
					&Connection->TdiReceiveContext,
					(PUCHAR)&RegMsg,
					sizeof(DRIX_REGISTER),
					0,
					NULL,
					NULL
					);
	if(!NT_SUCCESS(status)) {
		KDPrintM(DBG_LURN_INFO, ("LpxTdiRecvWithCompletionEvent returned %d.\n", status));
		goto out;
	}

	Timeout.QuadPart =  - HZ * 5;
	
	status = KeWaitForSingleObject(
		&Connection->TdiReceiveContext.CompletionEvent,
		Executive, KernelMode, 	FALSE, &Timeout);
	
	if (status == STATUS_SUCCESS) {
		UCHAR ResultCode;
		
		//
		// Data received. Check validity and forward channel to arbiter.
		//
		if (Connection->TdiReceiveContext.Result != sizeof(DRIX_REGISTER)) {
			KDPrintM(DBG_LURN_INFO, ("Registration packet size is not %d.\n", sizeof(DRIX_REGISTER)));
			status = STATUS_UNSUCCESSFUL;
			goto out;
		}

		if (NTOHL(RegMsg.Header.Signature) != DRIX_SIGNATURE) {
			KDPrintM(DBG_LURN_INFO, ("DRIX signature mismatch\n"));
			status = STATUS_UNSUCCESSFUL;
			goto out;
		}
		
		if (RegMsg.Header.Command != DRIX_CMD_REGISTER) {
			KDPrintM(DBG_LURN_INFO, ("Inappropriate command %x sent.\n", RegMsg.Header.Command));
			status = STATUS_UNSUCCESSFUL;
			goto out;
		}

		if (RegMsg.Header.ReplyFlag) {
			KDPrintM(DBG_LURN_INFO, ("Reply flag should be cleared\n"));
			status = STATUS_UNSUCCESSFUL;
			goto out;
		}
		if (NTOHS(RegMsg.Header.Length) !=  sizeof(DRIX_REGISTER)) {
			KDPrintM(DBG_LURN_INFO, ("Invalid packet length %d\n", NTOHS(RegMsg.Header.Length)));
			status = STATUS_UNSUCCESSFUL;
			goto out;
		}

		ACQUIRE_SPIN_LOCK(&g_DraidGlobals->ArbiterListSpinlock, &oldIrql);
		MatchFound = FALSE;
		for (listEntry = g_DraidGlobals->ArbiterList.Flink;
			listEntry != &g_DraidGlobals->ArbiterList;
			listEntry = listEntry->Flink) 
		{
			Arbiter = CONTAINING_RECORD (listEntry, DRAID_ARBITER_INFO, AllArbiterList);
			if (RtlCompareMemory(&Arbiter->Rmd.RaidSetId, &RegMsg.RaidSetId, sizeof(GUID)) == sizeof(GUID) &&
				RtlCompareMemory(&Arbiter->Rmd.ConfigSetId, &RegMsg.ConfigSetId, sizeof(GUID)) == sizeof(GUID)
			) {
				if (Arbiter->Status != DRAID_ARBITER_STATUS_TERMINATING) {
					MatchFound = TRUE;
				} else {
					KDPrintM(DBG_LURN_INFO, ("Arbiter is terminating. Reject reception\n"));	
					MatchFound = FALSE;
				}
				break;
			}
		}
		RELEASE_SPIN_LOCK(&g_DraidGlobals->ArbiterListSpinlock, oldIrql);

		if (MatchFound) {
			ResultCode = DRIX_RESULT_SUCCESS;
		} else {
			ResultCode = DRIX_RESULT_RAID_SET_NOT_FOUND;
		}
//reply:
		//
		// Send reply
		//
		Reply.Signature = 	NTOHL(DRIX_SIGNATURE);
		Reply.Command = DRIX_CMD_REGISTER;
		Reply.Length = NTOHS((UINT16)sizeof(DRIX_HEADER));
		Reply.ReplyFlag = 1;
		Reply.Sequence = RegMsg.Header.Sequence;
		Reply.Result = ResultCode;

		Timeout.QuadPart =  HZ * 5;

		KDPrintM(DBG_LURN_INFO, ("DRAID Sending registration reply(result=%x) to remote client\n", ResultCode));
		status = LpxTdiSend(
					Connection->ConnectionFileObject, (PUCHAR)&Reply, sizeof(DRIX_HEADER), 
					0, &Timeout,	NULL, &result	);
		KDPrintM(DBG_LURN_INFO, ("LpxTdiSend status=%x, result=%x.\n", status, result));
		if (status !=STATUS_SUCCESS) {
			Disconnect = TRUE;
			goto out;
		}
		if (MatchFound) {
			status = DraidArbiterAcceptClient(Arbiter, RegMsg.ConnType, Connection);
			if (status == STATUS_SUCCESS) {
				Disconnect = FALSE;
			} else {
				KDPrintM(DBG_LURN_INFO, ("Failed to accept client %x.\n", status));
			}
		}
	} else if (status == STATUS_TIMEOUT) {
		KDPrintM(DBG_LURN_INFO, ("Timeout before registration.\n"));
	}
	
out:
	if (Disconnect) {
		KDPrintM(DBG_LURN_INFO, ("Closing connection to client.\n"));			
		// Close connection.
		LpxTdiDisassociateAddress(Connection->ConnectionFileObject);
		LpxTdiCloseConnection(
					Connection->ConnectionFileHandle, 
					Connection->ConnectionFileObject
					);
		Connection->ConnectionFileHandle = NULL;
		Connection->ConnectionFileObject = NULL;

		ExFreePoolWithTag(Connection, DRAID_REMOTE_CLIENT_CHANNEL_POOL_TAG);
	} else {
		// Arbiter thread will close connection and free channel
	}
	
	KDPrintM(DBG_LURN_INFO, ("Exiting reception thread.\n"));
	// Decrease counter
	InterlockedDecrement(&g_DraidGlobals->ReceptionThreadCount);
}
Example #14
0
static PF_FORWARD_ACTION filter_cb(unsigned char *header, unsigned char *packet, unsigned int len, unsigned int recvindex, unsigned int sendindex, IPAddr nextrecvhop, IPAddr nextsendhop)
{
	PGNOTIFICATION pgn={0};
	const IP_HEADER *iph=(IP_HEADER*)header;
	const PGIPRANGE *range=NULL;
	const ULONG src=NTOHL(iph->ipSource);
	const ULONG dest=NTOHL(iph->ipDestination);
	USHORT srcport=0;
	USHORT destport=0;
	int opening=1;
	int http = 0;
	int forced_log = 0;

	//if the protocol is TCP or UDP
	if(iph->ipProtocol==6 || iph->ipProtocol==17)
	{
		const TCP_HEADER *tcp=(TCP_HEADER*)packet;
		srcport=NTOHS(tcp->sourcePort);
		destport=NTOHS(tcp->destinationPort);

		if(iph->ipProtocol==6)
		{
			opening=(tcp->ack==0);

			if(!g_internal->blockhttp && (srcport==80 || srcport==443 || destport==80 || destport==443))
			{
				http = 1;
			}
		}
	}

	if(!http)
	{
		KIRQL irq;

		KeAcquireSpinLock(&g_internal->rangeslock, &irq);

		//TODO: test allowed ranges.
		// -> beez : this is not working
		if(g_internal->allowedcount) 
		{
			range = inranges(g_internal->allowedranges, g_internal->allowedcount, src);
			if(!range) 
				range = inranges(g_internal->allowedranges, g_internal->allowedcount, dest);

			if(range)
			{
				pgn.label = range->label;
				pgn.labelsid = g_internal->allowedlabelsid;
				pgn.action = 1;
			}
		}

		if(!range && g_internal->blockedcount)
		{
			range=inranges(g_internal->blockedranges, g_internal->blockedcount, src);
			if(!range) 
				range=inranges(g_internal->blockedranges, g_internal->blockedcount, dest);

			if(range)
			{
				pgn.label = range->label;
				pgn.labelsid = g_internal->blockedlabelsid;
				pgn.action = 0;
			}
		}

		KeReleaseSpinLock(&g_internal->rangeslock, irq);
	}
	
	//seems like connection is oppening up. This means no special action
	if(!range)
	{
		pgn.action = 2;
	}

	//we filter only incomming and not already processed trafic for ports and connections
	if( sendindex == INVALID_PF_IF_INDEX && range == NULL && http == 0 )
	{
		unsigned int i;
		for(i=0;i<g_internal->perma_allow_list_length;i++)
			if( src == g_internal->perma_allow_list[ i ] )
				break;
		if( i == g_internal->perma_allow_list_length )
		{
			//he is sending us a TCP or UDP packet and we test if our port is open. 
			//If not he does not know about our open ports then we can ban him since he is scanning us
			if( destport != 0 && g_internal->f_port_open_ports[ destport ] == 0 && g_internal->disable_port_scan_detector == 0)
			{
#ifdef USE_FIXED_LIST
				CheckInsertedAndAddIPForBan( src );
#else
				Addbanned( src );
#endif
				forced_log = 1;
				pgn.action = 20;

			}
			//a new tcp connection. See if he is spamming connections
			else if( opening && g_internal->disable_connection_flood_detector == 0 ) 
			{
				//check if we are already banning this IP
#ifdef USE_FIXED_LIST
				int i;
				for(i=0;i<TEMP_BLOCK_LIST;i++)
					if( g_internal->temp_connection_flood_banns[ i ] == src )
					{
						forced_log = 1;
						pgn.action = 30;
						break;
					}
#else
				if( checkbanned( src ) != 0 )
				{
					forced_log = 1;
					pgn.action = 30;
				}
#endif
				//not yet in banlist then check if we should add it
				if( forced_log == 0 )
				{
					if( src == g_internal->f_cons_last_received_IP )
					{
						g_internal->f_cons_last_received_IP_count++;
						if( g_internal->f_cons_last_received_IP_count >= g_internal->f_cons_last_received_IP_count_limit )
						{
							//yes he is a flooder
#ifdef USE_FIXED_LIST
							g_internal->temp_connection_flood_banns[ g_internal->temp_block_count ] = src;
							g_internal->temp_block_count = (g_internal->temp_block_count + 1) & TEMP_BLOCK_LIST_MASK;
#else
							Addbanned( src );
#endif
							forced_log = 1;
							pgn.action = 30;
						}
					}
					else
					{
						//memorize new IP to see how many times it will consecutively connect
						g_internal->f_cons_last_received_IP = src;
						g_internal->f_cons_last_received_IP_count = 0;
					}
				}
			}
		}
	}

	if( range || opening 
		|| ( forced_log == 1 && IsListEmpty( &g_internal->queue.irp_list ) && g_internal->blockhttp == 0 ) //this is required or on DDOS CPU usage will go to 100%..
		) 
	{
		pgn.protocol=iph->ipProtocol;

		pgn.source.addr4.sin_family = AF_INET;
		pgn.source.addr4.sin_addr.s_addr = iph->ipSource;
		pgn.source.addr4.sin_port = HTONS(srcport);

		pgn.dest.addr4.sin_family = AF_INET;
		pgn.dest.addr4.sin_addr.s_addr = iph->ipDestination;
		pgn.dest.addr4.sin_port = HTONS(destport);

		Notification_Send(&g_internal->queue, &pgn);

		if( pgn.action != 1 && pgn.action != 2 )
			return PF_DROP;
	}

	return PF_FORWARD;
}
Example #15
0
static int nsm_resp_post_recv(struct tlv_extra *extra)
{
	struct nsm_resp_tlv_head *head;
	struct TLV *tlv = extra->tlv;
	struct timePropertiesDS *tp;
	struct PortAddress *paddr;
	struct currentDS *cds;
	struct parentDS *pds;
	unsigned char *ptr;
	uint16_t expected;

	if (tlv->length < sizeof(*head) + sizeof(*extra->foot)
	    - sizeof(head->type) - sizeof(head->length)) {
		return -EBADMSG;
	}
	head = (struct nsm_resp_tlv_head *) tlv;
	paddr = &head->parent_addr;
	NTOHS(paddr->networkProtocol);
	NTOHS(paddr->addressLength);

	switch (paddr->networkProtocol) {
	case TRANS_UDP_IPV4:
		expected = 4;
		break;
	case TRANS_UDP_IPV6:
		expected = 16;
		break;
	case TRANS_IEEE_802_3:
		expected = 6;
		break;
	default:
		return -EBADMSG;
	}
	if (paddr->addressLength != expected) {
		return -EBADMSG;
	}
	if (tlv->length != sizeof(*head) + sizeof(*extra->foot) +
	    paddr->addressLength - sizeof(head->type) - sizeof(head->length)) {
		return -EBADMSG;
	}

	ptr = (unsigned char *) tlv;
	ptr += sizeof(*head) + paddr->addressLength;
	extra->foot = (struct nsm_resp_tlv_foot *) ptr;

	pds = &extra->foot->parent;
	cds = &extra->foot->current;
	tp = &extra->foot->timeprop;

	/*
	 * At this point the alignment only 2 bytes worst case.
	 * So we need to be careful with the 64 bit words.
	 */
	NTOHS(pds->parentPortIdentity.portNumber);
	NTOHS(pds->observedParentOffsetScaledLogVariance);
	NTOHL(pds->observedParentClockPhaseChangeRate);
	NTOHS(pds->grandmasterClockQuality.offsetScaledLogVariance);

	NTOHS(cds->stepsRemoved);
	net2host64_unaligned(&cds->offsetFromMaster);
	net2host64_unaligned(&cds->meanPathDelay);

	NTOHS(tp->currentUtcOffset);

	NTOHL(extra->foot->lastsync.seconds_lsb);
	NTOHS(extra->foot->lastsync.seconds_msb);
	NTOHL(extra->foot->lastsync.nanoseconds);

	return 0;
}
/**
  Changes the state of a network interface from "stopped" to "started".

  @param  This Protocol instance pointer.

  @retval EFI_SUCCESS           The network interface was started.
  @retval EFI_ALREADY_STARTED   The network interface is already in the started state.
  @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
  @retval EFI_DEVICE_ERROR      The command could not be sent to the network interface.
  @retval EFI_UNSUPPORTED       This function is not supported by the network interface.

**/
EFI_STATUS
EmuSnpStart (
  IN EMU_SNP_PROTOCOL  *This
  )
{
  EFI_STATUS         Status;
  EMU_SNP_PRIVATE    *Private;
  struct ifreq       BoundIf;
  struct bpf_program BpfProgram;
  struct bpf_insn    *FilterProgram;
	u_int							 Value;
	u_int  						 ReadBufferSize;
  UINT16             Temp16;
  UINT32             Temp32;

  Private = EMU_SNP_PRIVATE_DATA_FROM_THIS (This);

  switch (Private->Mode->State) {
    case EfiSimpleNetworkStopped:
      break;

    case EfiSimpleNetworkStarted:
    case EfiSimpleNetworkInitialized:
      return EFI_ALREADY_STARTED;
      break;

    default:
      return EFI_DEVICE_ERROR;
      break;
  }

  Status = EFI_SUCCESS;
  if (Private->BpfFd == 0) {
    Status = OpenBpfFileDescriptor (Private, &Private->BpfFd);
    if (EFI_ERROR (Status)) {
      goto DeviceErrorExit;
    }

    //
		// Get the read buffer size.
		//
		if (ioctl (Private->BpfFd, BIOCGBLEN, &ReadBufferSize) < 0) {
			goto DeviceErrorExit;
		}

		//
		// Default value from BIOCGBLEN is usually too small, so use a much larger size, if necessary.
		//
		if (ReadBufferSize < FixedPcdGet32 (PcdNetworkPacketFilterSize)) {
			ReadBufferSize = FixedPcdGet32 (PcdNetworkPacketFilterSize);
			if (ioctl (Private->BpfFd, BIOCSBLEN, &ReadBufferSize) < 0) {
				goto DeviceErrorExit;
			}
		}

		//
    // Associate our interface with this BPF file descriptor.
    //
    AsciiStrCpy (BoundIf.ifr_name, Private->InterfaceName);
    if (ioctl (Private->BpfFd, BIOCSETIF, &BoundIf) < 0) {
      goto DeviceErrorExit;
    }

    //
		// Enable immediate mode.
    //
    Value = 1;
    if (ioctl (Private->BpfFd, BIOCIMMEDIATE, &Value) < 0) {
      goto DeviceErrorExit;
    }

    //
    // Enable non-blocking I/O.
    //
    if (fcntl (Private->BpfFd, F_GETFL, 0) == -1) {
      goto DeviceErrorExit;
    }

    Value |= O_NONBLOCK;

    if (fcntl (Private->BpfFd, F_SETFL, Value) == -1) {
      goto DeviceErrorExit;
    }

    //
    // Disable "header complete" flag.  This means the supplied source MAC address is
    // what goes on the wire.
    //
    Value = 1;
    if (ioctl (Private->BpfFd, BIOCSHDRCMPLT, &Value) < 0) {
      goto DeviceErrorExit;
    }

    //
    // Allocate read buffer.
    //
		Private->ReadBufferSize = ReadBufferSize;
		Private->ReadBuffer = malloc (Private->ReadBufferSize);
    if (Private->ReadBuffer == NULL) {
      goto ErrorExit;
    }

    Private->CurrentReadPointer = Private->EndReadPointer = Private->ReadBuffer;

    //
		// Install our packet filter: successful reads should only produce broadcast or unicast
    // packets directed to our fake MAC address.
    //
    FilterProgram = malloc (sizeof (mFilterInstructionTemplate)) ;
    if ( FilterProgram == NULL ) {
      goto ErrorExit;
    }

    CopyMem (FilterProgram, &mFilterInstructionTemplate, sizeof (mFilterInstructionTemplate));

    //
    // Insert out fake MAC address into the filter.  The data has to be host endian.
    //
    CopyMem (&Temp32, &Private->Mode->CurrentAddress.Addr[0], sizeof (UINT32));
    FilterProgram[1].k = NTOHL (Temp32);
    CopyMem (&Temp16, &Private->Mode->CurrentAddress.Addr[4], sizeof (UINT16));
    FilterProgram[3].k = NTOHS (Temp16);

    BpfProgram.bf_len = sizeof (mFilterInstructionTemplate) / sizeof (struct bpf_insn);
    BpfProgram.bf_insns = FilterProgram;

    if (ioctl (Private->BpfFd, BIOCSETF, &BpfProgram) < 0) {
      goto DeviceErrorExit;
    }

    free (FilterProgram);

    //
    // Enable promiscuous mode.
    //
    if (ioctl (Private->BpfFd, BIOCPROMISC, 0) < 0) {
      goto DeviceErrorExit;
    }


    Private->Mode->State = EfiSimpleNetworkStarted;
  }

  return Status;

DeviceErrorExit:
  Status = EFI_DEVICE_ERROR;
ErrorExit:
  if (Private->ReadBuffer != NULL) {
    free (Private->ReadBuffer);
    Private->ReadBuffer = NULL;
  }
  return Status;
}
static VOID
DispatchWinXpRequestWorker (
	IN  PPRIMARY_SESSION	PrimarySession,
	IN  UINT16				Mid
    )
{
	PNDFS_REQUEST_HEADER		ndfsRequestHeader = (PNDFS_REQUEST_HEADER)PrimarySession->Thread.SessionSlot[Mid].RequestMessageBuffer;
	PNDFS_REPLY_HEADER			ndfsReplyHeader = (PNDFS_REPLY_HEADER)PrimarySession->Thread.SessionSlot[Mid].ReplyMessageBuffer; 
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader = PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpRequestHeader;
	
	UINT32						replyDataSize;

	
	ASSERT(Mid == NTOHS(ndfsRequestHeader->Mid2));
	
    DebugTrace2( 0, Dbg, ("DispatchWinXpRequestWorker: entered PrimarySession = %p, ndfsRequestHeader->Command = %d\n", 
						  PrimarySession, ndfsRequestHeader->Command));

	ASSERT( PrimarySession->Thread.SessionSlot[Mid].State == SLOT_EXECUTING );


	replyDataSize = CaculateReplyDataLength(PrimarySession, ndfsWinxpRequestHeader);

	if (replyDataSize <= (ULONG)(PrimarySession->SessionContext.SecondaryMaxDataSize || 
	    sizeof(PrimarySession->Thread.SessionSlot[Mid].ReplyMessageBuffer) - sizeof(NDFS_REPLY_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER))) {

		if (ndfsRequestHeader->MessageSecurity == 1) {

			if (ndfsWinxpRequestHeader->IrpMajorFunction == IRP_MJ_READ && PrimarySession->SessionContext.RwDataSecurity == 0)
				PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpReplyHeader = (PNDFS_WINXP_REPLY_HEADER)(ndfsReplyHeader+1);
			else
				PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpReplyHeader = (PNDFS_WINXP_REPLY_HEADER)PrimarySession->Thread.SessionSlot[Mid].CryptWinxpMessageBuffer;
		}
		else
			PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpReplyHeader = (PNDFS_WINXP_REPLY_HEADER)(ndfsReplyHeader+1);
	
	} else {

		PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePoolLength = 
			ADD_ALIGN8(sizeof(NDFS_WINXP_REPLY_HEADER) + replyDataSize);
		PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePool = 
			ExAllocatePoolWithTag( NonPagedPool,
								   PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePoolLength,
								   PRIMARY_SESSION_BUFFERE_TAG );

		ASSERT( PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePool );

		if (PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePool == NULL) {
	
			DebugTrace2( 0, Dbg, ("failed to allocate ExtendWinxpReplyMessagePool\n"));
			goto fail_replypoolalloc;
		}

		PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpReplyHeader 
			= (PNDFS_WINXP_REPLY_HEADER)PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePool;
	}
	
    DebugTrace2( 0, Dbg,
				 ("DispatchWinXpRequestWorker: PrimarySession = %p, ndfsRequestHeader->Command = %d\n", 
				  PrimarySession, ndfsRequestHeader->Command) );

	PrimarySession->Thread.SessionSlot[Mid].Status = 
		DispatchWinXpRequest( PrimarySession, 
							  ndfsWinxpRequestHeader,
							  PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpReplyHeader,
							  NTOHL(ndfsRequestHeader->MessageSize4) - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER),
							  &PrimarySession->Thread.SessionSlot[Mid].ReplyDataSize );

    DebugTrace2( 0, Dbg, ("DispatchWinXpRequestWorker: Return PrimarySession = %p, ndfsRequestHeader->Command = %d\n", 
						  PrimarySession, ndfsRequestHeader->Command) );

fail_replypoolalloc:
	PrimarySession->Thread.SessionSlot[Mid].State = SLOT_FINISH;

	KeSetEvent( &PrimarySession->Thread.WorkCompletionEvent, IO_NO_INCREMENT, FALSE );

	return;
}
Example #18
0
//
// //////////////////////////////////////////////////////////////////////
//
//  Tcp Write Routine - called by base code - e.g. TFTP - already locked
//
EFI_STATUS
TcpWrite (
  IN PXE_BASECODE_DEVICE            *Private,
  IN UINT16                         OpFlags,
  IN UINT16                         *UrgentPointer,
  IN UINT32                         *SequenceNumber,
  IN UINT32                         *AckNumber,
  IN UINT16                         *HlenResCode,
  IN UINT16                         *Window,
  IN EFI_IP_ADDRESS                 *DestIpPtr,
  IN EFI_PXE_BASE_CODE_TCP_PORT     *DestPortPtr,
  IN EFI_IP_ADDRESS                 *GatewayIpPtr, OPTIONAL
  IN EFI_IP_ADDRESS                 *SrcIpPtr,
  IN OUT EFI_PXE_BASE_CODE_TCP_PORT *SrcPortPtr,
  IN UINTN                          *HeaderSizePtr,
  IN VOID                           *HeaderPtr,
  IN UINTN                          *BufferSizePtr,
  IN VOID                           *BufferPtr
  )
/*++
Routine description:
  Write buffer to TCP sesion.

Parameters:
  Private := Pointer to PxeBc interface
  OpFlags := 
  UrgentPointer := 
  SequenceNumber := 
  AckNumber := 
  HlenResCode := 
  Window := 
  DestIpPtr := Destination IP address
  DestPortPtr := Destination TCP port
  GatewayIpPtr := Gateway IP address or NULL
  SrcIpPtr := Source IP address
  SrcPortPtr := Source TCP port
  HeaderSizePtr := Size of packet header
  HeaderPtr := Pointer to header buffer
  BufferSizePtr := Size of packet data
  BufferPtr := Pointer to data buffer

Returns:
  EFI_SUCCESS := 
  EFI_INVALID_PARAMETER := 
  EFI_BAD_BUFFER_SIZE := 
  other := 
--*/
{
  EFI_PXE_BASE_CODE_TCP_PORT  DefaultSrcPort;
  UINTN                       TotalLength;
  UINT8                       CodeBits;

  DefaultSrcPort = 23;

  //
  // check parameters
  //
  if (BufferSizePtr == NULL ||
      BufferPtr == NULL ||
      DestIpPtr == NULL ||
      DestPortPtr == NULL ||
      HeaderPtr == NULL ||
      (OpFlags &~(EFI_PXE_BASE_CODE_UDP_OPFLAGS_MAY_FRAGMENT | EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT))
      ) {
    DEBUG (
      (EFI_D_WARN,
      "\nTcpWrite()  Exit #1  %xh (%r)",
      EFI_INVALID_PARAMETER,
      EFI_INVALID_PARAMETER)
      );

    return EFI_INVALID_PARAMETER;
  }
  //
  // Derive header size.
  //
  TotalLength = *BufferSizePtr + sizeof (TCPV4_HEADER);

  if (TotalLength > 0x0000ffff) {
    DEBUG (
      (EFI_D_WARN,
      "\nTcpWrite()  Exit #2  %xh (%r)",
      EFI_BAD_BUFFER_SIZE,
      EFI_BAD_BUFFER_SIZE)
      );

    return EFI_BAD_BUFFER_SIZE;
  }

  if (SrcIpPtr == NULL) {
    SrcIpPtr = &Private->EfiBc.Mode->StationIp;
  }

  if (SrcPortPtr == NULL) {
    SrcPortPtr = &DefaultSrcPort;
    OpFlags |= EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT;
  }

  if (OpFlags & EFI_PXE_BASE_CODE_UDP_OPFLAGS_ANY_SRC_PORT) {
    *SrcPortPtr = Private->RandomPort;

    if (++Private->RandomPort == 0) {
      Private->RandomPort = PXE_RND_PORT_LOW;
    }
  }

#define IpTxBuffer  ((IPV4_BUFFER *) Private->TransmitBufferPtr)
  //
  // build pseudo header and tcp header in transmit buffer
  //
#define Tcpv4Base ((TCPV4_HEADERS *) (IpTxBuffer->u.Data - sizeof (TCPV4_PSEUDO_HEADER)))

  Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.L    = SrcIpPtr->Addr[0];
  Tcpv4Base->Tcpv4PseudoHeader.DestAddr.L   = DestIpPtr->Addr[0];
  Tcpv4Base->Tcpv4PseudoHeader.Zero         = 0;
  Tcpv4Base->Tcpv4PseudoHeader.Protocol     = PROT_TCP;
  Tcpv4Base->Tcpv4PseudoHeader.TotalLength  = HTONS (TotalLength);
  Tcpv4Base->Tcpv4Header.SrcPort            = HTONS (*SrcPortPtr);
  Tcpv4Base->Tcpv4Header.DestPort           = HTONS (*DestPortPtr);
  Tcpv4Base->Tcpv4Header.SeqNumber          = HTONL (*SequenceNumber);
  Tcpv4Base->Tcpv4Header.AckNumber          = HTONL (*AckNumber);
  Tcpv4Base->Tcpv4Header.HlenResCode        = HTONS (*HlenResCode);
  Tcpv4Base->Tcpv4Header.Window             = HTONS (*Window);
  Tcpv4Base->Tcpv4Header.UrgentPointer      = HTONS (*UrgentPointer);
  Tcpv4Base->Tcpv4Header.Checksum           = 0;

  Tcpv4Base->Tcpv4Header.Checksum = IpChecksum2 (
                                      (UINT16 *) Tcpv4Base,
                                      sizeof (TCPV4_HEADER) + sizeof (TCPV4_PSEUDO_HEADER),
                                      (UINT16 *) BufferPtr,
                                      (UINT16) *BufferSizePtr
                                      );

  if (Tcpv4Base->Tcpv4Header.Checksum == 0) {
    //
    // transmit zero checksum as ones complement
    //
    Tcpv4Base->Tcpv4Header.Checksum = 0xffff;
  }

  DEBUG (
    (EFI_D_NET,
    "\nTcpWrite()  DestIP is:  %d.%d.%d.%d SrcIP is:  %d.%d.%d.%d\n",
    Tcpv4Base->Tcpv4PseudoHeader.DestAddr.B[0],
    Tcpv4Base->Tcpv4PseudoHeader.DestAddr.B[1],
    Tcpv4Base->Tcpv4PseudoHeader.DestAddr.B[2],
    Tcpv4Base->Tcpv4PseudoHeader.DestAddr.B[3],
    Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.B[0],
    Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.B[1],
    Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.B[2],
    Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.B[3])
    );

  DEBUG (
    (EFI_D_NET,
    "\nSrcPort=%d, DstPort=%d, SeqNum=%x, AckNum=%x\n",
    NTOHS (Tcpv4Base->Tcpv4Header.SrcPort),
    NTOHS (Tcpv4Base->Tcpv4Header.DestPort),
    NTOHL (Tcpv4Base->Tcpv4Header.SeqNumber),
    NTOHL (Tcpv4Base->Tcpv4Header.AckNumber))
    );

  CodeBits = (UINT8) (NTOHS (Tcpv4Base->Tcpv4Header.HlenResCode) & 0x3f);

  return Ip4Send (
          Private,
          OpFlags,
          PROT_TCP,
          Tcpv4Base->Tcpv4PseudoHeader.SrcAddr.L,
          Tcpv4Base->Tcpv4PseudoHeader.DestAddr.L,
          (GatewayIpPtr) ? GatewayIpPtr->Addr[0] : 0,
          sizeof (TCPV4_HEADER),
          BufferPtr,
          *BufferSizePtr
          );
}
Example #19
0
void
tcp_dooptions( struct tcpcb *tp, u_char *cp, int cnt,
	struct tcpiphdr *ti, int *ts_present,
	u_long *ts_val, u_long *ts_ecr)
{
	u_short mss;
	int opt, optlen;

	for (; cnt > 0; cnt -= optlen, cp += optlen) {
		opt = cp[0];
		if (opt == TCPOPT_EOL)
			break;
		if (opt == TCPOPT_NOP)
			optlen = 1;
		else {
			optlen = cp[1];
			if (optlen <= 0)
				break;
		}
		switch (opt) {

		default:
			continue;

		case TCPOPT_MAXSEG:
			if (optlen != TCPOLEN_MAXSEG)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			bcopy((char *) cp + 2, (char *) &mss, sizeof(mss));
			NTOHS(mss);
			tcp_mss(tp, mss);	// sets t_maxseg
			break;

		case TCPOPT_WINDOW:
			if (optlen != TCPOLEN_WINDOW)
				continue;
			if (!(ti->ti_flags & TH_SYN))
				continue;
			tp->t_flags |= TF_RCVD_SCALE;
			tp->requested_s_scale = min(cp[2], TCP_MAX_WINSHIFT);
			break;

		case TCPOPT_TIMESTAMP:
			if (optlen != TCPOLEN_TIMESTAMP)
				continue;
			*ts_present = 1;
			bcopy((char *)cp + 2, (char *) ts_val, sizeof(*ts_val));
			NTOHL(*ts_val);
			bcopy((char *)cp + 6, (char *) ts_ecr, sizeof(*ts_ecr));
			NTOHL(*ts_ecr);

			// A timestamp received in a SYN makes
			// it ok to send timestamp requests and replies.
			if (ti->ti_flags & TH_SYN) {
				tp->t_flags |= TF_RCVD_TSTMP;
				tp->ts_recent = *ts_val;
				tp->ts_recent_age = g_tcp_now;
			}
			break;
		}
	}
}
Example #20
0
NTSTATUS
ReceiveNtfsWinxpMessage (
	IN  PPRIMARY_SESSION	PrimarySession,
	IN  UINT16				Mid
	)
{
	PNDFS_REQUEST_HEADER		ndfsRequestHeader = (PNDFS_REQUEST_HEADER)PrimarySession->Thread.SessionSlot[Mid].RequestMessageBuffer;
	PNDFS_WINXP_REQUEST_HEADER	ndfsWinxpRequestHeader;
	UINT8							*cryptWinxpRequestMessage;

	NTSTATUS					tdiStatus;
	//int						desResult;


	cryptWinxpRequestMessage = PrimarySession->Thread.SessionSlot[Mid].CryptWinxpMessageBuffer;	

	//
	// If the request is not split, receive the request at a time
	//	and return to the caller.
	//

	if (ndfsRequestHeader->Splitted == 0) {

		ASSERT( NTOHL(ndfsRequestHeader->MessageSize4) <= PrimarySession->Thread.SessionSlot[Mid].RequestMessageBufferLength );

		ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);
	

		//
		// Receive non-encrypted request at a time and return to the caller.
		//

		if (ndfsRequestHeader->MessageSecurity == 0) {

			tdiStatus = RecvMessage( PrimarySession->ConnectionFileObject,
									 &PrimarySession->RecvNdasFcStatistics,
									 NULL,
									 (UINT8 *)ndfsWinxpRequestHeader,
									 NTOHL(ndfsRequestHeader->MessageSize4) - sizeof(NDFS_REQUEST_HEADER) );
	
			PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpRequestHeader = ndfsWinxpRequestHeader;
	
			return tdiStatus;
		}

		ASSERT( FALSE );
#if 0
		//
		//  Receive encrypted WinXP request header
		//	and return to the caller
		//

		ASSERT(ndfsRequestHeader->MessageSecurity == 1);
		
		tdiStatus = RecvMessage(
						PrimarySession->ConnectionFileObject,
						cryptWinxpRequestMessage,
							sizeof(NDFS_WINXP_REQUEST_HEADER),
							NULL
							);
			if(tdiStatus != STATUS_SUCCESS)
			{
			return tdiStatus;
			}

		RtlZeroMemory(&PrimarySession->DesCbcContext, sizeof(PrimarySession->DesCbcContext));
		RtlZeroMemory(PrimarySession->Iv, sizeof(PrimarySession->Iv));
		DES_CBCInit(&PrimarySession->DesCbcContext,
					PrimarySession->NetdiskPartition->NetdiskPartitionInformation.NetdiskInformation.Password,
					PrimarySession->Iv,
					DES_DECRYPT);
		desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext,
								(UINT8 *)ndfsWinxpRequestHeader,
								cryptWinxpRequestMessage,
								sizeof(NDFS_WINXP_REQUEST_HEADER));
		ASSERT(desResult == IDOK);

		//
		//  Receive encrypted WinXP request data
		//

		ASSERT(ndfsRequestHeader->MessageSize >= sizeof(NDFS_REQUEST_HEADER) + sizeof(NDFS_WINXP_REQUEST_HEADER));

		if(ndfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER))
		{
			if(ndfsWinxpRequestHeader->IrpMajorFunction == IRP_MJ_WRITE && ndfsRequestHeader->RwDataSecurity == 0)
			{
				tdiStatus = RecvMessage(
								PrimarySession->ConnectionFileObject,
								(UINT8 *)(ndfsWinxpRequestHeader+1),
								ndfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER),
								NULL
								);
				if(tdiStatus != STATUS_SUCCESS)
				{
					return tdiStatus;
				}
			}
			else
			{
				tdiStatus = RecvMessage(
								PrimarySession->ConnectionFileObject,
								cryptWinxpRequestMessage,
								ndfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER),
								NULL
								);
				if(tdiStatus != STATUS_SUCCESS)
				{
					return tdiStatus;
				}

				desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext, (UINT8 *)(ndfsWinxpRequestHeader+1), cryptWinxpRequestMessage, ndfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER));
				ASSERT(desResult == IDOK);
			}
		}

		PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpRequestHeader = ndfsWinxpRequestHeader;


		//
		//	return to the caller
		//

		return STATUS_SUCCESS;

#endif
	}

	ASSERT( ndfsRequestHeader->Splitted == 1 );

	//
	//	Allocate memory for extended WinXP header
	//

//	if(ndfsRequestHeader->MessageSize > (PrimarySession->RequestMessageBufferLength - sizeof(NDFS_REQUEST_HEADER) - sizeof(NDFS_WINXP_REQUEST_HEADER)))
	{
		ASSERT( PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePool == NULL );
		
		PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePoolLength = 
			NTOHL(ndfsRequestHeader->MessageSize4) - sizeof(NDFS_REQUEST_HEADER);
		PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePool = 
			ExAllocatePoolWithTag( NonPagedPool,
								   PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePoolLength,
								   PRIMARY_SESSION_BUFFERE_TAG );

		ASSERT( PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePool );

		if (PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePool == NULL) {
		
			SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_ERROR,	("ReceiveNtfsWinxpMessage: failed to allocate ExtendWinxpRequestMessagePool\n") );
			return STATUS_INSUFFICIENT_RESOURCES;
		}

		ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpRequestMessagePool);
	}
//	else
//		ndfsWinxpRequestHeader = (PNDFS_WINXP_REQUEST_HEADER)(ndfsRequestHeader+1);

	//
	//  Receive WinXP request header
	//

	if (ndfsRequestHeader->MessageSecurity == 0) {

		tdiStatus = RecvMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->RecvNdasFcStatistics,
								 NULL,
								 (UINT8 *)ndfsWinxpRequestHeader,
								 sizeof(NDFS_WINXP_REQUEST_HEADER) );

		if (tdiStatus != STATUS_SUCCESS) {

			return tdiStatus;
		}
	}

#if 0

	else
	{
		tdiStatus = RecvMessage(
						PrimarySession->ConnectionFileObject,
						cryptWinxpRequestMessage,
						sizeof(NDFS_WINXP_REQUEST_HEADER),
						NULL
						);

		if(tdiStatus != STATUS_SUCCESS)
		{
			return tdiStatus;
		}
		RtlZeroMemory(&PrimarySession->DesCbcContext, sizeof(PrimarySession->DesCbcContext));
		RtlZeroMemory(PrimarySession->Iv, sizeof(PrimarySession->Iv));
		DES_CBCInit(&PrimarySession->DesCbcContext, PrimarySession->NetdiskPartition->NetdiskPartitionInformation.NetdiskInformation.Password, PrimarySession->Iv, DES_DECRYPT);
		desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext, (UINT8 *)ndfsWinxpRequestHeader, cryptWinxpRequestMessage, sizeof(NDFS_WINXP_REQUEST_HEADER));
		ASSERT(desResult == IDOK);
	}

#endif

	//
	//	Receive a pair of NDFS request header and data
	//

	while (1) {

		PNDFS_REQUEST_HEADER	splitNdfsRequestHeader = &PrimarySession->Thread.SessionSlot[Mid].SplitNdfsRequestHeader;

		//
		//	Receive NDFS request
		//

		tdiStatus = RecvMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->RecvNdasFcStatistics,
								 NULL,
								 (UINT8 *)splitNdfsRequestHeader,
								 sizeof(NDFS_REQUEST_HEADER) );

		if (tdiStatus != STATUS_SUCCESS)
			return tdiStatus;

		if (!(NTOHS(ndfsRequestHeader->Uid2) == PrimarySession->SessionContext.Uid &&
			  NTOHS(ndfsRequestHeader->Tid2) == PrimarySession->SessionContext.Tid)) {

			ASSERT( LFS_BUG );
			return STATUS_UNSUCCESSFUL;
		}

		//
		// receive a part of data
		//

		if (ndfsRequestHeader->MessageSecurity == 0) {

			tdiStatus = RecvMessage( PrimarySession->ConnectionFileObject,
									 &PrimarySession->RecvNdasFcStatistics,
									 NULL,
									 (UINT8 *)ndfsWinxpRequestHeader + NTOHL(ndfsRequestHeader->MessageSize4) - NTOHL(splitNdfsRequestHeader->MessageSize4),
									 splitNdfsRequestHeader->Splitted ? 
										PrimarySession->SessionContext.PrimaryMaxDataSize : (NTOHL(splitNdfsRequestHeader->MessageSize4) - sizeof(NDFS_REQUEST_HEADER)) );

			if (tdiStatus != STATUS_SUCCESS)
				return tdiStatus;
		}
#if 0
		else
		{
			tdiStatus = RecvMessage(
							PrimarySession->ConnectionFileObject,
							cryptWinxpRequestMessage,
							splitNdfsRequestHeader->Splitted 
								? PrimarySession->SessionContext.PrimaryMaxDataSize
								: (splitNdfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER)),
							NULL
							);
			if(tdiStatus != STATUS_SUCCESS)
				return tdiStatus;

			desResult = DES_CBCUpdate(
							&PrimarySession->DesCbcContext, 
							(UINT8 *)ndfsWinxpRequestHeader + ndfsRequestHeader->MessageSize - splitNdfsRequestHeader->MessageSize, 
		 					cryptWinxpRequestMessage, 
							splitNdfsRequestHeader->Splitted 
								? PrimarySession->SessionContext.PrimaryMaxDataSize
								: (splitNdfsRequestHeader->MessageSize - sizeof(NDFS_REQUEST_HEADER))
								);
			ASSERT(desResult == IDOK);
		}
#endif
		if (splitNdfsRequestHeader->Splitted)
			continue;

		PrimarySession->Thread.SessionSlot[Mid].NdfsWinxpRequestHeader = ndfsWinxpRequestHeader;

		return STATUS_SUCCESS;
	}
}
Example #21
0
/**
 * Parser + hash function for the IPv6 packet
 */
static uint32_t
decode_ipv6_n_hash(struct ipv6hdr *ipv6h, uint8_t hash_split, uint8_t seed)
{
	TRACE_PKTHASH_FUNC_START();
	uint32_t saddr, daddr;
	uint32_t rc = 0;

	/* Get only the first 4 octets */
	saddr = ipv6h->saddr.in6_u.u6_addr8[0] |
		(ipv6h->saddr.in6_u.u6_addr8[1] << 8) |
		(ipv6h->saddr.in6_u.u6_addr8[2] << 16) |
		(ipv6h->saddr.in6_u.u6_addr8[3] << 24);
	daddr = ipv6h->daddr.in6_u.u6_addr8[0] |
		(ipv6h->daddr.in6_u.u6_addr8[1] << 8) |
		(ipv6h->daddr.in6_u.u6_addr8[2] << 16) |
		(ipv6h->daddr.in6_u.u6_addr8[3] << 24);

	if (hash_split == 2) {
		rc = sym_hash_fn(NTOHL(saddr),
				 NTOHL(daddr),
				 NTOHS(0xFFFD) + seed,
				 NTOHS(0xFFFE) + seed);
	} else {
		struct tcphdr *tcph = NULL;
		struct udphdr *udph = NULL;
		
		switch(NTOHS(ipv6h->nexthdr)) {
		case IPPROTO_TCP:
			tcph = (struct tcphdr *)(ipv6h + 1);
			rc = sym_hash_fn(NTOHL(saddr), 
					 NTOHL(daddr), 
					 NTOHS(tcph->source) + seed, 
					 NTOHS(tcph->dest) + seed);	       
			break;
		case IPPROTO_UDP:
			udph = (struct udphdr *)(ipv6h + 1);
			rc = sym_hash_fn(NTOHL(saddr),
					 NTOHL(daddr),
					 NTOHS(udph->source) + seed,
					 NTOHS(udph->dest) + seed);		
			break;
		case IPPROTO_IPIP:
			/* tunneling */
			rc = decode_ip_n_hash((struct iphdr *)(ipv6h + 1),
					      hash_split, seed);
			break;
		case IPPROTO_IPV6:
			/* tunneling */
			rc = decode_ipv6_n_hash((struct ipv6hdr *)(ipv6h + 1),
						hash_split, seed);
			break;
		case IPPROTO_ICMP:
		case IPPROTO_GRE:
		case IPPROTO_ESP:
		case IPPROTO_PIM:
		case IPPROTO_IGMP:
		default:
			/* 
			 * the hash strength (although weaker but)
			 * should still hold  even with 2 fields 
			 */
			rc = sym_hash_fn(NTOHL(saddr),
					 NTOHL(daddr),
					 NTOHS(0xFFFD) + seed,
					 NTOHS(0xFFFE) + seed);
		}
	}

	TRACE_PKTHASH_FUNC_END();
	return rc;
}
Example #22
0
NTSTATUS
SendNdfsWinxpMessage (
	IN PPRIMARY_SESSION			PrimarySession,
	IN PNDFS_REPLY_HEADER		NdfsReplyHeader, 
	IN PNDFS_WINXP_REPLY_HEADER	NdfsWinxpReplyHeader,
	IN UINT32						ReplyDataSize,
	IN UINT16						Mid
	)
{
	NTSTATUS	tdiStatus;
	UINT32		remaninigDataSize;		



	//
	//	If the replying data is less than max data size for the secondary,
	//	Send header and body at a time and return to the caller
	//

	if (ReplyDataSize <= PrimarySession->SessionContext.SecondaryMaxDataSize) {

		//int desResult;
		UINT8 *cryptWinxpRequestMessage = PrimarySession->Thread.SessionSlot[Mid].CryptWinxpMessageBuffer;

		//
		//	Set up reply NDFS header
		//

		RtlCopyMemory( NdfsReplyHeader->Protocol, NDFS_PROTOCOL, sizeof(NdfsReplyHeader->Protocol) );

		NdfsReplyHeader->Status		= NDFS_SUCCESS;
		NdfsReplyHeader->Flags	    = PrimarySession->SessionContext.Flags;
		NdfsReplyHeader->Uid2		= HTONS(PrimarySession->SessionContext.Uid);
		NdfsReplyHeader->Tid2		= HTONS(PrimarySession->SessionContext.Tid);
		NdfsReplyHeader->Mid2		= HTONS(Mid);
		NdfsReplyHeader->MessageSize4 = sizeof(NDFS_REPLY_HEADER) + 
									   (PrimarySession->SessionContext.MessageSecurity ? 
									    ADD_ALIGN8(sizeof(NDFS_WINXP_REPLY_HEADER) + ReplyDataSize) : (sizeof(NDFS_WINXP_REPLY_HEADER) + ReplyDataSize));

		NdfsReplyHeader->MessageSize4 = HTONL(NdfsReplyHeader->MessageSize4);

		ASSERT( HTONL(NdfsReplyHeader->MessageSize4) <= PrimarySession->Thread.SessionSlot[Mid].ReplyMessageBufferLength );

		tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->SendNdasFcStatistics,
								 NULL,
								 (UINT8 *)NdfsReplyHeader,
								 sizeof(NDFS_REPLY_HEADER) );

		if (tdiStatus != STATUS_SUCCESS) {

			return tdiStatus;
		}
		

		//
		//	If message security is not set,
		//	send a header and body in raw, and return to the caller.
		//

		if (PrimarySession->SessionContext.MessageSecurity == 0) {

			tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
									 &PrimarySession->SendNdasFcStatistics,
									 NULL,
									 (UINT8 *)NdfsWinxpReplyHeader,
									 NTOHL(NdfsReplyHeader->MessageSize4) - sizeof(NDFS_REPLY_HEADER) );

			return tdiStatus;
		}

		ASSERT( FALSE );

#if 0

		if(NdfsWinxpReplyHeader->IrpMajorFunction == IRP_MJ_READ)
				SPY_LOG_PRINT( LFS_DEBUG_PRIMARY_NOISE,
					("DispatchRequest: PrimarySession->SessionContext.RwDataSecurity = %d\n", PrimarySession->SessionContext.RwDataSecurity));

		if(NdfsWinxpReplyHeader->IrpMajorFunction == IRP_MJ_READ && PrimarySession->SessionContext.RwDataSecurity == 0)
			{
			RtlCopyMemory(cryptWinxpRequestMessage, NdfsWinxpReplyHeader, sizeof(NDFS_WINXP_REPLY_HEADER));
			RtlZeroMemory(&PrimarySession->DesCbcContext, sizeof(PrimarySession->DesCbcContext));
			RtlZeroMemory(PrimarySession->Iv, sizeof(PrimarySession->Iv));
			DES_CBCInit(&PrimarySession->DesCbcContext, PrimarySession->NetdiskPartition->NetdiskPartitionInformation.NetdiskInformation.Password, PrimarySession->Iv, DES_ENCRYPT);
			desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext, (UINT8 *)NdfsWinxpReplyHeader, cryptWinxpRequestMessage, sizeof(NDFS_WINXP_REPLY_HEADER));
			ASSERT(desResult == IDOK);

			tdiStatus = SendMessage(
							PrimarySession->ConnectionFileObject,
							(UINT8 *)NdfsWinxpReplyHeader,
							NdfsReplyHeader->MessageSize - sizeof(NDFS_REPLY_HEADER),
							NULL,
							&PrimarySession->Thread.TransportCtx
							);
			}
			else
			{
			RtlZeroMemory(&PrimarySession->DesCbcContext, sizeof(PrimarySession->DesCbcContext));
			RtlZeroMemory(PrimarySession->Iv, sizeof(PrimarySession->Iv));
			DES_CBCInit(&PrimarySession->DesCbcContext, PrimarySession->NetdiskPartition->NetdiskPartitionInformation.NetdiskInformation.Password, PrimarySession->Iv, DES_ENCRYPT);
			desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext, cryptWinxpRequestMessage, (UINT8 *)NdfsWinxpReplyHeader, NdfsReplyHeader->MessageSize-sizeof(NDFS_REPLY_HEADER));
			ASSERT(desResult == IDOK);

			tdiStatus = SendMessage(
							PrimarySession->ConnectionFileObject,
							cryptWinxpRequestMessage,
							NdfsReplyHeader->MessageSize - sizeof(NDFS_REPLY_HEADER),
							NULL,
							&PrimarySession->Thread.TransportCtx
							);
		}

		//
		//	Return to the caller
		//

		return tdiStatus;

#endif

	}


	ASSERT( (UINT8 *)NdfsWinxpReplyHeader == PrimarySession->Thread.SessionSlot[Mid].ExtendWinxpReplyMessagePool );
	ASSERT( ReplyDataSize > PrimarySession->SessionContext.SecondaryMaxDataSize );

	RtlCopyMemory( NdfsReplyHeader->Protocol, NDFS_PROTOCOL, sizeof(NdfsReplyHeader->Protocol) );
	NdfsReplyHeader->Status		= NDFS_SUCCESS;
	NdfsReplyHeader->Flags	    = PrimarySession->SessionContext.Flags;
	NdfsReplyHeader->Splitted	= 1;	// indicate the split.
	NdfsReplyHeader->Uid2		= HTONS(PrimarySession->SessionContext.Uid);
	NdfsReplyHeader->Tid2		= HTONS(PrimarySession->SessionContext.Tid);
	NdfsReplyHeader->Mid2		= 0;
	NdfsReplyHeader->MessageSize4 = sizeof(NDFS_REPLY_HEADER) + 
								   (PrimarySession->SessionContext.MessageSecurity ? 
									ADD_ALIGN8(sizeof(NDFS_WINXP_REPLY_HEADER) + ReplyDataSize) : (sizeof(NDFS_WINXP_REPLY_HEADER) + ReplyDataSize) );

	NdfsReplyHeader->MessageSize4 = HTONL(NdfsReplyHeader->MessageSize4);

	//
	//	Send reply NDFS header
	//

	tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
							 &PrimarySession->SendNdasFcStatistics,
							 NULL,
							 (UINT8 *)NdfsReplyHeader,
							 sizeof(NDFS_REPLY_HEADER) );

	if (tdiStatus != STATUS_SUCCESS) {

		return tdiStatus;
	} 

	//
	//	Send reply WinXp header
	//

#if 0

	if(PrimarySession->SessionContext.MessageSecurity)
	{
		int desResult;
		UINT8 *cryptWinxpRequestMessage = PrimarySession->Thread.SessionSlot[Mid].CryptWinxpMessageBuffer;

		RtlZeroMemory(&PrimarySession->DesCbcContext, sizeof(PrimarySession->DesCbcContext));
		RtlZeroMemory(PrimarySession->Iv, sizeof(PrimarySession->Iv));
		DES_CBCInit(&PrimarySession->DesCbcContext,
					PrimarySession->NetdiskPartition->NetdiskPartitionInformation.NetdiskInformation.Password, 
					PrimarySession->Iv, DES_ENCRYPT);
		desResult = DES_CBCUpdate(&PrimarySession->DesCbcContext,
								cryptWinxpRequestMessage,
								(UINT8 *)NdfsWinxpReplyHeader,
								sizeof(NDFS_WINXP_REPLY_HEADER));
		ASSERT(desResult == IDOK);
	
		tdiStatus = SendMessage(
					PrimarySession->ConnectionFileObject,
					cryptWinxpRequestMessage,
					sizeof(NDFS_WINXP_REPLY_HEADER),
					NULL,
					&PrimarySession->Thread.TransportCtx
					);
	}
	else
#endif
	{

		tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->SendNdasFcStatistics,
								 NULL,
								 (UINT8 *)NdfsWinxpReplyHeader,
								 sizeof(NDFS_WINXP_REPLY_HEADER) );
	} 

	if (tdiStatus != STATUS_SUCCESS) {
	
		return tdiStatus;
	}


	//
	//	Send data body
	//

	remaninigDataSize = ReplyDataSize;

	while(1)
	{

		//
		//	Set up reply NDFS header
		//

		RtlCopyMemory(NdfsReplyHeader->Protocol, NDFS_PROTOCOL, sizeof(NdfsReplyHeader->Protocol));
		NdfsReplyHeader->Status		= NDFS_SUCCESS;
		NdfsReplyHeader->Flags	    = PrimarySession->SessionContext.Flags;
		NdfsReplyHeader->Uid2		= HTONS(PrimarySession->SessionContext.Uid);
		NdfsReplyHeader->Tid2		= HTONS(PrimarySession->SessionContext.Tid);
		NdfsReplyHeader->Mid2		= 0;
		NdfsReplyHeader->MessageSize4 
				= sizeof(NDFS_REPLY_HEADER) 
					+ (PrimarySession->SessionContext.MessageSecurity ?
					ADD_ALIGN8(remaninigDataSize) : remaninigDataSize);

		NdfsReplyHeader->MessageSize4 = HTONL(NdfsReplyHeader->MessageSize4);

		if(remaninigDataSize > PrimarySession->SessionContext.SecondaryMaxDataSize)
			NdfsReplyHeader->Splitted = 1;
		else
			NdfsReplyHeader->Splitted = 0;

		//
		//	Send NDFS reply header
		//

		tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->SendNdasFcStatistics,
								 NULL,
								 (UINT8 *)NdfsReplyHeader,
								 sizeof(NDFS_REPLY_HEADER) );

		if(tdiStatus != STATUS_SUCCESS)
		{
			return tdiStatus;
		}
		//
		//	Send a part of data body
		//

#if 0

		if(PrimarySession->SessionContext.MessageSecurity)
		{
			int desResult;
			UINT8 *cryptNdfsWinxpReplyHeader = PrimarySession->Thread.SessionSlot[Mid].CryptWinxpMessageBuffer;

			desResult = DES_CBCUpdate(
							&PrimarySession->DesCbcContext, 
							cryptNdfsWinxpReplyHeader, 
							(UINT8 *)(NdfsWinxpReplyHeader+1) + (ReplyDataSize - remaninigDataSize), 
							NdfsReplyHeader->Splitted ?
								PrimarySession->SessionContext.SecondaryMaxDataSize :
								(NdfsReplyHeader->MessageSize - sizeof(NDFS_REPLY_HEADER))
							);
			ASSERT(desResult == IDOK);

			tdiStatus = SendMessage(
							PrimarySession->ConnectionFileObject,
							cryptNdfsWinxpReplyHeader,
							NdfsReplyHeader->Splitted ?
								PrimarySession->SessionContext.SecondaryMaxDataSize :
								(NdfsReplyHeader->MessageSize - sizeof(NDFS_REPLY_HEADER)),
							NULL,
							&PrimarySession->Thread.TransportCtx
							);
		}
		else
#endif
		{	

		tdiStatus = SendMessage( PrimarySession->ConnectionFileObject,
								 &PrimarySession->SendNdasFcStatistics,
								 NULL,
								 (UINT8 *)(NdfsWinxpReplyHeader+1) + (ReplyDataSize - remaninigDataSize),
								 NdfsReplyHeader->Splitted ? 
									PrimarySession->SessionContext.SecondaryMaxDataSize :
									(NTOHL(NdfsReplyHeader->MessageSize4) - sizeof(NDFS_REPLY_HEADER)) );
		}

		if(tdiStatus != STATUS_SUCCESS)
		{
			return tdiStatus;
		}

		//
		//	Decrease remaining bytes
		//

		if(NdfsReplyHeader->Splitted)
			remaninigDataSize -= PrimarySession->SessionContext.SecondaryMaxDataSize;
		else
			return STATUS_SUCCESS;


		ASSERT((INT32)remaninigDataSize > 0);
	}
}
Example #23
0
NTSTATUS
USBSTOR_SendReadWrite(
    IN PDEVICE_OBJECT DeviceObject,
    IN PIRP Irp,
    IN ULONG RetryCount)
{
    UFI_READ_WRITE_CMD Cmd;
    PPDO_DEVICE_EXTENSION PDODeviceExtension;
    PCDB pCDB;
    ULONG BlockCount, Temp;
    PIO_STACK_LOCATION IoStack;
    PSCSI_REQUEST_BLOCK Request;

    //
    // get current stack location
    //
    IoStack = IoGetCurrentIrpStackLocation(Irp);

    //
    // get request block
    //
    Request = (PSCSI_REQUEST_BLOCK)IoStack->Parameters.Others.Argument1;

    //
    // get SCSI command data block
    //
    pCDB = (PCDB)Request->Cdb;

    //
    // get PDO device extension
    //
    PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;

    //
    // informal debug print
    //
    DPRINT("USBSTOR_SendReadWrite DataTransferLength %lu, BlockLength %lu\n", Request->DataTransferLength, PDODeviceExtension->BlockLength);

    //
    // sanity check
    //
    ASSERT(PDODeviceExtension->BlockLength);

    //
    // block count
    //
    BlockCount = Request->DataTransferLength / PDODeviceExtension->BlockLength;

    //
    // initialize read cmd
    //
    RtlZeroMemory(&Cmd, sizeof(UFI_READ_WRITE_CMD));
    Cmd.Code = pCDB->AsByte[0];
    Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
    Cmd.ContiguousLogicBlocksByte0 = pCDB->CDB10.TransferBlocksMsb;
    Cmd.ContiguousLogicBlocksByte1 = pCDB->CDB10.TransferBlocksLsb;
    Cmd.LogicalBlockByte0 = pCDB->CDB10.LogicalBlockByte0;
    Cmd.LogicalBlockByte1 = pCDB->CDB10.LogicalBlockByte1;
    Cmd.LogicalBlockByte2 = pCDB->CDB10.LogicalBlockByte2;
    Cmd.LogicalBlockByte3 = pCDB->CDB10.LogicalBlockByte3;

    //
    // sanity check
    //
    Temp = (Cmd.ContiguousLogicBlocksByte0 << 8 | Cmd.ContiguousLogicBlocksByte1);
    ASSERT(NTOHL(Temp == BlockCount));

    DPRINT("USBSTOR_SendReadWrite BlockAddress %x%x%x%x BlockCount %lu BlockLength %lu\n", Cmd.LogicalBlockByte0, Cmd.LogicalBlockByte1, Cmd.LogicalBlockByte2, Cmd.LogicalBlockByte3, BlockCount, PDODeviceExtension->BlockLength);

    //
    // send request
    //
    return USBSTOR_SendRequest(DeviceObject, Irp, UFI_READ_WRITE_CMD_LEN, (PUCHAR)&Cmd, Request->DataTransferLength, (PUCHAR)Request->DataBuffer, RetryCount);
}
void
swat_tcp_rx_handle(STREAM_CXT_t * pStreamCxt)
{
    A_INT32 ret = 0;
    A_UINT32 clientIp;
    A_UINT16 clientPort;
    A_INT32 clientFd = -1;
    A_UINT32 isFirst = 0;
    struct sockaddr_in clientAddr;
    A_INT32 len = sizeof (struct sockaddr_in);
    struct timeval tmo;
    A_INT32 fdAct = 0;
    q_fd_set sockSet;

    SWAT_PTR_NULL_CHK(pStreamCxt);

    /* Initial Bench Value */
    swat_bench_quit_init();

    swat_fd_zero(&sockSet);
    swat_fd_set(pStreamCxt->socketLocal, &sockSet);
    pStreamCxt->pfd_set = (void *) &sockSet;
    tmo.tv_sec = 2;
    tmo.tv_usec = 0;
    while (1) {
        if (0 == isFirst) {
            ret = swat_listen(pStreamCxt->socketLocal, 10);
            if (ret < 0) {
                /* Close Socket */
                SWAT_PTF("Failed to listen socket %d.\n", pStreamCxt->socketLocal);
                goto QUIT;
            }
            isFirst = 1;
        }
        while (1) {
            if (swat_bench_quit()) {
                goto QUIT;
            }
            fdAct = swat_select(pStreamCxt->socketLocal, &sockSet, NULL, NULL, &tmo);   //k_select()
            if (fdAct != 0) {
                break;
            }
        }
        clientFd = swat_accept(pStreamCxt->socketLocal, (struct sockaddr *) &clientAddr, &len);
        if (clientFd < 0) {
            /* Close Socket */
            SWAT_PTF("Failed to accept socket %d.\n", clientFd);
            goto QUIT;
        }

        clientIp = NTOHL(clientAddr.sin_addr.s_addr);
        clientPort = NTOHS(clientAddr.sin_port);
        pStreamCxt->clientFd = clientFd;
        SWAT_PTF("Receiving from %d.%d.%d.%d Remote port:%d \r\n",
                 (clientIp) >> 24 & 0xFF, (clientIp) >> 16 & 0xFF,
                 (clientIp) >> 8 & 0xFF, (clientIp) & 0xFF, clientPort);

        /* Initial Calc & Time */
        pStreamCxt->calc.firstTime.milliseconds = CALC_TIME_DEF;
        pStreamCxt->calc.lastTime.milliseconds = CALC_TIME_DEF;
        pStreamCxt->calc.bytes = CALC_BYTES_DEF;
        pStreamCxt->calc.kbytes = CALC_KBYTES_DEF;

        swat_tcp_rx_data(pStreamCxt);
        /* Close Client Socket */
        swat_close(pStreamCxt->clientFd);

        pStreamCxt->clientFd = -1;
    }
  QUIT:
    swat_test_result_print(pStreamCxt);
    SWAT_PTF("*************IOT Throughput Test Completed **************\n");
    SWAT_PTF("Shell> ");
    /* Init fd_set */
    swat_fd_zero(&sockSet);
    pStreamCxt->pfd_set = NULL;
    /* Close Socket */
    swat_socket_close(pStreamCxt);
}
Example #25
0
static int 
ip_fw_chk(struct ip **pip, int hlen,
	struct ifnet *oif, int ignport, struct mbuf **m)
{
	struct ip_fw_chain *chain;
	struct ip_fw *rule = NULL;
	struct ip *ip = *pip;
	struct ifnet *const rif = (*m)->m_pkthdr.rcvif;
	u_short offset = (ip->ip_off & IP_OFFMASK);
	u_short src_port, dst_port;

	/*
	 * Go down the chain, looking for enlightment
	 */
	for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) {
		register struct ip_fw *const f = chain->rule;

		/* Check direction inbound */
		if (!oif && !(f->fw_flg & IP_FW_F_IN))
			continue;

		/* Check direction outbound */
		if (oif && !(f->fw_flg & IP_FW_F_OUT))
			continue;

		/* Fragments */
		if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))
			continue;

		/* If src-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVSRC) != 0) ^ ((ip->ip_src.s_addr
		    & f->fw_smsk.s_addr) != f->fw_src.s_addr))
			continue;

		/* If dest-addr doesn't match, not this rule. */
		if (((f->fw_flg & IP_FW_F_INVDST) != 0) ^ ((ip->ip_dst.s_addr
		    & f->fw_dmsk.s_addr) != f->fw_dst.s_addr))
			continue;

		/* Interface check */
		if ((f->fw_flg & IF_FW_F_VIAHACK) == IF_FW_F_VIAHACK) {
			struct ifnet *const iface = oif ? oif : rif;

			/* Backwards compatibility hack for "via" */
			if (!iface || !iface_match(iface,
			    &f->fw_in_if, f->fw_flg & IP_FW_F_OIFNAME))
				continue;
		} else {
			/* Check receive interface */
			if ((f->fw_flg & IP_FW_F_IIFACE)
			    && (!rif || !iface_match(rif,
			      &f->fw_in_if, f->fw_flg & IP_FW_F_IIFNAME)))
				continue;
			/* Check outgoing interface */
			if ((f->fw_flg & IP_FW_F_OIFACE)
			    && (!oif || !iface_match(oif,
			      &f->fw_out_if, f->fw_flg & IP_FW_F_OIFNAME)))
				continue;
		}

		/* Check IP options */
		if (f->fw_ipopt != f->fw_ipnopt && !ipopts_match(ip, f))
			continue;

		/* Check protocol; if wildcard, match */
		if (f->fw_prot == IPPROTO_IP)
			goto got_match;

		/* If different, don't match */
		if (ip->ip_p != f->fw_prot) 
			continue;

#define PULLUP_TO(len)	do {						\
			    if ((*m)->m_len < (len)			\
				&& (*m = m_pullup(*m, (len))) == 0) {	\
				    goto bogusfrag;			\
			    }						\
			    *pip = ip = mtod(*m, struct ip *);		\
			    offset = (ip->ip_off & IP_OFFMASK);		\
			} while (0)

		/* Protocol specific checks */
		switch (ip->ip_p) {
		case IPPROTO_TCP:
		    {
			struct tcphdr *tcp;

			if (offset == 1)	/* cf. RFC 1858 */
				goto bogusfrag;
			if (offset != 0) {
				/*
				 * TCP flags and ports aren't available in this
				 * packet -- if this rule specified either one,
				 * we consider the rule a non-match.
				 */
				if (f->fw_nports != 0 ||
				    f->fw_tcpf != f->fw_tcpnf)
					continue;

				break;
			}
			PULLUP_TO(hlen + 14);
			tcp = (struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			if (f->fw_tcpf != f->fw_tcpnf && !tcpflg_match(tcp, f))
				continue;
			src_port = ntohs(tcp->th_sport);
			dst_port = ntohs(tcp->th_dport);
			goto check_ports;
		    }

		case IPPROTO_UDP:
		    {
			struct udphdr *udp;

			if (offset != 0) {
				/*
				 * Port specification is unavailable -- if this
				 * rule specifies a port, we consider the rule
				 * a non-match.
				 */
				if (f->fw_nports != 0)
					continue;

				break;
			}
			PULLUP_TO(hlen + 4);
			udp = (struct udphdr *) ((u_long *)ip + ip->ip_hl);
			src_port = ntohs(udp->uh_sport);
			dst_port = ntohs(udp->uh_dport);
check_ports:
			if (!port_match(&f->fw_pts[0],
			    IP_FW_GETNSRCP(f), src_port,
			    f->fw_flg & IP_FW_F_SRNG))
				continue;
			if (!port_match(&f->fw_pts[IP_FW_GETNSRCP(f)],
			    IP_FW_GETNDSTP(f), dst_port,
			    f->fw_flg & IP_FW_F_DRNG)) 
				continue;
			break;
		    }

		case IPPROTO_ICMP:
		    {
			struct icmp *icmp;

			if (offset != 0)	/* Type isn't valid */
				break;
			PULLUP_TO(hlen + 2);
			icmp = (struct icmp *) ((u_long *)ip + ip->ip_hl);
			if (!icmptype_match(icmp, f))
				continue;
			break;
		    }
#undef PULLUP_TO

bogusfrag:
			if (fw_verbose)
				ipfw_report(NULL, ip, rif, oif);
			goto dropit;
		}

got_match:
		/* Ignore divert/tee rule if socket port is "ignport" */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_DIVERT:
		case IP_FW_F_TEE:
			if (f->fw_divert_port == ignport)
				continue;       /* ignore this rule */
			break;
		}

		/* Update statistics */
		f->fw_pcnt += 1;
		f->fw_bcnt += ip->ip_len;
		f->timestamp = rtems_bsdnet_seconds_since_boot();

		/* Log to console if desired */
		if ((f->fw_flg & IP_FW_F_PRN) && fw_verbose)
			ipfw_report(f, ip, rif, oif);

		/* Take appropriate action */
		switch (f->fw_flg & IP_FW_F_COMMAND) {
		case IP_FW_F_ACCEPT:
			return(0);
		case IP_FW_F_COUNT:
			continue;
		case IP_FW_F_DIVERT:
			return(f->fw_divert_port);
		case IP_FW_F_TEE:
			/*
			 * XXX someday tee packet here, but beware that you
			 * can't use m_copym() or m_copypacket() because
			 * the divert input routine modifies the mbuf
			 * (and these routines only increment reference
			 * counts in the case of mbuf clusters), so need
			 * to write custom routine.
			 */
			continue;
		case IP_FW_F_SKIPTO:
#ifdef DIAGNOSTIC
			while (chain->chain.le_next
			    && chain->chain.le_next->rule->fw_number
				< f->fw_skipto_rule)
#else
			while (chain->chain.le_next->rule->fw_number
			    < f->fw_skipto_rule)
#endif
				chain = chain->chain.le_next;
			continue;
		}

		/* Deny/reject this packet using this rule */
		rule = f;
		break;
	}

#ifdef DIAGNOSTIC
	/* Rule 65535 should always be there and should always match */
	if (!chain)
		panic("ip_fw: chain");
#endif

	/*
	 * At this point, we're going to drop the packet.
	 * Send a reject notice if all of the following are true:
	 *
	 * - The packet matched a reject rule
	 * - The packet is not an ICMP packet
	 * - The packet is not a multicast or broadcast packet
	 */
	if ((rule->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_REJECT
	    && ip->ip_p != IPPROTO_ICMP
	    && !((*m)->m_flags & (M_BCAST|M_MCAST))
	    && !IN_MULTICAST(ntohl(ip->ip_dst.s_addr))) {
		switch (rule->fw_reject_code) {
		case IP_FW_REJECT_RST:
		  {
			struct tcphdr *const tcp =
				(struct tcphdr *) ((u_long *)ip + ip->ip_hl);
			struct tcpiphdr ti, *const tip = (struct tcpiphdr *) ip;

			if (offset != 0 || (tcp->th_flags & TH_RST))
				break;
			ti.ti_i = *((struct ipovly *) ip);
			ti.ti_t = *tcp;
			bcopy(&ti, ip, sizeof(ti));
			NTOHL(tip->ti_seq);
			NTOHL(tip->ti_ack);
			tip->ti_len = ip->ip_len - hlen - (tip->ti_off << 2);
			if (tcp->th_flags & TH_ACK) {
				tcp_respond(NULL, tip, *m,
				    (tcp_seq)0, ntohl(tcp->th_ack), TH_RST);
			} else {
				if (tcp->th_flags & TH_SYN)
					tip->ti_len++;
				tcp_respond(NULL, tip, *m, tip->ti_seq
				    + tip->ti_len, (tcp_seq)0, TH_RST|TH_ACK);
			}
			*m = NULL;
			break;
		  }
		default:	/* Send an ICMP unreachable using code */
			icmp_error(*m, ICMP_UNREACH,
			    rule->fw_reject_code, 0L, 0);
			*m = NULL;
			break;
		}
	}

dropit:
	/*
	 * Finally, drop the packet.
	 */
	if (*m) {
		m_freem(*m);
		*m = NULL;
	}
	return(0);
}
void
swat_udp_rx_data(STREAM_CXT_t * pStreamCxt)
{
    A_INT32 recvBytes = 0;
    A_INT32 fromSize = 0;
    A_UINT32 sumBytes = 0;
    A_UINT8 *pDataBuffer = NULL;
    struct sockaddr_in fromAddr;
    q_fd_set sockSet;
    struct timeval tmo;
    A_INT32 fdAct = 0;
    A_UINT32 isFirst = 1;
    A_UINT32 clientIp = 0;
    A_UINT16 clientPort = 0;
    A_UINT32 totalInterval = 0;
    A_UINT32 sendBytes = 0;
    STAT_PACKET_t StatPacket;

    A_INT32 sendTerminalCount = 0;

    SWAT_PTR_NULL_CHK(pStreamCxt);

    /* Initial Calc & Time */
    pStreamCxt->calc.firstTime.milliseconds = CALC_TIME_DEF;
    pStreamCxt->calc.lastTime.milliseconds = CALC_TIME_DEF;
    pStreamCxt->calc.bytes = CALC_BYTES_DEF;
    pStreamCxt->calc.kbytes = CALC_KBYTES_DEF;

    /* Initial Bench Value */
    swat_bench_quit_init();

    /* Malloc Packet Buffer Size */
    pDataBuffer = swat_mem_malloc(pStreamCxt->param.pktSize);
    if (NULL == pDataBuffer) {
        SWAT_PTF("UDP RX data buffer malloc error\r\n");
        return;
    }
    pStreamCxt->param.pktBuff = pDataBuffer;

    memset(&StatPacket, 0, sizeof (StatPacket));

    /* Prepare IP address & port */
    memset(&fromAddr, 0, sizeof (struct sockaddr_in));
    fromSize = sizeof (struct sockaddr_in);

    /* Init fd_set */
    swat_fd_zero(&sockSet);
    swat_fd_set(pStreamCxt->socketLocal, &sockSet);
    pStreamCxt->pfd_set = (void *) &sockSet;
    tmo.tv_sec = 300;
    tmo.tv_usec = 0;

    /* Get First Time */
    swat_get_first_time(pStreamCxt);

    while (1) {
        if (swat_bench_quit()) {
            /* Get Last Time For Pressure */
            //SWAT_PTF("Bench quit!!\r\n");
            swat_get_last_time(pStreamCxt);

            //swat_bytes_calc(pStreamCxt, sumBytes);
            break;
        }

        /* Wait for Input */
        fdAct = swat_select(pStreamCxt->socketLocal + 1, &sockSet, NULL, NULL, &tmo);   //k_select()
        if (0 != fdAct) {
            if (swat_fd_isset(pStreamCxt->socketLocal, &sockSet)) {
                recvBytes = swat_recvfrom(pStreamCxt->socketLocal, (char*) pDataBuffer,
                                          pStreamCxt->param.pktSize, 0,
                                          (struct sockaddr *) &fromAddr, &fromSize);
                if (recvBytes <= 0) {
                    SWAT_PTF("UDP Socket receive is error %d, sumBytes = %d\r\n", recvBytes,
                             sumBytes);
                    break;
                }

                if (recvBytes >= sizeof (EOT_PACKET_t)) {
                    if (isFirst) {
                        if (recvBytes > sizeof (EOT_PACKET_t)) {
                            clientIp = NTOHL(fromAddr.sin_addr.s_addr);
                            clientPort = NTOHS(fromAddr.sin_port);

                            SWAT_PTF("UDP receving from %d.%d.%d.%d port:%d \r\n",
                                     (clientIp) >> 24 & 0xFF, (clientIp) >> 16 & 0xFF,
                                     (clientIp) >> 8 & 0xFF, (clientIp) & 0xFF, clientPort);
                            isFirst = 0;
                            swat_get_first_time(pStreamCxt);
                        }
                        swat_bytes_calc(pStreamCxt, recvBytes);
                    } else {

                    	/*End packet is not count*/
                    	if (recvBytes > sizeof (EOT_PACKET_t)) {
							swat_bytes_calc(pStreamCxt, recvBytes);
                    	}
						else {

							/* Update Port */
							fromAddr.sin_port = HTONS(pStreamCxt->param.port);
							fromAddr.sin_family = AF_INET;	/* End Of Transfer */

                            swat_get_last_time(pStreamCxt);

                            totalInterval =
                                (pStreamCxt->calc.lastTime.milliseconds -
                                 pStreamCxt->calc.firstTime.milliseconds);
                            StatPacket.kbytes = pStreamCxt->calc.kbytes;
                            StatPacket.bytes = pStreamCxt->calc.bytes;
                            StatPacket.msec = totalInterval;
                            /* Tell ath_console TX received end mark AABBCCDD with throughput value */
                            while (sendTerminalCount <= 10) {
                                /* Wait for Output */
                                fdAct = swat_select(pStreamCxt->socketLocal + 1, NULL, &sockSet, NULL, &tmo);   //k_select()
                                if (0 != fdAct) {
                                    if (swat_fd_isset(pStreamCxt->socketLocal, &sockSet)) {
                                        sendBytes = swat_sendto(pStreamCxt->socketLocal,
                                                                (char *) (&StatPacket),
                                                                sizeof (STAT_PACKET_t), 0,
                                                                (struct sockaddr *) &fromAddr,
                                                                sizeof (struct sockaddr_in));
                                        if (sendBytes < 0) {
                                            SWAT_PTF
                                                ("UDP send throughput info packet error %d , retry %d \r\n",
                                                 sendBytes, sendTerminalCount);
                                            qcom_thread_msleep(100);
                                        } else {
                                            /* Clean */
                                            tmo.tv_sec = 2;
                                            tmo.tv_usec = 0;
                                            while (recvBytes == sizeof (EOT_PACKET_t)) {
                                                fdAct = swat_select(pStreamCxt->socketLocal + 1, &sockSet, NULL, NULL, &tmo);   //k_select()
                                                if (0 == fdAct) {
                                                    SWAT_PTF("UDP break\n");
                                                    break;
                                                }

                                                if (swat_fd_isset(pStreamCxt->socketLocal, &sockSet)) {
                                                    recvBytes = swat_recvfrom(pStreamCxt->socketLocal, (char*) pDataBuffer,
                                                                              pStreamCxt->param.pktSize, 0,
                                                                              (struct sockaddr *) &fromAddr, &fromSize);
                                                }
                                            }
                                            break;
                                        }
                                    }
                                }
                                sendTerminalCount++;
                            }
                            break;
                        }
                    }
                }
            }
Example #27
0
/*
 * TCP input routine, follows pages 65-76 of the
 * protocol specification dated September, 1981 very closely.
 */
void
tcp_input(struct mbuf *m, int iphlen, struct socket *inso)
{
  	struct ip save_ip, *ip;
	register struct tcpiphdr *ti;
	caddr_t optp = NULL;
	int optlen = 0;
	int len, tlen, off;
        register struct tcpcb *tp = NULL;
	register int tiflags;
        struct socket *so = NULL;
	int todrop, acked, ourfinisacked, needoutput = 0;
	int iss = 0;
	u_long tiwin;
	int ret;
    struct ex_list *ex_ptr;
    Slirp *slirp;

	DEBUG_CALL("tcp_input");
	DEBUG_ARGS((dfd," m = %8lx  iphlen = %2d  inso = %lx\n",
		    (long )m, iphlen, (long )inso ));

	/*
	 * If called with m == 0, then we're continuing the connect
	 */
	if (m == NULL) {
		so = inso;
		slirp = so->slirp;

		/* Re-set a few variables */
		tp = sototcpcb(so);
		m = so->so_m;
                so->so_m = NULL;
		ti = so->so_ti;
		tiwin = ti->ti_win;
		tiflags = ti->ti_flags;

		goto cont_conn;
	}
	slirp = m->slirp;

	/*
	 * Get IP and TCP header together in first mbuf.
	 * Note: IP leaves IP header in first mbuf.
	 */
	ti = mtod(m, struct tcpiphdr *);
	if (iphlen > sizeof(struct ip )) {
	  ip_stripoptions(m, (struct mbuf *)0);
	  iphlen=sizeof(struct ip );
	}
	/* XXX Check if too short */


	/*
	 * Save a copy of the IP header in case we want restore it
	 * for sending an ICMP error message in response.
	 */
	ip=mtod(m, struct ip *);
	save_ip = *ip;
	save_ip.ip_len+= iphlen;

	/*
	 * Checksum extended TCP header and data.
	 */
	tlen = ((struct ip *)ti)->ip_len;
        tcpiphdr2qlink(ti)->next = tcpiphdr2qlink(ti)->prev = NULL;
        memset(&ti->ti_i.ih_mbuf, 0 , sizeof(struct mbuf_ptr));
	ti->ti_x1 = 0;
	ti->ti_len = htons((uint16_t)tlen);
	len = sizeof(struct ip ) + tlen;
	if(cksum(m, len)) {
	  goto drop;
	}

	/*
	 * Check that TCP offset makes sense,
	 * pull out TCP options and adjust length.		XXX
	 */
	off = ti->ti_off << 2;
	if (off < sizeof (struct tcphdr) || off > tlen) {
	  goto drop;
	}
	tlen -= off;
	ti->ti_len = tlen;
	if (off > sizeof (struct tcphdr)) {
	  optlen = off - sizeof (struct tcphdr);
	  optp = mtod(m, caddr_t) + sizeof (struct tcpiphdr);
	}
	tiflags = ti->ti_flags;

	/*
	 * Convert TCP protocol specific fields to host format.
	 */
	NTOHL(ti->ti_seq);
	NTOHL(ti->ti_ack);
	NTOHS(ti->ti_win);
	NTOHS(ti->ti_urp);

	/*
	 * Drop TCP, IP headers and TCP options.
	 */
	m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);

    if (slirp->restricted) {
        for (ex_ptr = slirp->exec_list; ex_ptr; ex_ptr = ex_ptr->ex_next) {
            if (ex_ptr->ex_fport == ti->ti_dport &&
                ti->ti_dst.s_addr == ex_ptr->ex_addr.s_addr) {
                break;
            }
        }
        if (!ex_ptr)
            goto drop;
    }
	/*
	 * Locate pcb for segment.
	 */
findso:
	so = slirp->tcp_last_so;
	if (so->so_fport != ti->ti_dport ||
	    so->so_lport != ti->ti_sport ||
	    so->so_laddr.s_addr != ti->ti_src.s_addr ||
	    so->so_faddr.s_addr != ti->ti_dst.s_addr) {
		so = solookup(&slirp->tcb, ti->ti_src, ti->ti_sport,
			       ti->ti_dst, ti->ti_dport);
		if (so)
			slirp->tcp_last_so = so;
	}

	/*
	 * If the state is CLOSED (i.e., TCB does not exist) then
	 * all data in the incoming segment is discarded.
	 * If the TCB exists but is in CLOSED state, it is embryonic,
	 * but should either do a listen or a connect soon.
	 *
	 * state == CLOSED means we've done socreate() but haven't
	 * attached it to a protocol yet...
	 *
	 * XXX If a TCB does not exist, and the TH_SYN flag is
	 * the only flag set, then create a session, mark it
	 * as if it was LISTENING, and continue...
	 */
        if (so == NULL) {
	  if ((tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) != TH_SYN)
	    goto dropwithreset;

	  if ((so = socreate(slirp)) == NULL)
	    goto dropwithreset;
	  if (tcp_attach(so) < 0) {
	    free(so); /* Not sofree (if it failed, it's not insqued) */
	    goto dropwithreset;
	  }

	  sbreserve(&so->so_snd, TCP_SNDSPACE);
	  sbreserve(&so->so_rcv, TCP_RCVSPACE);

	  so->so_laddr = ti->ti_src;
	  so->so_lport = ti->ti_sport;
	  so->so_faddr = ti->ti_dst;
	  so->so_fport = ti->ti_dport;

	  if ((so->so_iptos = tcp_tos(so)) == 0)
	    so->so_iptos = ((struct ip *)ti)->ip_tos;

	  tp = sototcpcb(so);
	  tp->t_state = TCPS_LISTEN;
	}

        /*
         * If this is a still-connecting socket, this probably
         * a retransmit of the SYN.  Whether it's a retransmit SYN
	 * or something else, we nuke it.
         */
        if (so->so_state & SS_ISFCONNECTING)
                goto drop;

	tp = sototcpcb(so);

	/* XXX Should never fail */
        if (tp == NULL)
		goto dropwithreset;
	if (tp->t_state == TCPS_CLOSED)
		goto drop;

	tiwin = ti->ti_win;

	/*
	 * Segment received on connection.
	 * Reset idle time and keep-alive timer.
	 */
	tp->t_idle = 0;
	if (SO_OPTIONS)
	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEPINTVL;
	else
	   tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_IDLE;

	/*
	 * Process options if not in LISTEN state,
	 * else do it below (after getting remote address).
	 */
	if (optp && tp->t_state != TCPS_LISTEN)
		tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	/*
	 * Header prediction: check for the two common cases
	 * of a uni-directional data xfer.  If the packet has
	 * no control flags, is in-sequence, the window didn't
	 * change and we're not retransmitting, it's a
	 * candidate.  If the length is zero and the ack moved
	 * forward, we're the sender side of the xfer.  Just
	 * free the data acked & wake any higher level process
	 * that was blocked waiting for space.  If the length
	 * is non-zero and the ack didn't move, we're the
	 * receiver side.  If we're getting packets in-order
	 * (the reassembly queue is empty), add the data to
	 * the socket buffer and note that we need a delayed ack.
	 *
	 * XXX Some of these tests are not needed
	 * eg: the tiwin == tp->snd_wnd prevents many more
	 * predictions.. with no *real* advantage..
	 */
	if (tp->t_state == TCPS_ESTABLISHED &&
	    (tiflags & (TH_SYN|TH_FIN|TH_RST|TH_URG|TH_ACK)) == TH_ACK &&
	    ti->ti_seq == tp->rcv_nxt &&
	    tiwin && tiwin == tp->snd_wnd &&
	    tp->snd_nxt == tp->snd_max) {
		if (ti->ti_len == 0) {
			if (SEQ_GT(ti->ti_ack, tp->snd_una) &&
			    SEQ_LEQ(ti->ti_ack, tp->snd_max) &&
			    tp->snd_cwnd >= tp->snd_wnd) {
				/*
				 * this is a pure ack for outstanding data.
				 */
				if (tp->t_rtt &&
				    SEQ_GT(ti->ti_ack, tp->t_rtseq))
					tcp_xmit_timer(tp, tp->t_rtt);
				acked = ti->ti_ack - tp->snd_una;
				sbdrop(&so->so_snd, acked);
				tp->snd_una = ti->ti_ack;
				m_freem(m);

				/*
				 * If all outstanding data are acked, stop
				 * retransmit timer, otherwise restart timer
				 * using current (possibly backed-off) value.
				 * If process is waiting for space,
				 * wakeup/selwakeup/signal.  If data
				 * are ready to send, let tcp_output
				 * decide between more output or persist.
				 */
				if (tp->snd_una == tp->snd_max)
					tp->t_timer[TCPT_REXMT] = 0;
				else if (tp->t_timer[TCPT_PERSIST] == 0)
					tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;

				/*
				 * This is called because sowwakeup might have
				 * put data into so_snd.  Since we don't so sowwakeup,
				 * we don't need this.. XXX???
				 */
				if (so->so_snd.sb_cc)
					(void) tcp_output(tp);

				return;
			}
		} else if (ti->ti_ack == tp->snd_una &&
		    tcpfrag_list_empty(tp) &&
		    ti->ti_len <= sbspace(&so->so_rcv)) {
			/*
			 * this is a pure, in-sequence data packet
			 * with nothing on the reassembly queue and
			 * we have enough buffer space to take it.
			 */
			tp->rcv_nxt += ti->ti_len;
			/*
			 * Add data to socket buffer.
			 */
			if (so->so_emu) {
				if (tcp_emu(so,m)) sbappend(so, m);
			} else
				sbappend(so, m);

			/*
			 * If this is a short packet, then ACK now - with Nagel
			 *	congestion avoidance sender won't send more until
			 *	he gets an ACK.
			 *
			 * It is better to not delay acks at all to maximize
			 * TCP throughput.  See RFC 2581.
			 */
			tp->t_flags |= TF_ACKNOW;
			tcp_output(tp);
			return;
		}
	} /* header prediction */
	/*
	 * Calculate amount of space in receive window,
	 * and then do TCP input processing.
	 * Receive window is amount of space in rcv queue,
	 * but not less than advertised window.
	 */
	{ int win;
          win = sbspace(&so->so_rcv);
	  if (win < 0)
	    win = 0;
	  tp->rcv_wnd = max(win, (int)(tp->rcv_adv - tp->rcv_nxt));
	}

	switch (tp->t_state) {

	/*
	 * If the state is LISTEN then ignore segment if it contains an RST.
	 * If the segment contains an ACK then it is bad and send a RST.
	 * If it does not contain a SYN then it is not interesting; drop it.
	 * Don't bother responding if the destination was a broadcast.
	 * Otherwise initialize tp->rcv_nxt, and tp->irs, select an initial
	 * tp->iss, and send a segment:
	 *     <SEQ=ISS><ACK=RCV_NXT><CTL=SYN,ACK>
	 * Also initialize tp->snd_nxt to tp->iss+1 and tp->snd_una to tp->iss.
	 * Fill in remote peer address fields if not previously specified.
	 * Enter SYN_RECEIVED state, and process any other fields of this
	 * segment in this state.
	 */
	case TCPS_LISTEN: {

	  if (tiflags & TH_RST)
	    goto drop;
	  if (tiflags & TH_ACK)
	    goto dropwithreset;
	  if ((tiflags & TH_SYN) == 0)
	    goto drop;

	  /*
	   * This has way too many gotos...
	   * But a bit of spaghetti code never hurt anybody :)
	   */

	  /*
	   * If this is destined for the control address, then flag to
	   * tcp_ctl once connected, otherwise connect
	   */
	  if ((so->so_faddr.s_addr & slirp->vnetwork_mask.s_addr) ==
	      slirp->vnetwork_addr.s_addr) {
	    if (so->so_faddr.s_addr != slirp->vhost_addr.s_addr &&
		so->so_faddr.s_addr != slirp->vnameserver_addr.s_addr) {
		/* May be an add exec */
		for (ex_ptr = slirp->exec_list; ex_ptr;
		     ex_ptr = ex_ptr->ex_next) {
		  if(ex_ptr->ex_fport == so->so_fport &&
		     so->so_faddr.s_addr == ex_ptr->ex_addr.s_addr) {
		    so->so_state |= SS_CTL;
		    break;
		  }
		}
		if (so->so_state & SS_CTL) {
		    goto cont_input;
		}
	    }
	    /* CTL_ALIAS: Do nothing, tcp_fconnect will be called on it */
	  }

	  if (so->so_emu & EMU_NOCONNECT) {
	    so->so_emu &= ~EMU_NOCONNECT;
	    goto cont_input;
	  }

	  if((tcp_fconnect(so) == -1) && (errno != EINPROGRESS) && (errno != EWOULDBLOCK)) {
	    u_char code=ICMP_UNREACH_NET;
	    DEBUG_MISC((dfd," tcp fconnect errno = %d-%s\n",
			errno,strerror(errno)));
	    if(errno == ECONNREFUSED) {
	      /* ACK the SYN, send RST to refuse the connection */
	      tcp_respond(tp, ti, m, ti->ti_seq+1, (tcp_seq)0,
			  TH_RST|TH_ACK);
	    } else {
	      if(errno == EHOSTUNREACH) code=ICMP_UNREACH_HOST;
	      HTONL(ti->ti_seq);             /* restore tcp header */
	      HTONL(ti->ti_ack);
	      HTONS(ti->ti_win);
	      HTONS(ti->ti_urp);
	      m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	      m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
	      *ip=save_ip;
	      icmp_error(m, ICMP_UNREACH,code, 0,strerror(errno));
	    }
            tcp_close(tp);
	    m_free(m);
	  } else {
	    /*
	     * Haven't connected yet, save the current mbuf
	     * and ti, and return
	     * XXX Some OS's don't tell us whether the connect()
	     * succeeded or not.  So we must time it out.
	     */
	    so->so_m = m;
	    so->so_ti = ti;
	    tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
	    tp->t_state = TCPS_SYN_RECEIVED;
	  }
	  return;

	cont_conn:
	  /* m==NULL
	   * Check if the connect succeeded
	   */
	  if (so->so_state & SS_NOFDREF) {
	    tp = tcp_close(tp);
	    goto dropwithreset;
	  }
	cont_input:
	  tcp_template(tp);

	  if (optp)
	    tcp_dooptions(tp, (u_char *)optp, optlen, ti);

	  if (iss)
	    tp->iss = iss;
	  else
	    tp->iss = slirp->tcp_iss;
	  slirp->tcp_iss += TCP_ISSINCR/2;
	  tp->irs = ti->ti_seq;
	  tcp_sendseqinit(tp);
	  tcp_rcvseqinit(tp);
	  tp->t_flags |= TF_ACKNOW;
	  tp->t_state = TCPS_SYN_RECEIVED;
	  tp->t_timer[TCPT_KEEP] = TCPTV_KEEP_INIT;
	  goto trimthenstep6;
	} /* case TCPS_LISTEN */

	/*
	 * If the state is SYN_SENT:
	 *	if seg contains an ACK, but not for our SYN, drop the input.
	 *	if seg contains a RST, then drop the connection.
	 *	if seg does not contain SYN, then drop it.
	 * Otherwise this is an acceptable SYN segment
	 *	initialize tp->rcv_nxt and tp->irs
	 *	if seg contains ack then advance tp->snd_una
	 *	if SYN has been acked change to ESTABLISHED else SYN_RCVD state
	 *	arrange for segment to be acked (eventually)
	 *	continue processing rest of data/controls, beginning with URG
	 */
	case TCPS_SYN_SENT:
		if ((tiflags & TH_ACK) &&
		    (SEQ_LEQ(ti->ti_ack, tp->iss) ||
		     SEQ_GT(ti->ti_ack, tp->snd_max)))
			goto dropwithreset;

		if (tiflags & TH_RST) {
                        if (tiflags & TH_ACK) {
                                tcp_drop(tp, 0); /* XXX Check t_softerror! */
                        }
			goto drop;
		}

		if ((tiflags & TH_SYN) == 0)
			goto drop;
		if (tiflags & TH_ACK) {
			tp->snd_una = ti->ti_ack;
			if (SEQ_LT(tp->snd_nxt, tp->snd_una))
				tp->snd_nxt = tp->snd_una;
		}

		tp->t_timer[TCPT_REXMT] = 0;
		tp->irs = ti->ti_seq;
		tcp_rcvseqinit(tp);
		tp->t_flags |= TF_ACKNOW;
		if (tiflags & TH_ACK && SEQ_GT(tp->snd_una, tp->iss)) {
			soisfconnected(so);
			tp->t_state = TCPS_ESTABLISHED;

			(void) tcp_reass(tp, (struct tcpiphdr *)0,
				(struct mbuf *)0);
			/*
			 * if we didn't have to retransmit the SYN,
			 * use its rtt as our initial srtt & rtt var.
			 */
			if (tp->t_rtt)
				tcp_xmit_timer(tp, tp->t_rtt);
		} else
			tp->t_state = TCPS_SYN_RECEIVED;

trimthenstep6:
		/*
		 * Advance ti->ti_seq to correspond to first data byte.
		 * If data, trim to stay within window,
		 * dropping FIN if necessary.
		 */
		ti->ti_seq++;
		if (ti->ti_len > tp->rcv_wnd) {
			todrop = ti->ti_len - tp->rcv_wnd;
			m_adj(m, -todrop);
			ti->ti_len = tp->rcv_wnd;
			tiflags &= ~TH_FIN;
		}
		tp->snd_wl1 = ti->ti_seq - 1;
		tp->rcv_up = ti->ti_seq;
		goto step6;
	} /* switch tp->t_state */
	/*
	 * States other than LISTEN or SYN_SENT.
	 * Check that at least some bytes of segment are within
	 * receive window.  If segment begins before rcv_nxt,
	 * drop leading data (and SYN); if nothing left, just ack.
	 */
	todrop = tp->rcv_nxt - ti->ti_seq;
	if (todrop > 0) {
		if (tiflags & TH_SYN) {
			tiflags &= ~TH_SYN;
			ti->ti_seq++;
			if (ti->ti_urp > 1)
				ti->ti_urp--;
			else
				tiflags &= ~TH_URG;
			todrop--;
		}
		/*
		 * Following if statement from Stevens, vol. 2, p. 960.
		 */
		if (todrop > ti->ti_len
		    || (todrop == ti->ti_len && (tiflags & TH_FIN) == 0)) {
			/*
			 * Any valid FIN must be to the left of the window.
			 * At this point the FIN must be a duplicate or out
			 * of sequence; drop it.
			 */
			tiflags &= ~TH_FIN;

			/*
			 * Send an ACK to resynchronize and drop any data.
			 * But keep on processing for RST or ACK.
			 */
			tp->t_flags |= TF_ACKNOW;
			todrop = ti->ti_len;
		}
		m_adj(m, todrop);
		ti->ti_seq += todrop;
		ti->ti_len -= todrop;
		if (ti->ti_urp > todrop)
			ti->ti_urp -= todrop;
		else {
			tiflags &= ~TH_URG;
			ti->ti_urp = 0;
		}
	}
	/*
	 * If new data are received on a connection after the
	 * user processes are gone, then RST the other end.
	 */
	if ((so->so_state & SS_NOFDREF) &&
	    tp->t_state > TCPS_CLOSE_WAIT && ti->ti_len) {
		tp = tcp_close(tp);
		goto dropwithreset;
	}

	/*
	 * If segment ends after window, drop trailing data
	 * (and PUSH and FIN); if nothing left, just ACK.
	 */
	todrop = (ti->ti_seq+ti->ti_len) - (tp->rcv_nxt+tp->rcv_wnd);
	if (todrop > 0) {
		if (todrop >= ti->ti_len) {
			/*
			 * If a new connection request is received
			 * while in TIME_WAIT, drop the old connection
			 * and start over if the sequence numbers
			 * are above the previous ones.
			 */
			if (tiflags & TH_SYN &&
			    tp->t_state == TCPS_TIME_WAIT &&
			    SEQ_GT(ti->ti_seq, tp->rcv_nxt)) {
				iss = tp->rcv_nxt + TCP_ISSINCR;
				tp = tcp_close(tp);
				goto findso;
			}
			/*
			 * If window is closed can only take segments at
			 * window edge, and have to drop data and PUSH from
			 * incoming segments.  Continue processing, but
			 * remember to ack.  Otherwise, drop segment
			 * and ack.
			 */
			if (tp->rcv_wnd == 0 && ti->ti_seq == tp->rcv_nxt) {
				tp->t_flags |= TF_ACKNOW;
			} else {
				goto dropafterack;
			}
		}
		m_adj(m, -todrop);
		ti->ti_len -= todrop;
		tiflags &= ~(TH_PUSH|TH_FIN);
	}

	/*
	 * If the RST bit is set examine the state:
	 *    SYN_RECEIVED STATE:
	 *	If passive open, return to LISTEN state.
	 *	If active open, inform user that connection was refused.
	 *    ESTABLISHED, FIN_WAIT_1, FIN_WAIT2, CLOSE_WAIT STATES:
	 *	Inform user that connection was reset, and close tcb.
	 *    CLOSING, LAST_ACK, TIME_WAIT STATES
	 *	Close the tcb.
	 */
	if (tiflags&TH_RST) switch (tp->t_state) {

	case TCPS_SYN_RECEIVED:
	case TCPS_ESTABLISHED:
	case TCPS_FIN_WAIT_1:
	case TCPS_FIN_WAIT_2:
	case TCPS_CLOSE_WAIT:
		tp->t_state = TCPS_CLOSED;
                tcp_close(tp);
		goto drop;

	case TCPS_CLOSING:
	case TCPS_LAST_ACK:
	case TCPS_TIME_WAIT:
                tcp_close(tp);
		goto drop;
	}

	/*
	 * If a SYN is in the window, then this is an
	 * error and we send an RST and drop the connection.
	 */
	if (tiflags & TH_SYN) {
		tp = tcp_drop(tp,0);
		goto dropwithreset;
	}

	/*
	 * If the ACK bit is off we drop the segment and return.
	 */
	if ((tiflags & TH_ACK) == 0) goto drop;

	/*
	 * Ack processing.
	 */
	switch (tp->t_state) {
	/*
	 * In SYN_RECEIVED state if the ack ACKs our SYN then enter
	 * ESTABLISHED state and continue processing, otherwise
	 * send an RST.  una<=ack<=max
	 */
	case TCPS_SYN_RECEIVED:

		if (SEQ_GT(tp->snd_una, ti->ti_ack) ||
		    SEQ_GT(ti->ti_ack, tp->snd_max))
			goto dropwithreset;
		tp->t_state = TCPS_ESTABLISHED;
		/*
		 * The sent SYN is ack'ed with our sequence number +1
		 * The first data byte already in the buffer will get
		 * lost if no correction is made.  This is only needed for
		 * SS_CTL since the buffer is empty otherwise.
		 * tp->snd_una++; or:
		 */
		tp->snd_una=ti->ti_ack;
		if (so->so_state & SS_CTL) {
		  /* So tcp_ctl reports the right state */
		  ret = tcp_ctl(so);
		  if (ret == 1) {
		    soisfconnected(so);
		    so->so_state &= ~SS_CTL;   /* success XXX */
		  } else if (ret == 2) {
		    so->so_state &= SS_PERSISTENT_MASK;
		    so->so_state |= SS_NOFDREF; /* CTL_CMD */
		  } else {
		    needoutput = 1;
		    tp->t_state = TCPS_FIN_WAIT_1;
		  }
		} else {
		  soisfconnected(so);
		}

		(void) tcp_reass(tp, (struct tcpiphdr *)0, (struct mbuf *)0);
		tp->snd_wl1 = ti->ti_seq - 1;
		/* Avoid ack processing; snd_una==ti_ack  =>  dup ack */
		goto synrx_to_est;
		/* fall into ... */

	/*
	 * In ESTABLISHED state: drop duplicate ACKs; ACK out of range
	 * ACKs.  If the ack is in the range
	 *	tp->snd_una < ti->ti_ack <= tp->snd_max
	 * then advance tp->snd_una to ti->ti_ack and drop
	 * data from the retransmission queue.  If this ACK reflects
	 * more up to date window information we update our window information.
	 */
	case TCPS_ESTABLISHED:
	case TCPS_FIN_WAIT_1:
	case TCPS_FIN_WAIT_2:
	case TCPS_CLOSE_WAIT:
	case TCPS_CLOSING:
	case TCPS_LAST_ACK:
	case TCPS_TIME_WAIT:

		if (SEQ_LEQ(ti->ti_ack, tp->snd_una)) {
			if (ti->ti_len == 0 && tiwin == tp->snd_wnd) {
			  DEBUG_MISC((dfd," dup ack  m = %lx  so = %lx \n",
				      (long )m, (long )so));
				/*
				 * If we have outstanding data (other than
				 * a window probe), this is a completely
				 * duplicate ack (ie, window info didn't
				 * change), the ack is the biggest we've
				 * seen and we've seen exactly our rexmt
				 * threshold of them, assume a packet
				 * has been dropped and retransmit it.
				 * Kludge snd_nxt & the congestion
				 * window so we send only this one
				 * packet.
				 *
				 * We know we're losing at the current
				 * window size so do congestion avoidance
				 * (set ssthresh to half the current window
				 * and pull our congestion window back to
				 * the new ssthresh).
				 *
				 * Dup acks mean that packets have left the
				 * network (they're now cached at the receiver)
				 * so bump cwnd by the amount in the receiver
				 * to keep a constant cwnd packets in the
				 * network.
				 */
				if (tp->t_timer[TCPT_REXMT] == 0 ||
				    ti->ti_ack != tp->snd_una)
					tp->t_dupacks = 0;
				else if (++tp->t_dupacks == TCPREXMTTHRESH) {
					tcp_seq onxt = tp->snd_nxt;
					u_int win =
					    min(tp->snd_wnd, tp->snd_cwnd) / 2 /
						tp->t_maxseg;

					if (win < 2)
						win = 2;
					tp->snd_ssthresh = win * tp->t_maxseg;
					tp->t_timer[TCPT_REXMT] = 0;
					tp->t_rtt = 0;
					tp->snd_nxt = ti->ti_ack;
					tp->snd_cwnd = tp->t_maxseg;
					(void) tcp_output(tp);
					tp->snd_cwnd = tp->snd_ssthresh +
					       tp->t_maxseg * tp->t_dupacks;
					if (SEQ_GT(onxt, tp->snd_nxt))
						tp->snd_nxt = onxt;
					goto drop;
				} else if (tp->t_dupacks > TCPREXMTTHRESH) {
					tp->snd_cwnd += tp->t_maxseg;
					(void) tcp_output(tp);
					goto drop;
				}
			} else
				tp->t_dupacks = 0;
			break;
		}
	synrx_to_est:
		/*
		 * If the congestion window was inflated to account
		 * for the other side's cached packets, retract it.
		 */
		if (tp->t_dupacks > TCPREXMTTHRESH &&
		    tp->snd_cwnd > tp->snd_ssthresh)
			tp->snd_cwnd = tp->snd_ssthresh;
		tp->t_dupacks = 0;
		if (SEQ_GT(ti->ti_ack, tp->snd_max)) {
			goto dropafterack;
		}
		acked = ti->ti_ack - tp->snd_una;

		/*
		 * If transmit timer is running and timed sequence
		 * number was acked, update smoothed round trip time.
		 * Since we now have an rtt measurement, cancel the
		 * timer backoff (cf., Phil Karn's retransmit alg.).
		 * Recompute the initial retransmit timer.
		 */
		if (tp->t_rtt && SEQ_GT(ti->ti_ack, tp->t_rtseq))
			tcp_xmit_timer(tp,tp->t_rtt);

		/*
		 * If all outstanding data is acked, stop retransmit
		 * timer and remember to restart (more output or persist).
		 * If there is more data to be acked, restart retransmit
		 * timer, using current (possibly backed-off) value.
		 */
		if (ti->ti_ack == tp->snd_max) {
			tp->t_timer[TCPT_REXMT] = 0;
			needoutput = 1;
		} else if (tp->t_timer[TCPT_PERSIST] == 0)
			tp->t_timer[TCPT_REXMT] = tp->t_rxtcur;
		/*
		 * When new data is acked, open the congestion window.
		 * If the window gives us less than ssthresh packets
		 * in flight, open exponentially (maxseg per packet).
		 * Otherwise open linearly: maxseg per window
		 * (maxseg^2 / cwnd per packet).
		 */
		{
		  register u_int cw = tp->snd_cwnd;
		  register u_int incr = tp->t_maxseg;

		  if (cw > tp->snd_ssthresh)
		    incr = incr * incr / cw;
		  tp->snd_cwnd = min(cw + incr, TCP_MAXWIN<<tp->snd_scale);
		}
		if (acked > so->so_snd.sb_cc) {
			tp->snd_wnd -= so->so_snd.sb_cc;
			sbdrop(&so->so_snd, (int )so->so_snd.sb_cc);
			ourfinisacked = 1;
		} else {
			sbdrop(&so->so_snd, acked);
			tp->snd_wnd -= acked;
			ourfinisacked = 0;
		}
		tp->snd_una = ti->ti_ack;
		if (SEQ_LT(tp->snd_nxt, tp->snd_una))
			tp->snd_nxt = tp->snd_una;

		switch (tp->t_state) {

		/*
		 * In FIN_WAIT_1 STATE in addition to the processing
		 * for the ESTABLISHED state if our FIN is now acknowledged
		 * then enter FIN_WAIT_2.
		 */
		case TCPS_FIN_WAIT_1:
			if (ourfinisacked) {
				/*
				 * If we can't receive any more
				 * data, then closing user can proceed.
				 * Starting the timer is contrary to the
				 * specification, but if we don't get a FIN
				 * we'll hang forever.
				 */
				if (so->so_state & SS_FCANTRCVMORE) {
					tp->t_timer[TCPT_2MSL] = TCP_MAXIDLE;
				}
				tp->t_state = TCPS_FIN_WAIT_2;
			}
			break;

	 	/*
		 * In CLOSING STATE in addition to the processing for
		 * the ESTABLISHED state if the ACK acknowledges our FIN
		 * then enter the TIME-WAIT state, otherwise ignore
		 * the segment.
		 */
		case TCPS_CLOSING:
			if (ourfinisacked) {
				tp->t_state = TCPS_TIME_WAIT;
				tcp_canceltimers(tp);
				tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			}
			break;

		/*
		 * In LAST_ACK, we may still be waiting for data to drain
		 * and/or to be acked, as well as for the ack of our FIN.
		 * If our FIN is now acknowledged, delete the TCB,
		 * enter the closed state and return.
		 */
		case TCPS_LAST_ACK:
			if (ourfinisacked) {
                                tcp_close(tp);
				goto drop;
			}
			break;

		/*
		 * In TIME_WAIT state the only thing that should arrive
		 * is a retransmission of the remote FIN.  Acknowledge
		 * it and restart the finack timer.
		 */
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			goto dropafterack;
		}
	} /* switch(tp->t_state) */

step6:
	/*
	 * Update window information.
	 * Don't look at window if no ACK: TAC's send garbage on first SYN.
	 */
	if ((tiflags & TH_ACK) &&
	    (SEQ_LT(tp->snd_wl1, ti->ti_seq) ||
	    (tp->snd_wl1 == ti->ti_seq && (SEQ_LT(tp->snd_wl2, ti->ti_ack) ||
	    (tp->snd_wl2 == ti->ti_ack && tiwin > tp->snd_wnd))))) {
		tp->snd_wnd = tiwin;
		tp->snd_wl1 = ti->ti_seq;
		tp->snd_wl2 = ti->ti_ack;
		if (tp->snd_wnd > tp->max_sndwnd)
			tp->max_sndwnd = tp->snd_wnd;
		needoutput = 1;
	}

	/*
	 * Process segments with URG.
	 */
	if ((tiflags & TH_URG) && ti->ti_urp &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
		/*
		 * This is a kludge, but if we receive and accept
		 * random urgent pointers, we'll crash in
		 * soreceive.  It's hard to imagine someone
		 * actually wanting to send this much urgent data.
		 */
		if (ti->ti_urp + so->so_rcv.sb_cc > so->so_rcv.sb_datalen) {
			ti->ti_urp = 0;
			tiflags &= ~TH_URG;
			goto dodata;
		}
		/*
		 * If this segment advances the known urgent pointer,
		 * then mark the data stream.  This should not happen
		 * in CLOSE_WAIT, CLOSING, LAST_ACK or TIME_WAIT STATES since
		 * a FIN has been received from the remote side.
		 * In these states we ignore the URG.
		 *
		 * According to RFC961 (Assigned Protocols),
		 * the urgent pointer points to the last octet
		 * of urgent data.  We continue, however,
		 * to consider it to indicate the first octet
		 * of data past the urgent section as the original
		 * spec states (in one of two places).
		 */
		if (SEQ_GT(ti->ti_seq+ti->ti_urp, tp->rcv_up)) {
			tp->rcv_up = ti->ti_seq + ti->ti_urp;
			so->so_urgc =  so->so_rcv.sb_cc +
				(tp->rcv_up - tp->rcv_nxt); /* -1; */
			tp->rcv_up = ti->ti_seq + ti->ti_urp;

		}
	} else
		/*
		 * If no out of band data is expected,
		 * pull receive urgent pointer along
		 * with the receive window.
		 */
		if (SEQ_GT(tp->rcv_nxt, tp->rcv_up))
			tp->rcv_up = tp->rcv_nxt;
dodata:

	/*
	 * Process the segment text, merging it into the TCP sequencing queue,
	 * and arranging for acknowledgment of receipt if necessary.
	 * This process logically involves adjusting tp->rcv_wnd as data
	 * is presented to the user (this happens in tcp_usrreq.c,
	 * case PRU_RCVD).  If a FIN has already been received on this
	 * connection then we just ignore the text.
	 */
	if ((ti->ti_len || (tiflags&TH_FIN)) &&
	    TCPS_HAVERCVDFIN(tp->t_state) == 0) {
		TCP_REASS(tp, ti, m, so, tiflags);
	} else {
		m_free(m);
		tiflags &= ~TH_FIN;
	}

	/*
	 * If FIN is received ACK the FIN and let the user know
	 * that the connection is closing.
	 */
	if (tiflags & TH_FIN) {
		if (TCPS_HAVERCVDFIN(tp->t_state) == 0) {
			/*
			 * If we receive a FIN we can't send more data,
			 * set it SS_FDRAIN
                         * Shutdown the socket if there is no rx data in the
			 * buffer.
			 * soread() is called on completion of shutdown() and
			 * will got to TCPS_LAST_ACK, and use tcp_output()
			 * to send the FIN.
			 */
			sofwdrain(so);

			tp->t_flags |= TF_ACKNOW;
			tp->rcv_nxt++;
		}
		switch (tp->t_state) {

	 	/*
		 * In SYN_RECEIVED and ESTABLISHED STATES
		 * enter the CLOSE_WAIT state.
		 */
		case TCPS_SYN_RECEIVED:
		case TCPS_ESTABLISHED:
		  if(so->so_emu == EMU_CTL)        /* no shutdown on socket */
		    tp->t_state = TCPS_LAST_ACK;
		  else
		    tp->t_state = TCPS_CLOSE_WAIT;
		  break;

	 	/*
		 * If still in FIN_WAIT_1 STATE FIN has not been acked so
		 * enter the CLOSING state.
		 */
		case TCPS_FIN_WAIT_1:
			tp->t_state = TCPS_CLOSING;
			break;

	 	/*
		 * In FIN_WAIT_2 state enter the TIME_WAIT state,
		 * starting the time-wait timer, turning off the other
		 * standard timers.
		 */
		case TCPS_FIN_WAIT_2:
			tp->t_state = TCPS_TIME_WAIT;
			tcp_canceltimers(tp);
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			break;

		/*
		 * In TIME_WAIT state restart the 2 MSL time_wait timer.
		 */
		case TCPS_TIME_WAIT:
			tp->t_timer[TCPT_2MSL] = 2 * TCPTV_MSL;
			break;
		}
	}

	/*
	 * If this is a small packet, then ACK now - with Nagel
	 *      congestion avoidance sender won't send more until
	 *      he gets an ACK.
	 *
	 * See above.
	 */
	if (ti->ti_len && (unsigned)ti->ti_len <= 5 &&
	    ((struct tcpiphdr_2 *)ti)->first_char == (char)27) {
		tp->t_flags |= TF_ACKNOW;
	}

	/*
	 * Return any desired output.
	 */
	if (needoutput || (tp->t_flags & TF_ACKNOW)) {
		(void) tcp_output(tp);
	}
	return;

dropafterack:
	/*
	 * Generate an ACK dropping incoming segment if it occupies
	 * sequence space, where the ACK reflects our state.
	 */
	if (tiflags & TH_RST)
		goto drop;
	m_freem(m);
	tp->t_flags |= TF_ACKNOW;
	(void) tcp_output(tp);
	return;

dropwithreset:
	/* reuses m if m!=NULL, m_free() unnecessary */
	if (tiflags & TH_ACK)
		tcp_respond(tp, ti, m, (tcp_seq)0, ti->ti_ack, TH_RST);
	else {
		if (tiflags & TH_SYN) ti->ti_len++;
		tcp_respond(tp, ti, m, ti->ti_seq+ti->ti_len, (tcp_seq)0,
		    TH_RST|TH_ACK);
	}

	return;

drop:
	/*
	 * Drop space held by incoming segment and return.
	 */
	m_free(m);

	return;
}
Example #28
0
int DOopen()
{
nwio_tcpconf_t tcpconf;
nwio_tcpcl_t tcpcopt;
char *tcp_device;
tcpport_t port;
int s;
struct hostent *hp;
struct servent *servent;

   if(linkopen) {
	printf("Use \"CLOSE\" to close the connection first.\n");
	return(0);
   }

   if(cmdargc < 2) {
	if(readline("Host: ", host, sizeof(host)) < 0)
		return(-1);
   } else
	strncpy(host, cmdargv[1], sizeof(host));

   if((servent = getservbyname("ftp", "tcp")) == (struct servent *)NULL) {
   	fprintf(stderr, "ftp: Could not find ftp tcp service\n");
   	port = htons(21);
   } else
	port = (tcpport_t)servent->s_port;

   hp = gethostbyname(host);
   if(hp == (struct hostent *)NULL) {
	hostip = (ipaddr_t)0;
	printf("Unresolved host %s\n", host);
	return(0);
   } else
	memcpy((char *) &hostip, (char *) hp->h_addr, hp->h_length);

   /* This HACK allows the server to establish data connections correctly */
   /* when using the loopback device to talk to ourselves */
#ifdef __NBSD_LIBC
   if((hostip & ntohl(0xFF000000)) == inet_addr("127.0.0.0"))
#else
   if((hostip & NTOHL(0xFF000000)) == inet_addr("127.0.0.0"))
#endif
	hostip = myip;

   if((tcp_device = getenv("TCP_DEVICE")) == NULL)
	tcp_device = "/dev/tcp";

   if((ftpcomm_fd = open(tcp_device, O_RDWR)) < 0) {
	perror("ftp: open error on tcp device");
	return(-1);
   }

   tcpconf.nwtc_flags = NWTC_LP_SEL | NWTC_SET_RA | NWTC_SET_RP;
   tcpconf.nwtc_remaddr = hostip;
   tcpconf.nwtc_remport = port;

   s = ioctl(ftpcomm_fd, NWIOSTCPCONF, &tcpconf);
   if(s < 0) {
	perror("ftp: ioctl error on NWIOSTCPCONF");
	close(ftpcomm_fd);
	return(-1);
   }

   tcpcopt.nwtcl_flags = 0;

   s = ioctl(ftpcomm_fd, NWIOTCPCONN, &tcpcopt);
   if(s < 0) {
	perror("ftp: ioctl error on NWIOTCPCONN");
	close(ftpcomm_fd);
	return(-1);
   }

   s = ioctl(ftpcomm_fd, NWIOGTCPCONF, &tcpconf);
   if(s < 0) {
	perror("ftp: ioctl error on NWIOGTCPCONF");
	close(ftpcomm_fd);
	return(-1);
   }

   s = DOgetreply();

   if(s < 0) {
	close(ftpcomm_fd);
	return(s);
   }

   if(s != 220) {
	close(ftpcomm_fd);
	return(0);
   }

   linkopen = 1;

   return(s);
}
/**
  Convert the IFR data into the network configuration data and set the IP
  configure parameters for the NIC.

  @param[in]       IfrFormNvData     The IFR NV data.
  @param[in, out]  Instance          The IP4 config2 instance.

  @retval EFI_SUCCESS            The configure parameter for this NIC was
                                 set successfully.
  @retval EFI_INVALID_PARAMETER  The address information for setting is invalid.
  @retval Others                 Other errors as indicated.

**/
EFI_STATUS
Ip4Config2ConvertIfrNvDataToConfigNvData (
  IN     IP4_CONFIG2_IFR_NVDATA     *IfrFormNvData,
  IN OUT IP4_CONFIG2_INSTANCE       *Instance
  )
{
  EFI_STATUS                       Status;
  EFI_IP4_CONFIG2_PROTOCOL         *Ip4Cfg2;
  IP4_CONFIG2_NVDATA               *Ip4NvData;

  EFI_IP_ADDRESS                   StationAddress;
  EFI_IP_ADDRESS                   SubnetMask;
  EFI_IP_ADDRESS                   Gateway;
  IP4_ADDR                         Ip;
  EFI_IPv4_ADDRESS                 *DnsAddress;
  UINTN                            DnsCount;
  UINTN                            Index;

  EFI_EVENT                        TimeoutEvent;
  EFI_EVENT                        SetAddressEvent;
  BOOLEAN                          IsAddressOk;
  UINTN                            DataSize;
  EFI_INPUT_KEY                    Key;

  Status          = EFI_SUCCESS;
  Ip4Cfg2         = &Instance->Ip4Config2;
  Ip4NvData       = &Instance->Ip4NvData;

  DnsCount        = 0;
  DnsAddress      = NULL;

  TimeoutEvent    = NULL;
  SetAddressEvent = NULL;



  if (Instance == NULL || IfrFormNvData == NULL) {
    return EFI_INVALID_PARAMETER;
  }

  if (IfrFormNvData->Configure != TRUE) {
    return EFI_SUCCESS;
  }

  if (IfrFormNvData->DhcpEnable == TRUE) {
    Ip4NvData->Policy = Ip4Config2PolicyDhcp;

    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypePolicy,
                        sizeof (EFI_IP4_CONFIG2_POLICY),
                        &Ip4NvData->Policy
                        );
    if (EFI_ERROR(Status)) {
      return Status;
    }
  } else {
    //
    // Get Ip4NvData from IfrFormNvData if it is valid.
    //
    Ip4NvData->Policy = Ip4Config2PolicyStatic;

    Status = Ip4Config2StrToIp (IfrFormNvData->SubnetMask, &SubnetMask.v4);
    if (EFI_ERROR (Status) || ((SubnetMask.Addr[0] != 0) && (GetSubnetMaskPrefixLength (&SubnetMask.v4) == 0))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Subnet Mask!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIp (IfrFormNvData->StationAddress, &StationAddress.v4);
    if (EFI_ERROR (Status) ||
        (SubnetMask.Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) ||
        !Ip4StationAddressValid (NTOHL (StationAddress.Addr[0]), NTOHL (SubnetMask.Addr[0]))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid IP address!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIp (IfrFormNvData->GatewayAddress, &Gateway.v4);
    if (EFI_ERROR (Status) ||
        (Gateway.Addr[0] != 0 && SubnetMask.Addr[0] != 0 && !NetIp4IsUnicast (NTOHL (Gateway.Addr[0]), NTOHL (SubnetMask.Addr[0])))) {
      CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Gateway!", NULL);
      return EFI_INVALID_PARAMETER;
    }

    Status = Ip4Config2StrToIpList (IfrFormNvData->DnsAddress, &DnsAddress, &DnsCount);
    if (!EFI_ERROR (Status) && DnsCount > 0) {
      for (Index = 0; Index < DnsCount; Index ++) {
        CopyMem (&Ip, &DnsAddress[Index], sizeof (IP4_ADDR));
        if (IP4_IS_UNSPECIFIED (NTOHL (Ip)) || IP4_IS_LOCAL_BROADCAST (NTOHL (Ip))) {
          CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
          FreePool(DnsAddress);
          return EFI_INVALID_PARAMETER;
        }
      }
    } else {
      if (EFI_ERROR (Status)) {
        CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, L"Invalid Dns Server!", NULL);
      }
    }

    if (Ip4NvData->ManualAddress != NULL) {
      FreePool(Ip4NvData->ManualAddress);
    }
    Ip4NvData->ManualAddressCount = 1;
    Ip4NvData->ManualAddress = AllocateZeroPool(sizeof(EFI_IP4_CONFIG2_MANUAL_ADDRESS));
    if (Ip4NvData->ManualAddress == NULL) {
      if (DnsAddress != NULL) {
        FreePool(DnsAddress);
      }

      return EFI_OUT_OF_RESOURCES;
    }
    CopyMem(&Ip4NvData->ManualAddress->Address, &StationAddress.v4, sizeof(EFI_IPv4_ADDRESS));
    CopyMem(&Ip4NvData->ManualAddress->SubnetMask, &SubnetMask.v4, sizeof(EFI_IPv4_ADDRESS));

    if (Ip4NvData->GatewayAddress != NULL) {
      FreePool(Ip4NvData->GatewayAddress);
    }
    Ip4NvData->GatewayAddressCount = 1;
    Ip4NvData->GatewayAddress = AllocateZeroPool(sizeof(EFI_IPv4_ADDRESS));
    if (Ip4NvData->GatewayAddress == NULL) {
      if (DnsAddress != NULL) {
        FreePool(DnsAddress);
      }
      return EFI_OUT_OF_RESOURCES;
    }
    CopyMem(Ip4NvData->GatewayAddress, &Gateway.v4, sizeof(EFI_IPv4_ADDRESS));

    if (Ip4NvData->DnsAddress != NULL) {
      FreePool(Ip4NvData->DnsAddress);
    }
    Ip4NvData->DnsAddressCount = (UINT32) DnsCount;
    Ip4NvData->DnsAddress      = DnsAddress;

    //
    // Setting Ip4NvData.
    //
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypePolicy,
                        sizeof (EFI_IP4_CONFIG2_POLICY),
                        &Ip4NvData->Policy
                        );
    if (EFI_ERROR(Status)) {
      return Status;
    }

    //
    // Create events & timers for asynchronous settings.
    //
    Status = gBS->CreateEvent (
                    EVT_TIMER,
                    TPL_CALLBACK,
                    NULL,
                    NULL,
                    &TimeoutEvent
                    );
    if (EFI_ERROR (Status)) {
      return EFI_OUT_OF_RESOURCES;
    }

    Status = gBS->CreateEvent (
                    EVT_NOTIFY_SIGNAL,
                    TPL_NOTIFY,
                    Ip4Config2ManualAddressNotify,
                    &IsAddressOk,
                    &SetAddressEvent
                    );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    IsAddressOk = FALSE;

    Status = Ip4Cfg2->RegisterDataNotify (
                        Ip4Cfg2,
                        Ip4Config2DataTypeManualAddress,
                        SetAddressEvent
                        );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set ManualAddress.
    //
    DataSize = Ip4NvData->ManualAddressCount * sizeof (EFI_IP4_CONFIG2_MANUAL_ADDRESS);
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypeManualAddress,
                        DataSize,
                        (VOID *) Ip4NvData->ManualAddress
                        );

    if (Status == EFI_NOT_READY) {
      gBS->SetTimer (TimeoutEvent, TimerRelative, 50000000);
      while (EFI_ERROR (gBS->CheckEvent (TimeoutEvent))) {
        if (IsAddressOk) {
          Status = EFI_SUCCESS;
          break;
        }
      }
    }

    Ip4Cfg2->UnregisterDataNotify (
               Ip4Cfg2,
               Ip4Config2DataTypeManualAddress,
               SetAddressEvent
               );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set gateway.
    //
    DataSize = Ip4NvData->GatewayAddressCount * sizeof (EFI_IPv4_ADDRESS);
    Status = Ip4Cfg2->SetData (
                        Ip4Cfg2,
                        Ip4Config2DataTypeGateway,
                        DataSize,
                        Ip4NvData->GatewayAddress
                        );
    if (EFI_ERROR (Status)) {
      goto Exit;
    }

    //
    // Set DNS addresses.
    //
    if (Ip4NvData->DnsAddressCount > 0 && Ip4NvData->DnsAddress != NULL) {
      DataSize = Ip4NvData->DnsAddressCount * sizeof (EFI_IPv4_ADDRESS);
      Status = Ip4Cfg2->SetData (
                          Ip4Cfg2,
                          Ip4Config2DataTypeDnsServer,
                          DataSize,
                          Ip4NvData->DnsAddress
                          );

      if (EFI_ERROR (Status)) {
        goto Exit;
      }
    }
  }

Exit:
  if (SetAddressEvent != NULL) {
    gBS->CloseEvent (SetAddressEvent);
  }

  if (TimeoutEvent != NULL) {
    gBS->CloseEvent (TimeoutEvent);
  }

  return Status;
}
Example #30
0
/**
  The event handle for UDP receive request.

  It will build a NET_BUF from the recieved UDP data, then deliver it
  to the receiver.

  @param[in]  Context               The UDP RX token.

**/
VOID
EFIAPI
UdpIoOnDgramRcvdDpc (
  IN VOID                   *Context
  )
{
  EFI_STATUS                Status;
  VOID                      *Token;
  VOID                      *RxData;
  VOID                      *Session;
  UDP_RX_TOKEN              *RxToken;
  UDP_END_POINT             EndPoint;
  NET_BUF                   *Netbuf;

  RxToken = (UDP_RX_TOKEN *) Context;

  ZeroMem (&EndPoint, sizeof(UDP_END_POINT));

  ASSERT ((RxToken->Signature == UDP_IO_RX_SIGNATURE) &&
          (RxToken == RxToken->UdpIo->RecvRequest));

  ASSERT ((RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) ||
          (RxToken->UdpIo->UdpVersion == UDP_IO_UDP6_VERSION));

  //
  // Clear the receive request first in case that the caller
  // wants to restart the receive in the callback.
  //
  RxToken->UdpIo->RecvRequest = NULL;

  if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    Token  = &RxToken->Token.Udp4;
    RxData = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Packet.RxData;
    Status = ((EFI_UDP4_COMPLETION_TOKEN *) Token)->Status;
  } else {
    Token  = &RxToken->Token.Udp6;
    RxData = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Packet.RxData;
    Status = ((EFI_UDP6_COMPLETION_TOKEN *) Token)->Status;
  }

  if (EFI_ERROR (Status) || RxData == NULL) {
    if (Status != EFI_ABORTED) {
      //
      // Invoke the CallBack only if the reception is not actively aborted.
      //
      RxToken->CallBack (NULL, NULL, Status, RxToken->Context);
    }

    UdpIoFreeRxToken (RxToken);
    return;
  }

  //
  // Build a NET_BUF from the UDP receive data, then deliver it up.
  //
  if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    if (((EFI_UDP4_RECEIVE_DATA *) RxData)->DataLength == 0) {
      //
      // Discard zero length data payload packet.
      //
      goto Resume;
    }

    Netbuf = NetbufFromExt (
               (NET_FRAGMENT *)((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentTable,
               ((EFI_UDP4_RECEIVE_DATA *) RxData)->FragmentCount,
               0,
               (UINT32) RxToken->HeadLen,
               UdpIoRecycleDgram,
               RxToken
               );

    if (Netbuf == NULL) {
      gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
      RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);

      UdpIoFreeRxToken (RxToken);
      return;
    }

    Session             = &((EFI_UDP4_RECEIVE_DATA *) RxData)->UdpSession;
    EndPoint.LocalPort  = ((EFI_UDP4_SESSION_DATA *) Session)->DestinationPort;
    EndPoint.RemotePort = ((EFI_UDP4_SESSION_DATA *) Session)->SourcePort;

    CopyMem (
      &EndPoint.LocalAddr,
      &((EFI_UDP4_SESSION_DATA *) Session)->DestinationAddress,
      sizeof (EFI_IPv4_ADDRESS)
      );

    CopyMem (
      &EndPoint.RemoteAddr,
      &((EFI_UDP4_SESSION_DATA *) Session)->SourceAddress,
      sizeof (EFI_IPv4_ADDRESS)
      );

    EndPoint.LocalAddr.Addr[0]  = NTOHL (EndPoint.LocalAddr.Addr[0]);
    EndPoint.RemoteAddr.Addr[0] = NTOHL (EndPoint.RemoteAddr.Addr[0]);
  } else {
    if (((EFI_UDP6_RECEIVE_DATA *) RxData)->DataLength == 0) {
      //
      // Discard zero length data payload packet.
      //
      goto Resume;
    }

    Netbuf = NetbufFromExt (
               (NET_FRAGMENT *)((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentTable,
               ((EFI_UDP6_RECEIVE_DATA *) RxData)->FragmentCount,
               0,
               (UINT32) RxToken->HeadLen,
               UdpIoRecycleDgram,
               RxToken
               );

    if (Netbuf == NULL) {
      gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
      RxToken->CallBack (NULL, NULL, EFI_OUT_OF_RESOURCES, RxToken->Context);

      UdpIoFreeRxToken (RxToken);
      return;
    }

    Session             = &((EFI_UDP6_RECEIVE_DATA *) RxData)->UdpSession;
    EndPoint.LocalPort  = ((EFI_UDP6_SESSION_DATA *) Session)->DestinationPort;
    EndPoint.RemotePort = ((EFI_UDP6_SESSION_DATA *) Session)->SourcePort;

    CopyMem (
      &EndPoint.LocalAddr,
      &((EFI_UDP6_SESSION_DATA *) Session)->DestinationAddress,
      sizeof (EFI_IPv6_ADDRESS)
      );

    CopyMem (
      &EndPoint.RemoteAddr,
      &((EFI_UDP6_SESSION_DATA *) Session)->SourceAddress,
      sizeof (EFI_IPv6_ADDRESS)
      );

    Ip6Swap128 (&EndPoint.LocalAddr.v6);
    Ip6Swap128 (&EndPoint.RemoteAddr.v6);
  }

  RxToken->CallBack (Netbuf, &EndPoint, EFI_SUCCESS, RxToken->Context);
  return;

Resume:
  if (RxToken->UdpIo->UdpVersion == UDP_IO_UDP4_VERSION) {
    gBS->SignalEvent (((EFI_UDP4_RECEIVE_DATA *) RxData)->RecycleSignal);
    RxToken->UdpIo->Protocol.Udp4->Receive (RxToken->UdpIo->Protocol.Udp4, &RxToken->Token.Udp4);
  } else {
    gBS->SignalEvent (((EFI_UDP6_RECEIVE_DATA *) RxData)->RecycleSignal);
    RxToken->UdpIo->Protocol.Udp6->Receive (RxToken->UdpIo->Protocol.Udp6, &RxToken->Token.Udp6);
  }
}