/******************************************************************************* | |
* (c) Copyright 2009 Actel Corporation,All Rights Reserved. | |
* | |
* tcpip.c:TCP/IP implementation for webserver. | |
*/ | |
#include "../port_config/cpu_types.h" | |
#include "nettype.h" | |
#include "../mss_ethernet_mac/mss_ethernet_mac.h" | |
#include "../mss_ethernet_mac/mss_ethernet_mac_regs.h" | |
#include "tcpip.h" | |
#include <string.h> | |
#include <stdio.h> | |
#include <math.h> | |
#define OK 0 | |
#define ERR 1 | |
#define MAC_BASE_ADDRESS 0x40003000 | |
extern char ethAddr[6]; | |
unsigned char my_ip[IP_ADDR_LEN]={192,168,0,14}; | |
unsigned char my_mac[ETH_ADDR_LEN]={0xAA,0xBB,0xCC,0x11,0x22,0x33}; | |
unsigned char tcp_packet[1532]; | |
unsigned char ip_known; | |
unsigned char dhcp_ip_found; | |
unsigned short int ip_id; | |
unsigned char selected_mode = 0; | |
unsigned char selectedwaveform = 0; | |
unsigned char rtc_count[5]={0,0,0,0,0}; | |
unsigned char rtc_match_count[5]={0,5,0,0,0}; | |
unsigned char get_count[5]; | |
unsigned int num_pkt_tx = 0,num_pkt_rx = 0; | |
#define TCP_START_SEQ 0x10203040 | |
static const unsigned char g_client_ip[IP_ADDR_LEN] = { 192, 168, 1, 10 }; | |
unsigned char oled_string[20]; | |
tcp_control_block_t tcb; | |
MAC_instance_t g_mac; | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char send_arp_reply(unsigned char *buf) | |
{ | |
/* Modify the packet in place */ | |
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t)); | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf; | |
memcpy(eth_hdr->da, eth_hdr->sa, ETH_ADDR_LEN); | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
arp_pkt->opcode[1] = ARP_OPCODE_REPLY_1; | |
memcpy(arp_pkt->mac_ta, arp_pkt->mac_sa, ETH_ADDR_LEN); | |
memcpy(arp_pkt->ip_ta, arp_pkt->ip_sa, IP_ADDR_LEN); | |
memcpy(arp_pkt->mac_sa, my_mac, ETH_ADDR_LEN); | |
memcpy(arp_pkt->ip_sa, my_ip, IP_ADDR_LEN); | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(buf,42, MSS_MAC_BLOCKING); | |
return OK; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
void send_gratuitous_arp(unsigned char *buf) | |
{ | |
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t)); | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf; | |
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */ | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
eth_hdr->type_code[0] = ETH_TYPE_0; | |
eth_hdr->type_code[1] = ETH_TYPE_ARP_1; | |
arp_pkt->hw_type[0] = ARP_HW_TYPE_0; | |
arp_pkt->hw_type[1] = ARP_HW_TYPE_1; | |
arp_pkt->proto_type[0] = ETH_TYPE_0; | |
arp_pkt->proto_type[1] = ETH_TYPE_IP_1; | |
arp_pkt->hw_addr_len = ETH_ADDR_LEN; | |
arp_pkt->proto_addr_len = IP_ADDR_LEN; | |
arp_pkt->opcode[0] = ARP_OPCODE_0; | |
arp_pkt->opcode[1] = ARP_OPCODE_REQ_1; | |
memcpy(arp_pkt->mac_sa, my_mac, ETH_ADDR_LEN); | |
memcpy(arp_pkt->ip_sa, my_ip, IP_ADDR_LEN); | |
memset(arp_pkt->mac_ta, 0x00, ETH_ADDR_LEN); | |
memcpy(arp_pkt->ip_ta, my_ip, IP_ADDR_LEN); | |
//mac_tx_send(buf,42,0); | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(buf,42, MSS_MAC_BLOCKING); | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
* | |
*/ | |
unsigned short int get_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos) | |
{ | |
unsigned int sum; /* our accumulated sum */ | |
unsigned short int delta; /* the next 16-bit quantity to add */ | |
unsigned short int i; | |
unsigned short int ilen; | |
sum = (unsigned int) 0; | |
ilen=(len&1)?len-1:len; | |
for (i = 0; i < ilen; i += 2) { | |
if (i == pos) continue; | |
delta = (unsigned short int)buf[i+1] + (unsigned short int)((unsigned short int)buf[i] << 8); | |
sum += delta; | |
if (sum & (unsigned int) 0x10000) { /* if there's a carry... */ | |
sum &= 0xffff; /* get rid of the carry bit */ | |
sum++; /* and move it down here */ | |
} | |
} | |
if ( len & 1) { | |
delta = (unsigned short int)((unsigned short int)buf[i] << 8); | |
sum += delta; | |
if (sum & (unsigned int) 0x10000) { /* if there's a carry... */ | |
sum &= 0xffff; /* get rid of the carry bit */ | |
sum++; /* and move it down here */ | |
} | |
} | |
sum = ~sum; | |
return sum; | |
} //end calc_checksum | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char fix_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos) | |
{ | |
unsigned short int sum = get_checksum(buf,len,pos); | |
buf[pos] = (unsigned char)(sum >> 8); | |
buf[pos+1] = (unsigned char)sum; | |
return OK; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char check_checksum(unsigned char *buf, unsigned short int len, unsigned short int pos, char type) | |
{ | |
unsigned short int sum = get_checksum(buf,len,pos); | |
if ((buf[pos] != (unsigned char)(sum >> 8)) || | |
(buf[pos+1] != (unsigned char) sum)) { | |
type = 0; /* get around compiler warning */ | |
return ERR; | |
} else { | |
return OK; | |
} | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char send_icmp_echo_reply(unsigned char *buf) | |
{ | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) buf; | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t)); | |
icmp_hdr_xp icmp_hdr = (icmp_hdr_xp ) | |
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t)); | |
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t); | |
memcpy(eth_hdr->da, eth_hdr->sa, ETH_ADDR_LEN); | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
memcpy(ip_hdr->da, ip_hdr->sa, IP_ADDR_LEN); | |
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN); | |
ip_hdr->ttl--; | |
fix_checksum((unsigned char *)ip_hdr, (unsigned short int) 20, (unsigned short int) 10); | |
icmp_hdr->type = ICMP_TYPE_ECHO_REPLY; | |
if (elen & 1) { | |
((unsigned char *)icmp_hdr)[elen] = 0; | |
} | |
fix_checksum((unsigned char *)icmp_hdr, (unsigned short int) elen, (unsigned short int) 2); | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(buf,elen + sizeof(ether_hdr_t) + sizeof(ip_hdr_t), MSS_MAC_BLOCKING); | |
return OK; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
void dtoa_reverse(unsigned short int n, unsigned char *buf) | |
{ | |
buf--; | |
if (n == 0) { | |
*buf = '0'; | |
return; | |
} | |
while (n > 0) { | |
*buf-- = (n % 10) + '0'; | |
n = n / 10; | |
} | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
void send_bootp_packet (unsigned char *buf) | |
{ | |
/* output packet */ | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet; | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t)); | |
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
bootp_pkt_xp bootp_pkt = (bootp_pkt_xp )((unsigned char *)udp_hdr + sizeof(udp_hdr_t)); | |
unsigned char *opts = bootp_pkt->vend; | |
/* input packet */ | |
// eth_hdr_xp ieth_hdr = (eth_hdr_xp ) buf; | |
// ip_hdr_xp iip_hdr = (ip_hdr_xp ) (buf + sizeof(ether_hdr_t)); | |
udp_hdr_xp iudp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
bootp_pkt_xp ibootp_pkt = (bootp_pkt_xp )((unsigned char *)iudp_hdr + sizeof(udp_hdr_t)); | |
unsigned short int plen; | |
/* Set up Bootp */ | |
memset(bootp_pkt, 0, sizeof(bootp_pkt_t)); | |
bootp_pkt->op = BOOTP_OP_REQUEST; | |
bootp_pkt->hwtype = BOOTP_HWTYPE_ETH; | |
bootp_pkt->hlen = ETH_ADDR_LEN; | |
bootp_pkt->secs[1] = 0x64; | |
memcpy(bootp_pkt->chaddr, my_mac, ETH_ADDR_LEN); | |
bootp_pkt->flags[0] = 0x80; /* ask for a broadcast */ | |
if (buf) { | |
if (memcmp(my_mac, ibootp_pkt->chaddr, ETH_ADDR_LEN)) /* not for me ignore */ | |
return; | |
memcpy(my_ip, ibootp_pkt->yiaddr, IP_ADDR_LEN); | |
ip_known = 1; | |
dhcp_ip_found = 1; | |
memcpy(bootp_pkt->ciaddr, ibootp_pkt->yiaddr, IP_ADDR_LEN); | |
memcpy(bootp_pkt->xid, ibootp_pkt->xid, BOOTP_XID_LEN); | |
} else { | |
bootp_pkt->xid[0] = 0x90; | |
} | |
*opts++ = 99; /* magic number */ | |
*opts++ = 130; | |
*opts++ = 83; | |
*opts++ = 99; | |
*opts++ = BOOTP_OPTCODE_DHCP_TYPE; | |
*opts++ = 1; | |
if (buf) { | |
*opts++ = DHCP_TYPE_REQUEST; | |
*opts++ = BOOTP_OPTCODE_DHCP_SID; | |
*opts++ = 4; | |
*opts++ = ibootp_pkt->siaddr[0]; | |
*opts++ = ibootp_pkt->siaddr[1]; | |
*opts++ = ibootp_pkt->siaddr[2]; | |
*opts++ = ibootp_pkt->siaddr[3]; | |
} else { | |
*opts++ = DHCP_TYPE_DISCOVER; | |
} | |
*opts++ = BOOTP_OPTCODE_END; | |
/* Set up Udp */ | |
memset(udp_hdr, 0, sizeof(udp_hdr_t)); | |
udp_hdr->sp[1] = BOOTP_CLIENT_PORT; | |
udp_hdr->dp[1] = BOOTP_SERVER_PORT; | |
plen = sizeof(udp_hdr_t) + sizeof(bootp_pkt_t); | |
udp_hdr->len[0] = plen >> 8; | |
udp_hdr->len[1] = (unsigned char) plen; | |
/* leave csum 0 */ | |
/* Set up IP */ | |
memset(ip_hdr, 0, sizeof(ip_hdr_t)); | |
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */ | |
plen += sizeof(ip_hdr_t); | |
ip_hdr->tlen[0] = plen >> 8; | |
ip_hdr->tlen[1] = (unsigned char) plen; | |
ip_hdr->id[0] = ip_id >> 8; | |
ip_hdr->id[1] = (unsigned char) ip_id; | |
ip_id++; | |
ip_hdr->ttl = 32; /* max 32 hops */ | |
ip_hdr->proto = UDP_PROTO; | |
memset(ip_hdr->da, 0xFF, IP_ADDR_LEN); | |
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10); | |
/* Set up Ethernet */ | |
eth_hdr->type_code[0] = ETH_TYPE_0; | |
eth_hdr->type_code[1] = ETH_TYPE_IP_1; | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */ | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING); | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
void send_dhcp_server_packet (unsigned char *buf) | |
{ | |
unsigned char * tcp_packet = tcp_packet; | |
/* output packet */ | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet; | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t)); | |
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
bootp_pkt_xp bootp_pkt = (bootp_pkt_xp )((unsigned char *)udp_hdr + sizeof(udp_hdr_t)); | |
unsigned char *opts = bootp_pkt->vend; | |
/* input packet */ | |
eth_hdr_xp ieth_hdr = (eth_hdr_xp ) buf; | |
// ip_hdr_xp iip_hdr = (ip_hdr_xp ) (buf + sizeof(ether_hdr_t)); | |
udp_hdr_xp iudp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
bootp_pkt_xp ibootp_pkt = (bootp_pkt_xp )((unsigned char *)iudp_hdr + sizeof(udp_hdr_t)); | |
unsigned char *iopts = ibootp_pkt->vend; | |
unsigned short int plen; | |
/* Set up Bootp */ | |
memset(bootp_pkt, 0, sizeof(bootp_pkt_t)); | |
bootp_pkt->op = BOOTP_OP_REPLY; | |
bootp_pkt->hwtype = BOOTP_HWTYPE_ETH; | |
bootp_pkt->hlen = ETH_ADDR_LEN; | |
bootp_pkt->secs[1] = 0x64; | |
memcpy(bootp_pkt->chaddr, ieth_hdr->sa, ETH_ADDR_LEN); | |
bootp_pkt->flags[0] = 0x00; | |
if (buf) { | |
memcpy(bootp_pkt->ciaddr, ibootp_pkt->yiaddr, IP_ADDR_LEN); | |
memcpy(bootp_pkt->yiaddr, g_client_ip, IP_ADDR_LEN); | |
memcpy(bootp_pkt->xid, ibootp_pkt->xid, BOOTP_XID_LEN); | |
} else { | |
bootp_pkt->xid[0] = 0x90; | |
} | |
*opts++ = 99; /* magic number */ | |
*opts++ = 130; | |
*opts++ = 83; | |
*opts++ = 99; | |
*opts++ = BOOTP_OPTCODE_DHCP_TYPE; | |
*opts++ = 1; | |
if (iopts[6] == DHCP_TYPE_DISCOVER) | |
{ | |
*opts++ = DHCP_TYPE_OFFER; | |
} | |
else | |
{ | |
*opts++ = DHCP_TYPE_ACK; | |
} | |
/* Server ID */ | |
*opts++ = BOOTP_OPTCODE_DHCP_SID; | |
*opts++ = 4; | |
*opts++ = my_ip[0]; | |
*opts++ = my_ip[1]; | |
*opts++ = my_ip[2]; | |
*opts++ = my_ip[3]; | |
/* Lease time (1 our) */ | |
*opts++ = BOOTP_OPTCODE_DHCP_LEASE; | |
*opts++ = 4; | |
*opts++ = 0x00; | |
*opts++ = 0x00; | |
*opts++ = 0x0E; | |
*opts++ = 0x10; | |
/* Renewal time */ | |
*opts++ = BOOTP_OPTCODE_DHCP_RENEW; | |
*opts++ = 4; | |
*opts++ = 0x00; | |
*opts++ = 0x00; | |
*opts++ = 0x07; | |
*opts++ = 0x08; | |
/* Rebinding time */ | |
*opts++ = BOOTP_OPTCODE_DHCP_REBIND; | |
*opts++ = 4; | |
*opts++ = 0x00; | |
*opts++ = 0x00; | |
*opts++ = 0x0C; | |
*opts++ = 0x4E; | |
/* Subnet mask */ | |
*opts++ = BOOTP_OPTCODE_DHCP_SUBNET; | |
*opts++ = 4; | |
*opts++ = 0xFF; | |
*opts++ = 0xFF; | |
*opts++ = 0xFF; | |
*opts++ = 0x00; | |
/* Router */ | |
*opts++ = BOOTP_OPTCODE_DHCP_ROUTER; | |
*opts++ = 4; | |
*opts++ = my_ip[0]; | |
*opts++ = my_ip[1]; | |
*opts++ = my_ip[2]; | |
*opts++ = my_ip[3]; | |
/* Domain */ | |
*opts++ = BOOTP_OPTCODE_DHCP_DOMAIN; | |
*opts++ = 4; | |
*opts++ = my_ip[0]; | |
*opts++ = my_ip[1]; | |
*opts++ = my_ip[2]; | |
*opts++ = my_ip[3]; | |
*opts++ = BOOTP_OPTCODE_END; | |
/* Set up Udp */ | |
memset(udp_hdr, 0, sizeof(udp_hdr_t)); | |
udp_hdr->sp[1] = BOOTP_SERVER_PORT; | |
udp_hdr->dp[1] = BOOTP_CLIENT_PORT; | |
plen = sizeof(udp_hdr_t) + sizeof(bootp_pkt_t); | |
udp_hdr->len[0] = plen >> 8; | |
udp_hdr->len[1] = (unsigned char) plen; | |
/* leave csum 0 */ | |
/* Set up IP */ | |
memset(ip_hdr, 0, sizeof(ip_hdr_t)); | |
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */ | |
plen += sizeof(ip_hdr_t); | |
ip_hdr->tlen[0] = plen >> 8; | |
ip_hdr->tlen[1] = (unsigned char) plen; | |
ip_hdr->id[0] = ip_id >> 8; | |
ip_hdr->id[1] = (unsigned char) ip_id; | |
ip_id++; | |
ip_hdr->ttl = 255; | |
ip_hdr->proto = UDP_PROTO; | |
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN); | |
memset(ip_hdr->da, 0xFF, IP_ADDR_LEN); | |
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10); | |
/* Set up Ethernet */ | |
eth_hdr->type_code[0] = ETH_TYPE_0; | |
eth_hdr->type_code[1] = ETH_TYPE_IP_1; | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
memset(eth_hdr->da, 0xFF, ETH_ADDR_LEN); /* broadcast */ | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING); | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_udp_packet (unsigned char *buf) | |
{ | |
udp_hdr_xp udp_hdr = (udp_hdr_xp ) (buf + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
if (udp_hdr->dp[1] != BOOTP_CLIENT_PORT) { | |
send_dhcp_server_packet( buf ); | |
return OK; | |
} | |
if (ip_known) { | |
return ERR; | |
} | |
/* some more error checking here? */ | |
send_bootp_packet(buf); | |
return OK; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
void send_tcp_packet (unsigned char control_bits,unsigned short int buflen) | |
{ | |
eth_hdr_xp eth_hdr = (eth_hdr_xp ) tcp_packet; | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (tcp_packet + sizeof(ether_hdr_t)); | |
tcp_hdr_xp tcp_hdr = (tcp_hdr_xp ) | |
(tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t)); | |
tcp_pseudo_hdr_xp tcp_pseudo_hdr = (tcp_pseudo_hdr_xp ) | |
(((unsigned char *)tcp_hdr) - sizeof(tcp_pseudo_hdr_t)); | |
unsigned char *tcp_data = tcp_packet + sizeof(ether_hdr_t) + sizeof(ip_hdr_t) + sizeof (tcp_hdr_t); | |
unsigned char *seqp = (unsigned char *)(&tcb.local_seq); | |
unsigned short int plen; | |
memset(tcp_hdr, 0, sizeof(tcp_hdr_t)); | |
memcpy(tcp_hdr->sp, tcb.local_port, TCP_PORT_LEN); | |
memcpy(tcp_hdr->dp, tcb.remote_port, TCP_PORT_LEN); | |
tcp_hdr->seqnum[0] = seqp[3]; | |
tcp_hdr->seqnum[1] = seqp[2]; | |
tcp_hdr->seqnum[2] = seqp[1]; | |
tcp_hdr->seqnum[3] = seqp[0]; | |
tcb.local_seq++; | |
if (buflen) { | |
tcb.local_seq += buflen - 1; | |
} | |
if (control_bits & TCP_CNTRL_ACK) { | |
seqp = (unsigned char *)(&tcb.remote_seq); | |
tcp_hdr->acknum[3] = seqp[0]; | |
tcp_hdr->acknum[2] = seqp[1]; | |
tcp_hdr->acknum[1] = seqp[2]; | |
tcp_hdr->acknum[0] = seqp[3]; | |
} | |
tcp_hdr->data_off = 0x50; /* always 5 32 bit words for us */ | |
tcp_hdr->urg_ack_psh_rst_syn_fin = control_bits; | |
tcp_hdr->wsize[0] = 0x08; /* this is 0x0800, which is 2K */ | |
if (buflen & 1) { | |
tcp_data[buflen] = 0; | |
} | |
/* memset(tcp_pseudo_hdr, 0, sizeof(tcp_pseudo_hdr_t)); */ | |
memcpy(tcp_pseudo_hdr->sa, my_ip, IP_ADDR_LEN); | |
memcpy(tcp_pseudo_hdr->da, tcb.remote_addr, IP_ADDR_LEN); | |
tcp_pseudo_hdr->zero = 0; | |
tcp_pseudo_hdr->proto = TCP_PROTO; | |
plen = buflen + sizeof(tcp_hdr_t); | |
tcp_pseudo_hdr->plen[0] = plen >> 8; | |
tcp_pseudo_hdr->plen[1] = (unsigned char)plen; | |
fix_checksum((unsigned char *)tcp_pseudo_hdr, | |
(unsigned short int)(plen + sizeof(tcp_pseudo_hdr_t)), (unsigned short int)28); | |
memset(ip_hdr, 0, sizeof(ip_hdr_t)); | |
ip_hdr->ver_hlen = 0x45; /* IPv4 with 20 byte header */ | |
plen += sizeof(ip_hdr_t); /* add the size of the IP Header */ | |
ip_hdr->tlen[0] = plen >> 8; | |
ip_hdr->tlen[1] = (unsigned char) plen; | |
ip_hdr->id[0] = ip_id >> 8; | |
ip_hdr->id[1] = (unsigned char) ip_id; | |
ip_id++; | |
ip_hdr->ttl = 32; /* max 32 hops */ | |
ip_hdr->proto = TCP_PROTO; | |
memcpy(ip_hdr->sa, my_ip, IP_ADDR_LEN); | |
memcpy(ip_hdr->da, tcb.remote_addr, IP_ADDR_LEN); | |
fix_checksum((unsigned char *)ip_hdr, sizeof(ip_hdr_t), 10); | |
/* Fix the Ethernet Header */ | |
eth_hdr->type_code[0] = ETH_TYPE_0; | |
eth_hdr->type_code[1] = ETH_TYPE_IP_1; | |
memcpy(eth_hdr->sa, my_mac, ETH_ADDR_LEN); | |
memcpy(eth_hdr->da, tcb.remote_mac, ETH_ADDR_LEN); /* should be table lookup */ | |
num_pkt_tx++; | |
MSS_MAC_tx_packet(tcp_packet,plen + sizeof(ether_hdr_t), MSS_MAC_BLOCKING); | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char tcp_init(void) | |
{ | |
memset(&tcb,0,sizeof(tcp_control_block_t)); | |
tcb.state = TCP_STATE_LISTEN; | |
ip_id = 0; | |
ip_known = 0; | |
return OK; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char hex_digits_to_byte(unsigned char u, unsigned char l) | |
{ | |
if (u > '9') | |
u = u - 'A' + 10; | |
else | |
u = u - '0'; | |
if (l > '9') | |
l = l - 'A' + 10; | |
else | |
l = l - '0'; | |
return (u << 4) + l; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_icmp_packet(unsigned char *buf) | |
{ | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t)); | |
icmp_hdr_xp icmp_hdr = (icmp_hdr_xp ) | |
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t)); | |
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t); | |
if (check_checksum((unsigned char *)icmp_hdr, (unsigned short int) elen, (unsigned short int) 2, 'M') != OK) | |
return ERR; | |
if (icmp_hdr->type != ICMP_TYPE_ECHO_REQUEST) { | |
return ERR; | |
} | |
return send_icmp_echo_reply(buf); | |
} | |
/* See tcpip.h for more information. | |
*/ | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_tcp_packet(unsigned char *buf) | |
{ | |
eth_hdr_xp eth_hdr = (eth_hdr_xp )buf; | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t)); | |
tcp_hdr_xp tcp_hdr = (tcp_hdr_xp ) | |
(buf + sizeof (ether_hdr_t) + sizeof(ip_hdr_t)); | |
unsigned short int elen = ((unsigned short int)ip_hdr->tlen[0] << 8) + (unsigned short int)ip_hdr->tlen[1] - sizeof(ip_hdr_t); | |
unsigned char state; | |
if ( !memcmp(tcb.remote_addr, ip_hdr->sa, IP_ADDR_LEN) && /* same source IP */ | |
!memcmp(tcb.remote_port, tcp_hdr->sp, TCP_PORT_LEN) && /* same source port */ | |
!memcmp(tcb.local_port, tcp_hdr->dp, TCP_PORT_LEN)) { /* same dest port */ | |
state = tcb.state; | |
} else { /* copy it over, a new IP wants in */ | |
memcpy(tcb.remote_addr, ip_hdr->sa, IP_ADDR_LEN); | |
memcpy(tcb.remote_port, tcp_hdr->sp, TCP_PORT_LEN); | |
memcpy(tcb.local_port, tcp_hdr->dp, TCP_PORT_LEN); | |
memcpy(tcb.remote_mac, eth_hdr->sa, ETH_ADDR_LEN); | |
state = TCP_STATE_LISTEN; | |
} | |
switch (state) { | |
case TCP_STATE_LISTEN: | |
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_SYN) { | |
/* recd SYN : new connection; send SYN+ACK */ | |
tcb.local_seq = TCP_START_SEQ; | |
tcb.remote_seq = 0; | |
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]); | |
tcb.remote_seq++; | |
send_tcp_packet( TCP_CNTRL_SYN | TCP_CNTRL_ACK, 0); | |
tcb.state = TCP_STATE_SYN_RECVD; | |
} | |
break; | |
case TCP_STATE_SYN_RECVD: | |
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_ACK) { | |
/* recd ack; send nothing */ | |
tcb.state = TCP_STATE_ESTABLISHED; | |
} | |
else { | |
tcb.state = TCP_STATE_LISTEN; | |
} | |
break; | |
case TCP_STATE_ESTABLISHED: | |
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_FIN) { | |
/* recd fin; send ack */ | |
/* skip CLOSE_WAIT state; send fin along with ack */ | |
tcb.remote_seq = 0; | |
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]); | |
tcb.remote_seq++; | |
send_tcp_packet(TCP_CNTRL_ACK | TCP_CNTRL_FIN, 0); | |
tcb.state = TCP_STATE_LAST_ACK; | |
/* Default scroll message on OLED */ | |
} | |
else if (tcp_hdr->dp[0] != 0 || \ | |
tcp_hdr->dp[1] != 80) { /* HTTP Port */ | |
break; | |
} | |
else if (elen > sizeof(tcp_hdr_t)) { /* dont respond to empty packets*/ | |
tcb.remote_seq = 0; | |
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]); | |
tcb.remote_seq += (unsigned long) (elen - sizeof(tcp_hdr_t)); | |
//send_http_response(((unsigned char *)(tcp_hdr)) + sizeof (tcp_hdr_t)); | |
tcb.state = TCP_STATE_MY_LAST; | |
} | |
break; | |
case TCP_STATE_MY_LAST: | |
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_FIN) { | |
/* sent fin, got fin, ack the fin */ | |
tcb.remote_seq = 0; | |
tcb.remote_seq = (tcb.remote_seq | tcp_hdr->seqnum[0]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[1]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[2]); | |
tcb.remote_seq = ((tcb.remote_seq << 8) |tcp_hdr->seqnum[3]); | |
tcb.remote_seq++; | |
send_tcp_packet(TCP_CNTRL_ACK, 0); | |
tcb.state = TCP_STATE_CLOSED; | |
} | |
break; | |
case TCP_STATE_LAST_ACK: | |
if (tcp_hdr->urg_ack_psh_rst_syn_fin & TCP_CNTRL_ACK) { | |
/* recd ack; send nothing */ | |
tcb.state = TCP_STATE_CLOSED; | |
} | |
/* no break here... go on to CLOSED directly */ | |
case TCP_STATE_CLOSED: | |
memset (&tcb, 0, sizeof (tcp_control_block_t)); | |
break; | |
default: | |
break; | |
} | |
return 0; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_ip_packet(unsigned char *buf) | |
{ | |
ip_hdr_xp ip_hdr = (ip_hdr_xp ) (buf + sizeof (ether_hdr_t)); | |
/* Is the incoming pkt for me? | |
(either explicity addressed to me or a broadcast address) */ | |
if (memcmp(my_ip, ip_hdr->da, IP_ADDR_LEN)) /* not my IP */ { | |
if (ip_known) { | |
return ERR; | |
} | |
if (ip_hdr->da[0] != 0xFF || ip_hdr->da[1] != 0xFF || | |
ip_hdr->da[2] != 0xFF || ip_hdr->da[3] != 0xFF) { | |
return ERR; | |
} | |
} | |
if (check_checksum((unsigned char *)ip_hdr, (unsigned short int) 20, (unsigned short int) 10, 'I') != OK) | |
return ERR; | |
switch (ip_hdr->proto) | |
{ | |
case TCP_PROTO: | |
return process_tcp_packet(buf); | |
case ICMP_PROTO: | |
return process_icmp_packet(buf); | |
case UDP_PROTO: | |
return process_udp_packet(buf); | |
default: { | |
return ERR; | |
} | |
} | |
return ERR; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_arp_packet(unsigned char *buf) | |
{ | |
arp_pkt_xp arp_pkt = (arp_pkt_xp )(buf + sizeof(ether_hdr_t)); | |
if (arp_pkt->opcode[1] != ARP_OPCODE_REQ_1) { | |
if (arp_pkt->opcode[1] == ARP_OPCODE_REPLY_1) | |
{ | |
if (!memcmp(my_ip, arp_pkt->ip_sa, IP_ADDR_LEN)) | |
{ | |
//printf("IP conflict with MAC"); | |
//printf("%02x:%02x:%02x:%02x:%02x:%02x",arp_pkt->mac_sa[0],arp_pkt->mac_sa[1],arp_pkt->mac_sa[2],arp_pkt->mac_sa[3],arp_pkt->mac_sa[4],arp_pkt->mac_sa[5]); | |
} | |
} | |
return ERR; | |
} | |
if (memcmp(my_ip, arp_pkt->ip_ta, IP_ADDR_LEN)) { | |
return ERR; | |
} | |
return send_arp_reply(buf); | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char process_packet( unsigned char * buf ) | |
{ | |
eth_hdr_xp eth_hdr; | |
unsigned char typ; | |
eth_hdr = (eth_hdr_xp ) buf; | |
typ = eth_hdr->type_code[0]; | |
if (typ != ETH_TYPE_0) | |
{ | |
return ERR; | |
} | |
typ = eth_hdr->type_code[1]; | |
if (typ == ETH_TYPE_ARP_1) | |
{ | |
return process_arp_packet(buf); | |
} | |
else if (typ == ETH_TYPE_IP_1) { | |
return process_ip_packet(buf); | |
} | |
else | |
{ | |
return ERR; | |
} | |
return ERR; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
unsigned char *xstrcpy(unsigned char *d, const unsigned char *s) | |
{ | |
unsigned char c; | |
while ((c = *s++)) | |
(*d++ = c) ; | |
return d; | |
} | |
/***************************************************************************//** | |
* See tcpip.h for more information. | |
*/ | |
// updated html page with fusion board link on page: | |