📄 kitleth.c
字号:
size = sizeof(g_kitlEthState.packet);
if (!g_kitlEthState.pfnRecv(g_kitlEthState.packet, &size)) continue;
KitlEthDecode(g_kitlEthState.packet, &size);
if (g_kitlEthState.dhcpState == DHCP_BOUND) break;
}
// If there was timeout try start DHCP againg with new transaction id
if (g_kitlEthState.dhcpState != DHCP_BOUND) {
g_kitlEthState.dhcpXId += 0x00080000;
continue;
}
// We get address, verify if it isn't used by somebody else...
SendARP(ARP_REQUEST, mac, g_kitlEthState.deviceIP);
startTime = OALGetTickCount();
while ((OALGetTickCount() - startTime) < ARP_TIMEOUT) {
size = sizeof(g_kitlEthState.packet);
if (g_kitlEthState.pfnRecv(g_kitlEthState.packet, &size)) {
if (GetOpARP(g_kitlEthState.packet, size) == ARP_RESPONSE) {
// Oops, somebody is using assigned address, decline...
SendDHCP(DHCP_DECLINE, g_kitlEthState.deviceIP);
g_kitlEthState.deviceIP = 0;
break;
}
}
}
// If we get with valid address we are done
if (g_kitlEthState.deviceIP != 0) break;
// Let try new DHCP transaction
g_kitlEthState.dhcpXId += 0x01080000;
}
cleanUp:
if(g_kitlEthState.deviceIP != 0)
KITL_RETAILMSG(ZONE_INIT, ("KITL: DHCP get/renew device IP: %s\r\n",
OALKitlIPtoString(g_kitlEthState.deviceIP)
));
}
//------------------------------------------------------------------------------
static VOID DecodeDHCP(UINT8* pFrame, UINT16 *pSize, BOOL *pUsed)
{
BOOTP_MESSAGE *pDHCP;
UINT8 *pOption, msgType;
UINT32 value;
BOOL rc;
// Be pesimistic
*pUsed = FALSE;
// Get pointers to BOOTP/DHCP message
pDHCP = (BOOTP_MESSAGE*)(
pFrame + sizeof(ETH_HEADER) + sizeof(IP4_HEADER) + sizeof(UDP_HEADER)
);
// Check magic DHCP cookie & transaction id
if (
pDHCP->options[0] != 0x63 || pDHCP->options[1] != 0x82 ||
pDHCP->options[2] != 0x53 || pDHCP->options[3] != 0x63 ||
pDHCP->xid != g_kitlEthState.dhcpXId
) goto cleanUp;
// This is our DHCP transaction
*pUsed = TRUE;
// Then find DHCP message type
pOption = FindDHCPOption(pDHCP, DHCP_MSGTYPE);
if (pOption == NULL) return;
msgType = pOption[2];
// Message processing depend on DHCP client state
switch (g_kitlEthState.dhcpState) {
case DHCP_SELECTING:
// Ignore anything other then offer
if (msgType != DHCP_OFFER) break;
// Find server IP address
pOption = FindDHCPOption(pDHCP, DHCP_SERVER_ID);
if (pOption == NULL) break;
memcpy(&g_kitlEthState.dhcpServerIP, &pOption[2], sizeof(UINT32));
// Request offered IP address
SendDHCP(DHCP_REQUEST, pDHCP->yiaddr);
// We moved to new state
g_kitlEthState.dhcpState = DHCP_REQUESTING;
break;
case DHCP_REQUESTING:
if (msgType == DHCP_ACK) {
// Set assigned address
g_kitlEthState.deviceIP = pDHCP->yiaddr;
// Find renew period & set timer callback
pOption = FindDHCPOption(pDHCP, DHCP_RENEW_TIME);
if (pOption != NULL) {
memcpy(&value, &pOption[2], sizeof(UINT32));
rc = KitlSetTimerCallback(ntohl(value), RenewDHCP, NULL);
} else {
// If there isn't renew period select 30 minutes
KitlSetTimerCallback(30*60, RenewDHCP, NULL);
}
// We get address, let check it...
g_kitlEthState.dhcpState = DHCP_BOUND;
} else if (msgType == DHCP_NAK) {
g_kitlEthState.deviceIP = 0;
// Discover DHCP servers
SendDHCP(DHCP_DISCOVER, 0);
// Start with discover again
g_kitlEthState.dhcpState = DHCP_SELECTING;
}
break;
}
cleanUp:
return;
}
//------------------------------------------------------------------------------
static VOID DecodeICMP(UINT8 *pFrame, UINT16 length, BOOL *pUsed)
{
ETH_HEADER *pEth = (ETH_HEADER*)pFrame;
IP4_HEADER *pIP = (IP4_HEADER*)((UINT8*)pEth + sizeof(ETH_HEADER));
ICMP_HEADER *pICMP = (ICMP_HEADER*)((UINT8*)pIP + sizeof(IP4_HEADER));
UINT16 icmpLength;
// Be pesimistic
*pUsed = FALSE;
// Get ICMP message size & verify checksum
icmpLength = ntohs(pIP->length) - sizeof(IP4_HEADER);
if (Sum(0, pICMP, icmpLength) != 0xFFFF) goto cleanUp;
// Reply to ping only
if (pICMP->op != ICMP_ECHOREQ) goto cleanUp;
// We now know that packet is used
*pUsed = TRUE;
// Encode reply & do checksum
pICMP->op = 0;
pICMP->code = 0;
pICMP->sum = 0;
pICMP->sum = ~ Sum(0, pICMP, icmpLength);
// Add IP header
EncodeIP(
pFrame, icmpLength, pEth->srcmac, pIP->destip, pIP->srcip, ICMP_PROTOCOL
);
// Send packet
g_kitlEthState.pfnSend(pFrame, length);
cleanUp:
return;
}
//------------------------------------------------------------------------------
static UINT8* DecodeUDP(UINT8 *pFrame, UINT16 *pLength, BOOL *pUsed)
{
UINT8 *pData = NULL;
ETH_HEADER *pEth = (ETH_HEADER*)pFrame;
IP4_HEADER *pIP = (IP4_HEADER*)((UINT8*)pEth + sizeof(ETH_HEADER));
UDP_HEADER *pUDP = (UDP_HEADER*)((UINT8*)pIP + sizeof(IP4_HEADER));
UINT16 xsum;
UINT32 ipLength, udpLength;
// Be pesimistic
*pUsed = FALSE;
// Get IP and UDP lengths from packet
ipLength = ntohs(pIP->length);
udpLength = ntohs(pUDP->length);
// UPD length must be in sync with IP length
if (ipLength < sizeof(IP4_HEADER) + udpLength) goto cleanUp;
// Verify UDP header checksum
if (pUDP->sum != 0) {
xsum = htons(UDP_PROTOCOL);
xsum = Sum(xsum, &pIP->srcip, sizeof(UINT32));
xsum = Sum(xsum, &pIP->destip, sizeof(UINT32));
xsum = Sum(xsum, &pUDP->length, sizeof(UINT32));
xsum = Sum(xsum, pUDP, udpLength);
if (xsum != pUDP->sum) goto cleanUp;
}
switch (ntohs(pUDP->dstPort)) {
case DHCP_CLIENT_PORT:
DecodeDHCP(pFrame, pLength, pUsed);
break;
case KITL_CLIENT_PORT:
// Message must be for us and client must have an address
if (
g_kitlEthState.deviceIP != pIP->destip ||
g_kitlEthState.deviceIP == 0
) break;
// Initialize KITL server address
if (g_kitlEthState.kitlServerIP == 0xFFFFFFFF) {
memcpy(
g_kitlEthState.kitlServerMAC, pEth->srcmac,
sizeof(g_kitlEthState.kitlServerMAC)
);
g_kitlEthState.kitlServerIP = pIP->srcip;
g_kitlEthState.kitlServerPort = pUDP->srcPort;
KITL_RETAILMSG(ZONE_INIT, (
"KITL: Connected host IP: %s Port: %d\r\n",
OALKitlIPtoString(g_kitlEthState.kitlServerIP),
ntohs(g_kitlEthState.kitlServerPort)
));
}
*pUsed = TRUE;
pData = (UINT8*)pUDP + sizeof(UDP_HEADER);
*pLength = udpLength - sizeof(UDP_HEADER);
break;
}
cleanUp:
return pData;
}
//------------------------------------------------------------------------------
UINT8* DecodeIP(UINT8 *pFrame, UINT16 *pLength, BOOL *pUsed)
{
UINT8 *pData = NULL;
ETH_HEADER *pEth = (ETH_HEADER*)pFrame;
IP4_HEADER *pIP = (IP4_HEADER*)((UINT8*)pEth + sizeof(ETH_HEADER));
// Be pesimistic
*pUsed = FALSE;
// We support only IP4 with standard IP4 header (no options...)
if (pIP->verlen != 0x45) goto cleanUp;
// First check if packet is for us
if (
pIP->destip != g_kitlEthState.deviceIP &&
pIP->destip != 0xFFFFFFFF &&
g_kitlEthState.deviceIP != 0
) goto cleanUp;
// Verify IP4 header checksum
if (Sum(0, pIP, sizeof(IP4_HEADER)) != 0xFFFF) goto cleanUp;
// Then decode protocol
switch (pIP->protocol) {
case UDP_PROTOCOL:
pData = DecodeUDP(pFrame, pLength, pUsed);
break;
case ICMP_PROTOCOL:
DecodeICMP(pFrame, *pLength, pUsed);
break;
}
cleanUp:
return pData;
}
//------------------------------------------------------------------------------
//
// Function: KitlEthDecode
//
// This function is called by KITL to decode data for transport. For KITL
// ethernet it means process packet if it belongs to any supporting protocol
// (currently ARP, ICMP and DHCP) and send any reply packet. For KITL packets
// function returns (after checksums pass) pointer to data and its size.
// For any other packet function return NULL.
//
static UINT8* KitlEthDecode(UINT8 *pFrame, UINT16 *pLength)
{
ETH_HEADER *pEth = (ETH_HEADER*)pFrame;
UINT8 *pData = NULL;
BOOL used = FALSE;
KITL_RETAILMSG(ZONE_RECV, (
"+KitlEthDecode(0x%08x, 0x%08x->%d)\r\n", pFrame, pLength, *pLength
));
// Process received packet
switch (ntohs(pEth->ftype)) {
case ARP_FRAME:
DecodeARP(pFrame, *pLength, &used);
break;
case IP_FRAME:
pData = DecodeIP(pFrame, pLength, &used);
break;
}
// If packet wasn't used, indicate it to VMINI
if (!used && (g_kitlEthState.flags & OAL_KITL_FLAGS_VMINI) != 0) {
VBridgeKIndicateOneRxBuffer(pFrame, *pLength, FALSE, &used);
}
KITL_RETAILMSG(ZONE_RECV, (
"-KitlEthDecode(pData = 0x%08x, length = %d)\r\n", pData, *pLength
));
return pData;
}
//------------------------------------------------------------------------------
//
// Function: KitlEthEncode
//
// This function is called by KITL to encode data for transport. For KITL
// ethernet it means adding MAC/IP4/UDP headers and checksums.
//
static BOOL KitlEthEncode(UINT8 *pFrame, UINT16 length)
{
KITL_RETAILMSG(ZONE_SEND, (
"+KitlEthEncode(%08x, %d)\r\n", pFrame, length
));
// Encode packets
EncodeUDP(
pFrame, length,
g_kitlEthState.kitlServerMAC, g_kitlEthState.deviceIP,
g_kitlEthState.kitlServerIP, htons(KITL_CLIENT_PORT),
g_kitlEthState.kitlServerPort
);
KITL_RETAILMSG(ZONE_SEND, ("-KitlEthEncode(rc = 1)\r\n"));
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: KitlEthGetFrameHdrSize
//
// This function is called by KITL to get information about transport header
// size. It allows to allocate packet structure with room for it.
//
static UCHAR KitlEthGetFrameHdrSize()
{
return sizeof(ETH_HEADER) + sizeof(IP4_HEADER) + sizeof(UDP_HEADER);
}
//------------------------------------------------------------------------------
//
// Function: KitlEthSetHostCfg
//
// This function is called by KITL to with information sent by host in
// negotiation. There is nothing useful for KITL on Ethernet.
//
static BOOL KitlEthSetHostCfg(UINT8 *pData, UINT16 size)
{
return TRUE;
}
//------------------------------------------------------------------------------
//
// Function: KitlEthGetDevCfg
//
// This function is called by KITL to get information about transport layer.
// For ethernet device should return its IP address, MAC address and UDP port.
//
static BOOL KitlEthGetDevCfg(UINT8 *pData, UINT16 *pSize)
{
BOOL rc = FALSE;
UINT16 port = htons(KITL_CLIENT_PORT);
KITL_RETAILMSG(ZONE_KITL_OAL, (
"+KitlEthGetDevCfg(0x%08x, 0x%08x->%d)\r\n", pData, pSize, *pSize
));
// Is there space in buffer?
if (*pSize < (sizeof(UINT32) + 4 * sizeof(UINT16))) goto cleanUp;
*pSize = 0;
memcpy(pData, &g_kitlEthState.deviceIP, sizeof(UINT32));
pData += sizeof(UINT32);
*pSize += sizeof(UINT32);
memcpy(pData, g_kitlEthState.deviceMAC, 3*sizeof(UINT16));
pData += 3*sizeof(UINT16);
*pSize += 3*sizeof(UINT16);
memcpy(pData, &port, sizeof(UINT16));
pData += sizeof(UINT16);
*pSize += sizeof(UINT16);
// We are done
rc = TRUE;
cleanUp:
KITL_RETAILMSG(ZONE_KITL_OAL, ("-KitlEthGetDevCfg(rc = %d)\r\n", rc));
return rc;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -