/*----------------------------------------------------------------
|
/*----------------------------------------------------------------
|
// //
|
// //
|
// boot-loader-ethmac.c //
|
// boot-loader-ethmac.c //
|
// //
|
// //
|
// This file is part of the Amber project //
|
// This file is part of the Amber project //
|
// http://www.opencores.org/project,amber //
|
// http://www.opencores.org/project,amber //
|
// //
|
// //
|
// Description //
|
// Description //
|
// The main functions for the boot loader application. This //
|
// The main functions for the boot loader application. This //
|
// application is embedded in the FPGA's SRAM and is used //
|
// application is embedded in the FPGA's SRAM and is used //
|
// to load larger applications into the DDR3 memory on //
|
// to load larger applications into the DDR3 memory on //
|
// the development board. //
|
// the development board. //
|
// //
|
// //
|
// Author(s): //
|
// Author(s): //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// - Conor Santifort, csantifort.amber@gmail.com //
|
// //
|
// //
|
//////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////
|
// //
|
// //
|
// Copyright (C) 2011 Authors and OPENCORES.ORG //
|
// Copyright (C) 2011 Authors and OPENCORES.ORG //
|
// //
|
// //
|
// This source file may be used and distributed without //
|
// This source file may be used and distributed without //
|
// restriction provided that this copyright statement is not //
|
// restriction provided that this copyright statement is not //
|
// removed from the file and that any derivative work contains //
|
// removed from the file and that any derivative work contains //
|
// the original copyright notice and the associated disclaimer. //
|
// the original copyright notice and the associated disclaimer. //
|
// //
|
// //
|
// This source file is free software; you can redistribute it //
|
// This source file is free software; you can redistribute it //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// and/or modify it under the terms of the GNU Lesser General //
|
// Public License as published by the Free Software Foundation; //
|
// Public License as published by the Free Software Foundation; //
|
// either version 2.1 of the License, or (at your option) any //
|
// either version 2.1 of the License, or (at your option) any //
|
// later version. //
|
// later version. //
|
// //
|
// //
|
// This source is distributed in the hope that it will be //
|
// This source is distributed in the hope that it will be //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// useful, but WITHOUT ANY WARRANTY; without even the implied //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// PURPOSE. See the GNU Lesser General Public License for more //
|
// details. //
|
// details. //
|
// //
|
// //
|
// You should have received a copy of the GNU Lesser General //
|
// You should have received a copy of the GNU Lesser General //
|
// Public License along with this source; if not, download it //
|
// Public License along with this source; if not, download it //
|
// from http://www.opencores.org/lgpl.shtml //
|
// from http://www.opencores.org/lgpl.shtml //
|
// //
|
// //
|
----------------------------------------------------------------*/
|
----------------------------------------------------------------*/
|
|
|
|
|
#include "amber_registers.h"
|
#include "amber_registers.h"
|
#include "address_map.h"
|
#include "address_map.h"
|
#include "line-buffer.h"
|
#include "line-buffer.h"
|
#include "timer.h"
|
#include "timer.h"
|
#include "utilities.h"
|
#include "utilities.h"
|
#include "packet.h"
|
#include "packet.h"
|
#include "tcp.h"
|
#include "tcp.h"
|
#include "telnet.h"
|
#include "telnet.h"
|
|
#include "serial.h"
|
|
|
|
|
/* Global variables */
|
/* Global variables */
|
int tcp_checksum_errors_g = 0;
|
int tcp_checksum_errors_g = 0;
|
socket_t* first_socket_g;
|
socket_t* first_socket_g = NULL;
|
socket_t* socket1_g;
|
|
|
|
/* input argument is a pointer to the previous socket,
|
/* input argument is a pointer to the previous socket,
|
if this is the first socket object, then it is NULL */
|
if this is the first socket object, then it is NULL */
|
socket_t* new_socket(socket_t* prev)
|
socket_t* new_socket(socket_t* prev)
|
{
|
{
|
socket_t* socket;
|
socket_t* socket;
|
int i;
|
int i;
|
|
|
socket = (socket_t*) malloc(sizeof(socket_t));
|
socket = (socket_t*) malloc(sizeof(socket_t));
|
socket->rx_packet = (packet_t*) malloc(sizeof(packet_t));
|
socket->rx_packet = (packet_t*) malloc(sizeof(packet_t));
|
|
|
/* Create space for an array of pointers */
|
/* Create space for an array of pointers */
|
socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *));
|
socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *));
|
|
|
/* Create space for a set of buffers, each pointed to by an element of the array */
|
/* Create space for a set of buffers, each pointed to by an element of the array */
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t));
|
socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t));
|
socket->tcp_buf[i]->payload_valid = 0;
|
socket->tcp_buf[i]->payload_valid = 0;
|
socket->tcp_buf[i]->starting_seq = 0;
|
socket->tcp_buf[i]->starting_seq = 0;
|
socket->tcp_buf[i]->ending_seq = 0;
|
socket->tcp_buf[i]->ending_seq = 0;
|
socket->tcp_buf[i]->len_bytes = 0;
|
socket->tcp_buf[i]->len_bytes = 0;
|
socket->tcp_buf[i]->ack_received = 0;
|
socket->tcp_buf[i]->ack_received = 0;
|
}
|
}
|
|
|
socket->telnet_txbuf = init_line_buffer(0x80000);
|
|
socket->telnet_rxbuf = init_line_buffer(0x1000);
|
|
|
|
socket->packets_sent = 0;
|
socket->packets_sent = 0;
|
socket->packets_received = 0;
|
socket->packets_received = 0;
|
socket->packets_resent = 0;
|
socket->packets_resent = 0;
|
|
|
socket->telnet_sent_opening_message = 0;
|
|
socket->telnet_echo_mode = 0;
|
|
socket->telnet_connection_state = TELNET_CLOSED;
|
|
socket->telnet_options_sent = 0;
|
|
|
|
socket->tcp_current_buf = 0;
|
socket->tcp_current_buf = 0;
|
socket->tcp_reset = 0;
|
socket->tcp_reset = 0;
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->tcp_disconnect = 0;
|
socket->tcp_disconnect = 0;
|
socket->tcp_seq = 0x100; /* should be random initial seq number for tcp */
|
socket->tcp_tx_seq = 0x100; /* should be random initial seq number for tcp */
|
socket->tcp_last_seq = socket->tcp_seq;
|
socket->tcp_rx_ack = 0;
|
socket->tcp_last_ack = 0;
|
socket->tcp_bytes_received = 0;
|
|
socket->tcp_bytes_acked = 0;
|
|
|
/* Chain the socket objects together */
|
/* Chain the socket objects together */
|
if (prev == NULL){
|
if (prev == NULL){
|
socket->first = socket;
|
socket->first = socket;
|
socket->id = 0;
|
socket->id = 0;
|
}
|
}
|
else {
|
else {
|
socket->first = prev->first;
|
socket->first = prev->first;
|
socket->id = prev->id + 1;
|
socket->id = prev->id + 1;
|
prev->next = socket;
|
prev->next = socket;
|
}
|
}
|
socket->next = NULL;
|
socket->next = NULL;
|
|
|
return socket;
|
return socket;
|
}
|
}
|
|
|
|
|
|
|
|
/* returns the socket id */
|
|
int listen_socket (unsigned int listen_port, app_t* app)
|
|
{
|
|
socket_t* socket;
|
|
|
|
/* Add a new socket to the end of the list */
|
|
if (first_socket_g == NULL) {
|
|
trace("first_socket_g == NULL");
|
|
first_socket_g = new_socket(NULL);
|
|
socket = first_socket_g;
|
|
}
|
|
else {
|
|
socket = first_socket_g;
|
|
for(;;){
|
|
if (socket->next!=NULL)
|
|
socket=socket->next;
|
|
else
|
|
break;
|
|
}
|
|
socket = new_socket(socket);
|
|
}
|
|
|
|
socket->listen_port = listen_port;
|
|
socket->tcp_connection_state = TCP_LISTENING;
|
|
|
|
/* Assign the telnet object */
|
|
socket->app = app;
|
|
/* cross link, so can find the socket object when have pointer to the telnet object */
|
|
socket->app->socket = socket;
|
|
|
|
trace("new socket %d listening", socket->id);
|
|
|
|
return socket->id;
|
|
}
|
|
|
|
|
|
|
/* All received tcp packets with dset ip == me arrive here */
|
/* All received tcp packets with dset ip == me arrive here */
|
void parse_tcp_packet(char * buf, packet_t* rx_packet)
|
void parse_tcp_packet(char * buf, packet_t* rx_packet)
|
{
|
{
|
int i;
|
int i;
|
int ptr;
|
int ptr;
|
socket_t* socket;
|
socket_t* socket;
|
int found=0;
|
int found=0;
|
|
|
/* TCP Length */
|
/* TCP Length */
|
rx_packet->tcp_len = rx_packet->ip_len - rx_packet->ip_header_len*4;
|
rx_packet->tcp_len = rx_packet->ip_len - rx_packet->ip_header_len*4;
|
rx_packet->tcp_hdr_len = (buf[12]>>4)*4;
|
rx_packet->tcp_hdr_len = (buf[12]>>4)*4;
|
|
|
// Guard against incorrect tcp_hdr_len value
|
// Guard against incorrect tcp_hdr_len value
|
if (rx_packet->tcp_hdr_len < rx_packet->tcp_len)
|
if (rx_packet->tcp_hdr_len < rx_packet->tcp_len)
|
rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len;
|
rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len;
|
else
|
else
|
rx_packet->tcp_payload_len = 0;
|
rx_packet->tcp_payload_len = 0;
|
|
|
/* Verify the TCP checksum is correct */
|
/* Verify the TCP checksum is correct */
|
if (tcp_checksum(buf, rx_packet, 0)) {
|
if (tcp_checksum(buf, rx_packet, 0)) {
|
tcp_checksum_errors_g++;
|
tcp_checksum_errors_g++;
|
return;
|
return;
|
}
|
}
|
|
|
|
|
rx_packet->tcp_src_port = buf[0]<<8|buf[1];
|
rx_packet->tcp_src_port = buf[0]<<8|buf[1];
|
rx_packet->tcp_dst_port = buf[2]<<8|buf[3];
|
rx_packet->tcp_dst_port = buf[2]<<8|buf[3];
|
rx_packet->tcp_seq = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7];
|
rx_packet->tcp_seq = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7];
|
rx_packet->tcp_ack = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11];
|
rx_packet->tcp_ack = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11];
|
rx_packet->tcp_flags = buf[13];
|
rx_packet->tcp_flags = buf[13];
|
rx_packet->tcp_window_size = buf[14]<<8|buf[15];
|
rx_packet->tcp_window_size = buf[14]<<8|buf[15];
|
|
|
|
// trace("client tcp rx window %d bytes",
|
|
// (rx_packet->tcp_window_size)<<rx_packet->tcp_window_scale);
|
|
|
/* only interested in telnet packet to dest port xx */
|
|
if (rx_packet->tcp_dst_port != 23) {
|
|
return;
|
|
}
|
|
|
|
if (rx_packet->tcp_hdr_len > 20) {
|
if (rx_packet->tcp_hdr_len > 20) {
|
/* Get the source time stamp */
|
/* Get the source time stamp */
|
parse_tcp_options(buf, rx_packet);
|
parse_tcp_options(buf, rx_packet);
|
}
|
}
|
|
|
|
|
|
/* only interested in telnet packet to dest port xx */
|
|
//if (rx_packet->tcp_dst_port != 23) {
|
|
// return;
|
|
//}
|
|
|
|
|
/* --------------------------------------------------
|
/* --------------------------------------------------
|
Assign the received packet to a socket
|
Assign the received packet to a socket
|
-------------------------------------------------- */
|
-------------------------------------------------- */
|
/* seach for an open socket that matches the tcp connection */
|
/* seach for an open socket that matches the tcp connection */
|
socket = first_socket_g;
|
socket = first_socket_g;
|
|
if (socket == NULL) {
|
|
trace("first socket is null");
|
|
return;
|
|
}
|
|
|
|
|
|
/* Search for an already open socket */
|
for(;;){
|
for(;;){
|
if (socket->tcp_connection_state != TCP_CLOSED &&
|
if ((socket->tcp_connection_state == TCP_PENDING ||
|
|
socket->tcp_connection_state == TCP_OPEN) &&
|
socket->rx_packet->tcp_src_port == rx_packet->tcp_src_port) {
|
socket->rx_packet->tcp_src_port == rx_packet->tcp_src_port) {
|
found=1;
|
found=1;
|
break;
|
break;
|
}
|
}
|
if (socket->next!=NULL)
|
if (socket->next!=NULL)
|
socket=socket->next;
|
socket=socket->next;
|
else
|
else
|
break;
|
break;
|
}
|
}
|
|
|
|
|
/* Search for an available closed soeckt to reuse */
|
/* Search for a listening socket */
|
if (!found){
|
if (!found){
|
socket = first_socket_g;
|
socket = first_socket_g;
|
|
trace("search for listening socket");
|
|
|
for(;;){
|
for(;;){
|
if (socket->tcp_connection_state == TCP_CLOSED) {
|
if (socket->tcp_connection_state == TCP_LISTENING) {
|
|
if (socket->listen_port == rx_packet->tcp_dst_port) {
|
found=1;
|
found=1;
|
break;
|
break;
|
}
|
}
|
|
}
|
if (socket->next!=NULL)
|
if (socket->next!=NULL)
|
socket=socket->next;
|
socket=socket->next;
|
else
|
else
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
|
|
/* All available sockets being used. Add a new one to the end of the chain */
|
/* All available sockets being used. Add a new one to the end of the chain */
|
if (!found) {
|
if (!found) {
|
socket = new_socket(socket);
|
trace("not found");
|
|
return;
|
}
|
}
|
|
|
|
|
/* Copy the rx_packet structure into the socket */
|
/* Copy the rx_packet structure into the socket */
|
memcpy(socket->rx_packet, rx_packet, sizeof(packet_t));
|
memcpy(socket->rx_packet, rx_packet, sizeof(packet_t));
|
|
|
tcp_response(buf, socket);
|
tcp_response(buf, socket);
|
}
|
}
|
|
|
|
|
/* Get the tcp source time stamp by walking through the options */
|
/* Get the tcp source time stamp by walking through the options */
|
void parse_tcp_options(char * buf, packet_t* rx_packet)
|
void parse_tcp_options(char * buf, packet_t* rx_packet)
|
{
|
{
|
int ptr;
|
int ptr;
|
|
|
ptr = 20;
|
ptr = 20;
|
while (ptr < rx_packet->tcp_hdr_len-1) {
|
while (ptr < rx_packet->tcp_hdr_len-1) {
|
switch (buf[ptr]) {
|
switch (buf[ptr]) {
|
case 0: ptr=rx_packet->tcp_hdr_len; break; // end of options
|
case 0: ptr=rx_packet->tcp_hdr_len; break; // end of options
|
case 1: ptr++; break;
|
case 1: ptr++; break;
|
case 2: ptr = ptr + buf[ptr+1]; break; // max segment size
|
case 2: ptr = ptr + buf[ptr+1]; break; // max segment size
|
case 3: ptr = ptr + buf[ptr+1]; break; // Window Scale
|
case 3:
|
|
// Window Scale
|
|
trace("%s:L%d window scale bytes %d, 0x%x", buf[ptr+1], buf[ptr+2]);
|
|
rx_packet->tcp_window_scale = buf[ptr+2];
|
|
ptr = ptr + buf[ptr+1];
|
|
break;
|
|
|
case 4: ptr = ptr + buf[ptr+1]; break; // SACK Permitted
|
case 4: ptr = ptr + buf[ptr+1]; break; // SACK Permitted
|
case 5: ptr = ptr + buf[ptr+1]; break; // SACK
|
case 5: ptr = ptr + buf[ptr+1]; break; // SACK
|
case 8:
|
case 8:
|
// Time Stamp Option
|
// Time Stamp Option
|
rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5];
|
rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5];
|
ptr = ptr + buf[ptr+1];
|
ptr = ptr + buf[ptr+1];
|
break;
|
break;
|
|
|
case 28: // User Timeout Option
|
case 28: // User Timeout Option
|
ptr = ptr + buf[ptr+1]; break;
|
ptr = ptr + buf[ptr+1]; break;
|
|
|
default:
|
default:
|
ptr++; break;
|
ptr++; break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
void tcp_response(char * buf, socket_t* socket)
|
void tcp_response(char * buf, socket_t* socket)
|
{
|
{
|
socket->packets_received++;
|
socket->packets_received++;
|
|
trace("tcp_response");
|
|
|
/* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */
|
/* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */
|
if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ?
|
if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ?
|
tcp_ack(socket);
|
tcp_ack(socket);
|
|
|
|
|
// Other side requesting to reset a connection ?
|
// Other side requesting to reset a connection ?
|
if (socket->rx_packet->tcp_flags & 0x04) { // RST
|
if (socket->rx_packet->tcp_flags & 0x04) { // RST
|
// Reset the connection
|
// Reset the connection
|
socket->tcp_disconnect = 1;
|
socket->tcp_disconnect = 1;
|
}
|
}
|
|
|
// open a connection
|
// open a connection
|
else if (socket->tcp_connection_state == TCP_CLOSED) {
|
else if (socket->tcp_connection_state == TCP_LISTENING) {
|
|
|
if (socket->rx_packet->tcp_flags & 0x02) { // SYN
|
if (socket->rx_packet->tcp_flags & 0x02) { // SYN
|
|
trace("tcp_open");
|
// Open connection
|
// Open connection
|
tcp_open(socket);
|
tcp_open(socket);
|
socket->tcp_connection_state = TCP_PENDING;
|
socket->tcp_connection_state = TCP_PENDING;
|
}
|
}
|
|
|
/* ACK any FIN received */
|
/* ACK any FIN received */
|
else if (socket->rx_packet->tcp_flags & 0x01) // FIN
|
else if (socket->rx_packet->tcp_flags & 0x01) // FIN
|
tcp_reply(socket, NULL, 0);
|
tcp_reply(socket, NULL, 0);
|
}
|
}
|
|
|
|
|
// Sent the first ack packet to establish a connection.
|
// Sent the first ack packet to establish a connection.
|
// Have just received the second packet from the server
|
// Have just received the second packet from the server
|
else if (socket->tcp_connection_state == TCP_PENDING) {
|
else if (socket->tcp_connection_state == TCP_PENDING) {
|
/* Add 1 to the sequence number as a special case to open
|
/* Add 1 to the sequence number as a special case to open
|
the connection */
|
the connection */
|
socket->tcp_seq++;
|
socket->tcp_tx_seq++;
|
socket->tcp_connection_state = TCP_OPEN;
|
socket->tcp_connection_state = TCP_OPEN;
|
}
|
}
|
|
|
|
|
// connection is already open
|
// connection is already open
|
else {
|
else {
|
|
|
/* contains tcp payload */
|
/* contains tcp payload */
|
if (socket->rx_packet->tcp_payload_len != 0) {
|
if (socket->rx_packet->tcp_payload_len != 0) {
|
|
|
|
socket->tcp_bytes_received += socket->rx_packet->tcp_payload_len;
|
|
trace("socket %d received total %d bytes", socket->id, socket->tcp_bytes_received);
|
|
|
/* Ack the packet only if the payload length is non-zero */
|
/* Ack the packet only if the payload length is non-zero */
|
tcp_reply(socket, NULL, 0);
|
tcp_reply(socket, NULL, 0);
|
|
|
/* Process the tcp contents */
|
/* Process the tcp contents */
|
if (socket->rx_packet->tcp_dst_port == TELNET_PORT)
|
if (socket->rx_packet->tcp_dst_port == TELNET_PORT)
|
/* telnet */
|
/* telnet */
|
parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket);
|
parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket);
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
void tcp_disconnect(socket_t * socket)
|
void tcp_disconnect(socket_t * socket)
|
{
|
{
|
|
telnet_t* telnet;
|
|
|
if (socket->tcp_connection_state != TCP_CLOSED) {
|
if (socket->tcp_connection_state != TCP_CLOSED) {
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->telnet_connection_state = TELNET_CLOSED;
|
|
socket->telnet_options_sent = 0;
|
|
socket->telnet_sent_opening_message = 0;
|
|
tcp_reply(socket, NULL, 0);
|
tcp_reply(socket, NULL, 0);
|
|
|
|
/* app level disconnect function */
|
|
switch(socket->app->type) {
|
|
case APP_TELNET: telnet_disconnect(socket->app);
|
|
break;
|
|
default:
|
|
trace("Unknown app type");
|
|
}
|
socket->tcp_disconnect = 0;
|
socket->tcp_disconnect = 0;
|
socket->telnet_echo_mode = 0; // reset this setting
|
|
}
|
}
|
}
|
}
|
|
|
|
|
|
|
/* Transmit a string of length line_len
|
/* Transmit a string of length line_len
|
Suspend interrupts so this process does not get interrupted */
|
Suspend interrupts so this process does not get interrupted */
|
void tcp_tx(socket_t* socket, char* buf, int len)
|
void tcp_tx(socket_t* socket, char* buf, int len)
|
{
|
{
|
/* Disable ethmac_int interrupt */
|
/* Disable ethmac_int interrupt */
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
|
|
|
tcp_reply(socket, buf, len);
|
tcp_reply(socket, buf, len);
|
|
|
/* Enable ethmac_int interrupt */
|
/* Enable ethmac_int interrupt */
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
|
}
|
}
|
|
|
|
|
|
|
/* TODO merge this into tcp_reply */
|
/* TODO merge this into tcp_reply */
|
void tcp_open(socket_t* socket)
|
void tcp_open(socket_t* socket)
|
{
|
{
|
|
|
int i, j;
|
int i, j;
|
unsigned short header_checksum;
|
unsigned short header_checksum;
|
mac_ip_t target;
|
|
int ip_length;
|
int ip_length;
|
char * buf;
|
char * buf;
|
|
|
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
|
|
|
|
strncpy(&socket->dest_ip, socket->rx_packet->src_ip, 4);
|
target.mac[0] = socket->rx_packet->src_mac[0];
|
strncpy(&socket->dest_mac, socket->rx_packet->src_mac, 6);
|
target.mac[1] = socket->rx_packet->src_mac[1];
|
|
target.mac[2] = socket->rx_packet->src_mac[2];
|
|
target.mac[3] = socket->rx_packet->src_mac[3];
|
|
target.mac[4] = socket->rx_packet->src_mac[4];
|
|
target.mac[5] = socket->rx_packet->src_mac[5];
|
|
target.ip[0] = socket->rx_packet->src_ip[0];
|
|
target.ip[1] = socket->rx_packet->src_ip[1];
|
|
target.ip[2] = socket->rx_packet->src_ip[2];
|
|
target.ip[3] = socket->rx_packet->src_ip[3];
|
|
|
|
|
|
/* Include 20 bytes of tcp options */
|
/* Include 20 bytes of tcp options */
|
ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */
|
ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */
|
|
|
|
/* fill in the information about the packet about to be sent */
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
|
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW);
|
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW);
|
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1;
|
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1;
|
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
|
|
|
|
ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/
|
|
ethernet_header(buf, &target, 0x0800); /* bytes 0 to 13*/
|
|
|
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
|
|
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
|
|
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
|
ip_header(&buf[14], &socket->dest_ip, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/
|
|
ethernet_header(buf, &socket->dest_mac, 0x0800); /* bytes 0 to 13*/
|
|
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options
|
/* transmit an ethernet frame */
|
|
//trace("tx_packet buf 0x%d, len %d",
|
|
// (unsigned int)buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
|
|
ethmac_tx_packet(buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
|
socket->packets_sent++;
|
socket->packets_sent++;
|
|
|
|
|
/* Pick the next tx buffer to use */
|
/* Pick the next tx buffer to use */
|
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
|
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
|
socket->tcp_current_buf=0;
|
socket->tcp_current_buf=0;
|
else
|
else
|
socket->tcp_current_buf++;
|
socket->tcp_current_buf++;
|
}
|
}
|
|
|
|
|
|
|
void tcp_reply(socket_t* socket, char* telnet_payload, int telnet_payload_length)
|
void tcp_reply(socket_t* socket, char* telnet_payload, int telnet_payload_length)
|
{
|
{
|
|
|
int i, j;
|
int i, j;
|
mac_ip_t target;
|
|
int ip_length;
|
int ip_length;
|
char * buf;
|
char * buf;
|
|
|
|
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
|
buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
|
|
|
target.mac[0] = socket->rx_packet->src_mac[0];
|
|
target.mac[1] = socket->rx_packet->src_mac[1];
|
|
target.mac[2] = socket->rx_packet->src_mac[2];
|
|
target.mac[3] = socket->rx_packet->src_mac[3];
|
|
target.mac[4] = socket->rx_packet->src_mac[4];
|
|
target.mac[5] = socket->rx_packet->src_mac[5];
|
|
target.ip[0] = socket->rx_packet->src_ip[0];
|
|
target.ip[1] = socket->rx_packet->src_ip[1];
|
|
target.ip[2] = socket->rx_packet->src_ip[2];
|
|
target.ip[3] = socket->rx_packet->src_ip[3];
|
|
|
|
ip_length = 20+20 + telnet_payload_length;
|
ip_length = 20+20 + telnet_payload_length;
|
|
|
/* Copy the payload into the transmit buffer */
|
/* Copy the payload into the transmit buffer */
|
if (telnet_payload_length != 0) {
|
if (telnet_payload_length != 0) {
|
for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) {
|
for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) {
|
buf[i] = telnet_payload[j];
|
buf[i] = telnet_payload[j];
|
}
|
}
|
}
|
}
|
|
|
if (telnet_payload_length)
|
if (telnet_payload_length)
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
|
else
|
else
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0;
|
socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0;
|
|
|
|
/* fill in the information about the packet about to be sent */
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
|
socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
|
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL);
|
socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL);
|
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length;
|
socket->tcp_buf[socket->tcp_current_buf]->ending_seq = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length;
|
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
|
|
|
|
ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/
|
|
ethernet_header(buf, &target, 0x0800); /*bytes 0 to 13*/
|
|
|
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
|
socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
|
|
set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
|
|
|
strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
|
/* Create the IP header */
|
|
/* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/
|
|
ip_header(&buf[14], &socket->dest_ip, ip_length, 6); /* 20 byes of tcp options, bytes 14 to 33, ip_proto = 6, TCP*/
|
|
ethernet_header(buf, &socket->dest_mac, 0x0800); /* bytes 0 to 13*/
|
|
|
tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes); // MAC header, IP header, TCP header, TCP options
|
/* transmit an ethernet frame */
|
|
ethmac_tx_packet(buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
|
socket->packets_sent++;
|
socket->packets_sent++;
|
|
|
|
|
/* Pick the next tx buffer to use */
|
/* Pick the next tx buffer to use */
|
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
|
if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
|
socket->tcp_current_buf=0;
|
socket->tcp_current_buf=0;
|
else
|
else
|
socket->tcp_current_buf++;
|
socket->tcp_current_buf++;
|
}
|
}
|
|
|
|
|
|
|
|
|
/* Find the packets lower than or equal to seq and mark them as acked */
|
/* Find the packets lower than or equal to seq and mark them as acked */
|
void tcp_ack(socket_t* socket)
|
void tcp_ack(socket_t* socket)
|
{
|
{
|
int i, ack_valid;
|
int i, ack_valid;
|
unsigned int ack = socket->rx_packet->tcp_ack;
|
unsigned int ack = socket->rx_packet->tcp_ack;
|
unsigned int last_ack = socket->tcp_last_ack;
|
unsigned int last_ack = socket->tcp_rx_ack;
|
|
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
if (socket->tcp_buf[i]->payload_valid) {
|
if (socket->tcp_buf[i]->payload_valid) {
|
|
|
if (ack > last_ack) {
|
if (ack > last_ack) {
|
ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) &&
|
ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) &&
|
(socket->tcp_buf[i]->ending_seq <= ack);
|
(socket->tcp_buf[i]->ending_seq <= ack);
|
}
|
}
|
else { /* ack is a little after 0, last_ack is a little before 0 */
|
else { /* ack is a little after 0, last_ack is a little before 0 */
|
if (socket->tcp_buf[i]->ending_seq < last_ack)
|
if (socket->tcp_buf[i]->ending_seq < last_ack)
|
/* ending sequence is a little after 0 */
|
/* ending sequence is a little after 0 */
|
ack_valid = socket->tcp_buf[i]->ending_seq <= ack;
|
ack_valid = socket->tcp_buf[i]->ending_seq <= ack;
|
else
|
else
|
ack_valid = 1;
|
ack_valid = 1;
|
}
|
}
|
|
|
if (ack_valid) {
|
if (ack_valid) {
|
socket->tcp_buf[i]->ack_received = 1;
|
socket->tcp_buf[i]->ack_received = 1;
|
if (socket->tcp_buf[i]->ending_seq == ack) break;
|
if (socket->tcp_buf[i]->ending_seq == ack) break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
socket->tcp_last_ack = ack;
|
socket->tcp_rx_ack = ack;
|
}
|
}
|
|
|
|
|
/* Check if any tcp packets need to be re-transmitted */
|
/* Check if any tcp packets need to be re-transmitted */
|
void tcp_retransmit(socket_t* socket)
|
void tcp_retransmit(socket_t* socket)
|
{
|
{
|
int i;
|
int i;
|
|
|
/* Find the packet that matches seq */
|
/* Find the packet that matches seq */
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
|
if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) {
|
if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) {
|
if (timer_expired(&socket->tcp_buf[i]->resend_time)) {
|
if (timer_expired(&socket->tcp_buf[i]->resend_time)) {
|
|
|
/* Update the timer to trigger again in another little while */
|
/* Update the timer to trigger again in another little while */
|
set_timer(&socket->tcp_buf[i]->resend_time, 500);
|
set_timer(&socket->tcp_buf[i]->resend_time, 500);
|
|
|
socket->packets_resent++;
|
socket->packets_resent++;
|
|
|
/* Disable ethmac_int interrupt */
|
/* Disable ethmac_int interrupt */
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
|
|
|
strncpy((char*)ETHMAC_TX_BUFFER, socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes);
|
/* transmit an ethernet frame */
|
tx_packet(socket->tcp_buf[i]->len_bytes); // MAC header, IP header, TCP header, TCP options
|
ethmac_tx_packet(socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes);
|
socket->packets_sent++;
|
socket->packets_sent++;
|
|
|
|
|
/* Enable ethmac_int interrupt */
|
/* Enable ethmac_int interrupt */
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
|
*(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
/* return the starting seq number for this packet */
|
/* return the starting seq number for this packet */
|
unsigned int tcp_header(char *buf, socket_t* socket, int payload_length, int options)
|
unsigned int tcp_header(char *buf, socket_t* socket, int payload_length, int options)
|
{
|
{
|
unsigned short header_checksum;
|
unsigned short header_checksum;
|
unsigned int seq_num;
|
unsigned int seq_num;
|
unsigned int ack_num;
|
unsigned int ack_num;
|
char flags = 0;
|
char flags = 0;
|
unsigned short len_tcp;
|
unsigned short len_tcp;
|
unsigned int starting_seq;
|
unsigned int starting_seq;
|
|
|
/* Source Port */
|
/* Source Port */
|
buf[0] = socket->rx_packet->tcp_dst_port >>8;
|
buf[0] = socket->rx_packet->tcp_dst_port >>8;
|
buf[1] = socket->rx_packet->tcp_dst_port &0xff;
|
buf[1] = socket->rx_packet->tcp_dst_port &0xff;
|
|
|
/* Destination Port */
|
/* Destination Port */
|
buf[2] = socket->rx_packet->tcp_src_port >>8;
|
buf[2] = socket->rx_packet->tcp_src_port >>8;
|
buf[3] = socket->rx_packet->tcp_src_port &0xff;
|
buf[3] = socket->rx_packet->tcp_src_port &0xff;
|
|
|
/* Sequence Number */
|
/* Sequence Number */
|
/* Increment the sequence number for the next packet */
|
/* Increment the sequence number for the next packet */
|
starting_seq = socket->tcp_seq;
|
starting_seq = socket->tcp_tx_seq;
|
socket->tcp_last_seq = socket->tcp_seq;
|
socket->tcp_tx_seq += payload_length;
|
socket->tcp_seq += payload_length;
|
|
|
|
|
|
buf[4] = starting_seq>>24;
|
buf[4] = starting_seq>>24;
|
buf[5] = (starting_seq>>16)&0xff;
|
buf[5] = (starting_seq>>16)&0xff;
|
buf[6] = (starting_seq>>8)&0xff;
|
buf[6] = (starting_seq>>8)&0xff;
|
buf[7] = starting_seq&0xff;
|
buf[7] = starting_seq&0xff;
|
|
|
|
|
/* Ack Number */
|
/* Ack Number */
|
if (options == TCP_NEW)
|
if (options == TCP_NEW) {
|
ack_num = socket->rx_packet->tcp_seq + 1;
|
ack_num = socket->rx_packet->tcp_seq + 1;
|
|
socket->tcp_rx_init_seq = socket->rx_packet->tcp_seq;
|
|
}
|
else if (socket->rx_packet->tcp_flags & 0x01) // FIN
|
else if (socket->rx_packet->tcp_flags & 0x01) // FIN
|
// +1 to the final ack
|
// +1 to the final ack
|
ack_num = socket->rx_packet->tcp_seq + 1;
|
ack_num = socket->rx_packet->tcp_seq + 1;
|
else
|
else
|
ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len;
|
ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len;
|
|
|
|
socket->tcp_rx_seq= ack_num;
|
|
//trace("socket %d received seq %d",
|
|
// socket->id, socket->tcp_rx_seq - socket->tcp_rx_init_seq);
|
|
|
|
|
buf[8] = ack_num>>24;
|
buf[8] = ack_num>>24;
|
buf[9] = (ack_num>>16)&0xff;
|
buf[9] = (ack_num>>16)&0xff;
|
buf[10] = (ack_num>>8)&0xff;
|
buf[10] = (ack_num>>8)&0xff;
|
buf[11] = ack_num&0xff;
|
buf[11] = ack_num&0xff;
|
|
|
|
|
/* Data offset with OPTIONS */
|
/* Data offset with OPTIONS */
|
if (options == TCP_NEW)
|
if (options == TCP_NEW)
|
buf[12] = 0xa0; /* upper 4 bits, min is 5 */
|
buf[12] = 0xa0; /* upper 4 bits, min is 5 */
|
else
|
else
|
buf[12] = 0x50; /* upper 4 bits, min is 5 */
|
buf[12] = 0x50; /* upper 4 bits, min is 5 */
|
|
|
|
|
/* Flags */
|
/* Flags */
|
flags = 0x10; /* ACK */
|
flags = 0x10; /* ACK */
|
if (options == TCP_NEW) /* Valid in first reply in new connection only */
|
if (options == TCP_NEW) /* Valid in first reply in new connection only */
|
flags |= 0x02; /* SYNchronise */
|
flags |= 0x02; /* SYNchronise */
|
if (socket->tcp_disconnect)
|
if (socket->tcp_disconnect)
|
flags |= 0x01; /* FINish */
|
flags |= 0x01; /* FINish */
|
if (socket->tcp_reset)
|
if (socket->tcp_reset)
|
flags |= 0x04; /* Reset */
|
flags |= 0x04; /* Reset */
|
|
|
buf[13] = flags;
|
buf[13] = flags;
|
|
|
/* Window Size */
|
/* Window Size */
|
buf[14] = socket->rx_packet->tcp_window_size >> 8;
|
buf[14] = socket->rx_packet->tcp_window_size >> 8;
|
buf[15] = socket->rx_packet->tcp_window_size & 0xff;
|
buf[15] = socket->rx_packet->tcp_window_size & 0xff;
|
|
|
/* Checksum */
|
/* Checksum */
|
buf[16] = 0;
|
buf[16] = 0;
|
buf[17] = 0;
|
buf[17] = 0;
|
|
|
/* Urgent Pointer */
|
/* Urgent Pointer */
|
buf[18] = 0;
|
buf[18] = 0;
|
buf[19] = 0;
|
buf[19] = 0;
|
|
|
|
|
if (options == TCP_NEW) {
|
if (options == TCP_NEW) {
|
/* OPTION: max seg size */
|
/* OPTION: max seg size */
|
buf[20] = 0x02;
|
buf[20] = 0x02;
|
buf[21] = 0x04;
|
buf[21] = 0x04;
|
buf[22] = 0x05;
|
buf[22] = 0x05;
|
buf[23] = 0xb4;
|
buf[23] = 0xb4;
|
|
|
/* OPTION Sack OK */
|
/* OPTION Sack OK */
|
buf[24] = 0x04;
|
buf[24] = 0x04;
|
buf[25] = 0x02;
|
buf[25] = 0x02;
|
|
|
/* OPTION Time Stamp */
|
/* OPTION Time Stamp */
|
buf[26] = 0x08;
|
buf[26] = 0x08;
|
buf[27] = 0x0a;
|
buf[27] = 0x0a;
|
buf[28] = 0x00;
|
buf[28] = 0x00;
|
buf[29] = 0x61;
|
buf[29] = 0x61;
|
buf[30] = 0x1f;
|
buf[30] = 0x1f;
|
buf[31] = 0xc6;
|
buf[31] = 0xc6;
|
buf[32] = socket->rx_packet->tcp_src_time_stamp>>24;
|
buf[32] = socket->rx_packet->tcp_src_time_stamp>>24;
|
buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff;
|
buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff;
|
buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff;
|
buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff;
|
buf[35] = socket->rx_packet->tcp_src_time_stamp&0xff;
|
buf[35] = socket->rx_packet->tcp_src_time_stamp&0xff;
|
|
|
/* OPTION: NOP */
|
/* OPTION: NOP */
|
buf[36] = 0x01;
|
buf[36] = 0x01;
|
|
|
/* OPTION Window Scale */
|
/* OPTION Window Scale */
|
buf[37] = 0x03;
|
buf[37] = 0x03;
|
buf[38] = 0x03;
|
buf[38] = 0x03;
|
buf[39] = 0x06;
|
buf[39] = 0x06;
|
}
|
}
|
|
|
|
|
/* Length */
|
/* Length */
|
if (options == TCP_NEW)
|
if (options == TCP_NEW)
|
len_tcp = 40+payload_length;
|
len_tcp = 40+payload_length;
|
else
|
else
|
len_tcp = 20+payload_length;
|
len_tcp = 20+payload_length;
|
|
|
|
|
/* header checksum */
|
/* header checksum */
|
header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp);
|
header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp);
|
buf[16] = (header_checksum>>8)&0xff;
|
buf[16] = (header_checksum>>8)&0xff;
|
buf[17] = header_checksum&0xff;
|
buf[17] = header_checksum&0xff;
|
|
|
return starting_seq;
|
return starting_seq;
|
}
|
}
|
|
|
|
|
unsigned short tcp_checksum(unsigned char *buf, packet_t* rx_packet, unsigned short len_tcp)
|
unsigned short tcp_checksum(unsigned char *buf, packet_t* rx_packet, unsigned short len_tcp)
|
{
|
{
|
unsigned short prot_tcp=6;
|
unsigned short prot_tcp=6;
|
unsigned short word16;
|
unsigned short word16;
|
unsigned long sum;
|
unsigned long sum;
|
int i;
|
int i;
|
|
|
//initialize sum to zero
|
//initialize sum to zero
|
sum=0;
|
sum=0;
|
if (!len_tcp) len_tcp = rx_packet->tcp_len;
|
if (!len_tcp) len_tcp = rx_packet->tcp_len;
|
|
|
|
|
// add the TCP pseudo header which contains:
|
// add the TCP pseudo header which contains:
|
// the IP source and destinationn addresses,
|
// the IP source and destinationn addresses,
|
for (i=0;i<4;i=i+2){
|
for (i=0;i<4;i=i+2){
|
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF);
|
word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF);
|
sum=sum+word16;
|
sum=sum+word16;
|
}
|
}
|
for (i=0;i<4;i=i+2){
|
for (i=0;i<4;i=i+2){
|
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF);
|
word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF);
|
sum=sum+word16;
|
sum=sum+word16;
|
}
|
}
|
// the protocol number and the length of the TCP packet
|
// the protocol number and the length of the TCP packet
|
sum = sum + prot_tcp + len_tcp;
|
sum = sum + prot_tcp + len_tcp;
|
|
|
|
|
return header_checksum16(buf, len_tcp, sum);
|
return header_checksum16(buf, len_tcp, sum);
|
}
|
}
|
|
|
|
|
/* handle tcp connections and process buffers
|
/* handle tcp connections and process buffers
|
Poll all sockets in turn for activity */
|
Poll all sockets in turn for activity */
|
void process_tcp(socket_t* socket)
|
void process_tcp(socket_t* socket)
|
{
|
{
|
|
telnet_t* telnet;
|
|
|
/* Check if any tcp packets need to be re-transmitted */
|
/* Check if any tcp packets need to be re-transmitted */
|
tcp_retransmit(socket);
|
tcp_retransmit(socket);
|
|
|
/* Handle exit command */
|
/* Handle exit command */
|
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) {
|
if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) {
|
|
trace("calling tcp disconnect %d",
|
|
socket->tcp_rx_seq - socket->tcp_rx_init_seq);
|
tcp_disconnect(socket);
|
tcp_disconnect(socket);
|
}
|
}
|
|
|
/* Reset connection */
|
/* Reset connection */
|
else if (socket->tcp_reset) {
|
else if (socket->tcp_reset) {
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->tcp_connection_state = TCP_CLOSED;
|
socket->telnet_connection_state = TELNET_CLOSED;
|
|
socket->telnet_options_sent = 0;
|
telnet = (telnet_t*) socket->app->telnet;
|
|
telnet->connection_state = TELNET_CLOSED;
|
|
telnet->options_sent = 0;
|
|
|
tcp_reply(socket, NULL, 0);
|
tcp_reply(socket, NULL, 0);
|
socket->tcp_reset = 0;
|
socket->tcp_reset = 0;
|
}
|
}
|
|
|
/* handle telnet messages */
|
/* handle telnet messages */
|
else if (socket->tcp_connection_state == TCP_OPEN){
|
else if (socket->tcp_connection_state == TCP_OPEN){
|
process_telnet(socket);
|
|
|
/* app level process function */
|
|
switch(socket->app->type) {
|
|
case APP_TELNET: process_telnet(socket);
|
|
break;
|
|
default:
|
|
trace("Unknown app type");
|
}
|
}
|
}
|
}
|
|
}
|
|
|
|
|
|
|
|
void process_sockets()
|
|
{
|
|
socket_t* socket;
|
|
|
|
/* handle tcp connections and process buffers */
|
|
/* Poll all sockets in turn for activity */
|
|
socket = first_socket_g;
|
|
for(;;){
|
|
process_tcp(socket);
|
|
if (socket->next!=NULL)
|
|
socket=socket->next;
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
|
No newline at end of file
|
No newline at end of file
|