OpenCores
URL https://opencores.org/ocsvn/amber/amber/trunk

Subversion Repositories amber

[/] [amber/] [trunk/] [sw/] [boot-loader-ethmac/] [tcp.c] - Blame information for rev 81

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 61 csantifort
/*----------------------------------------------------------------
2
//                                                              //
3
//  boot-loader-ethmac.c                                        //
4
//                                                              //
5
//  This file is part of the Amber project                      //
6
//  http://www.opencores.org/project,amber                      //
7
//                                                              //
8
//  Description                                                 //
9
//  The main functions for the boot loader application. This    //
10 80 csantifort
//  application is embedded in the FPGA's SRAM and is used      //
11 61 csantifort
//  to load larger applications into the DDR3 memory on         //
12
//  the development board.                                      //
13
//                                                              //
14
//  Author(s):                                                  //
15
//      - Conor Santifort, csantifort.amber@gmail.com           //
16
//                                                              //
17
//////////////////////////////////////////////////////////////////
18
//                                                              //
19
// Copyright (C) 2011 Authors and OPENCORES.ORG                 //
20
//                                                              //
21
// This source file may be used and distributed without         //
22
// restriction provided that this copyright statement is not    //
23
// removed from the file and that any derivative work contains  //
24
// the original copyright notice and the associated disclaimer. //
25
//                                                              //
26
// This source file is free software; you can redistribute it   //
27
// and/or modify it under the terms of the GNU Lesser General   //
28
// Public License as published by the Free Software Foundation; //
29
// either version 2.1 of the License, or (at your option) any   //
30
// later version.                                               //
31
//                                                              //
32
// This source is distributed in the hope that it will be       //
33
// useful, but WITHOUT ANY WARRANTY; without even the implied   //
34
// warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR      //
35
// PURPOSE.  See the GNU Lesser General Public License for more //
36
// details.                                                     //
37
//                                                              //
38
// You should have received a copy of the GNU Lesser General    //
39
// Public License along with this source; if not, download it   //
40
// from http://www.opencores.org/lgpl.shtml                     //
41
//                                                              //
42
----------------------------------------------------------------*/
43
 
44
 
45
#include "amber_registers.h"
46
#include "address_map.h"
47
#include "line-buffer.h"
48
#include "timer.h"
49
#include "utilities.h"
50
#include "packet.h"
51
#include "tcp.h"
52
#include "telnet.h"
53 81 csantifort
#include "serial.h"
54 61 csantifort
 
55
 
56
/* Global variables */
57
int         tcp_checksum_errors_g = 0;
58 81 csantifort
socket_t*   first_socket_g = NULL;
59 61 csantifort
 
60 81 csantifort
 
61 80 csantifort
/* input argument is a pointer to the previous socket,
62
   if this is the first socket object, then it is NULL */
63
socket_t* new_socket(socket_t* prev)
64
{
65
    socket_t* socket;
66
    int i;
67 61 csantifort
 
68 80 csantifort
    socket = (socket_t*) malloc(sizeof(socket_t));
69
    socket->rx_packet = (packet_t*) malloc(sizeof(packet_t));
70
 
71
    /* Create space for an array of pointers */
72
    socket->tcp_buf = malloc (TCP_TX_BUFFERS * sizeof (void *));
73
 
74
    /* Create space for a set of buffers, each pointed to by an element of the array */
75
    for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
76
        socket->tcp_buf[i] = (packet_buffer_t*) malloc (sizeof (packet_buffer_t));
77
        socket->tcp_buf[i]->payload_valid = 0;
78
        socket->tcp_buf[i]->starting_seq = 0;
79
        socket->tcp_buf[i]->ending_seq   = 0;
80
        socket->tcp_buf[i]->len_bytes    = 0;
81
        socket->tcp_buf[i]->ack_received = 0;
82
        }
83
 
84
    socket->packets_sent = 0;
85
    socket->packets_received = 0;
86
    socket->packets_resent = 0;
87
 
88
    socket->tcp_current_buf = 0;
89
    socket->tcp_reset = 0;
90
    socket->tcp_connection_state = TCP_CLOSED;
91
    socket->tcp_disconnect = 0;
92 81 csantifort
    socket->tcp_tx_seq = 0x100;  /* should be random initial seq number for tcp */
93
    socket->tcp_rx_ack = 0;
94
    socket->tcp_bytes_received = 0;
95
    socket->tcp_bytes_acked = 0;
96 80 csantifort
 
97
    /* Chain the socket objects together */
98
    if (prev == NULL){
99
        socket->first = socket;
100
        socket->id = 0;
101
        }
102
    else {
103
        socket->first = prev->first;
104
        socket->id = prev->id + 1;
105
        prev->next = socket;
106
        }
107
    socket->next  = NULL;
108
 
109
    return socket;
110
}
111
 
112
 
113 81 csantifort
 
114
/* returns the socket id */
115
int listen_socket (unsigned int listen_port, app_t* app)
116
{
117
    socket_t* socket;
118
 
119
    /* Add a new socket to the end of the list */
120
    if (first_socket_g == NULL) {
121
        trace("first_socket_g == NULL");
122
        first_socket_g = new_socket(NULL);
123
        socket = first_socket_g;
124
    }
125
    else {
126
        socket = first_socket_g;
127
        for(;;){
128
            if (socket->next!=NULL)
129
                socket=socket->next;
130
            else
131
                break;
132
            }
133
        socket = new_socket(socket);
134
    }
135
 
136
    socket->listen_port = listen_port;
137
    socket->tcp_connection_state = TCP_LISTENING;
138
 
139
    /* Assign the telnet object */
140
    socket->app = app;
141
    /* cross link, so can find the socket object when have pointer to the telnet object */
142
    socket->app->socket = socket;
143
 
144
    trace("new socket %d listening", socket->id);
145
 
146
    return socket->id;
147
}
148
 
149
 
150
 
151 80 csantifort
/* All received tcp packets with dset ip == me arrive here */
152 61 csantifort
void parse_tcp_packet(char * buf, packet_t* rx_packet)
153
{
154
    int i;
155
    int ptr;
156
    socket_t* socket;
157 80 csantifort
    int found=0;
158
 
159 61 csantifort
    /* TCP Length */
160
    rx_packet->tcp_len         = rx_packet->ip_len - rx_packet->ip_header_len*4;
161
    rx_packet->tcp_hdr_len     = (buf[12]>>4)*4;
162 80 csantifort
 
163 61 csantifort
    // Guard against incorrect tcp_hdr_len value
164
    if (rx_packet->tcp_hdr_len < rx_packet->tcp_len)
165
        rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len;
166
    else
167
        rx_packet->tcp_payload_len = 0;
168 80 csantifort
 
169 61 csantifort
    /* Verify the TCP checksum is correct */
170
    if (tcp_checksum(buf, rx_packet, 0)) {
171
        tcp_checksum_errors_g++;
172 80 csantifort
        return;
173 61 csantifort
    }
174 80 csantifort
 
175
 
176 61 csantifort
    rx_packet->tcp_src_port    = buf[0]<<8|buf[1];
177
    rx_packet->tcp_dst_port    = buf[2]<<8|buf[3];
178
    rx_packet->tcp_seq         = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7];
179
    rx_packet->tcp_ack         = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11];
180
    rx_packet->tcp_flags       = buf[13];
181 80 csantifort
    rx_packet->tcp_window_size = buf[14]<<8|buf[15];
182 61 csantifort
 
183 81 csantifort
    // trace("client tcp rx window %d bytes",
184
    //     (rx_packet->tcp_window_size)<<rx_packet->tcp_window_scale);
185 80 csantifort
 
186
 
187 61 csantifort
    if (rx_packet->tcp_hdr_len > 20) {
188
        /* Get the source time stamp */
189 80 csantifort
        parse_tcp_options(buf, rx_packet);
190 61 csantifort
        }
191
 
192
 
193 81 csantifort
    /* only interested in telnet packet to dest port xx */
194
    //if (rx_packet->tcp_dst_port != 23) {
195
    //    return;
196
    //}
197
 
198
 
199 61 csantifort
    /*  --------------------------------------------------
200 80 csantifort
        Assign the received packet to a socket
201 61 csantifort
        -------------------------------------------------- */
202 80 csantifort
    /*  seach for an open socket that matches the tcp connection */
203
    socket = first_socket_g;
204 81 csantifort
    if (socket == NULL) {
205
        trace("first socket is null");
206
        return;
207
    }
208
 
209
 
210
    /* Search for an already open socket */
211 80 csantifort
    for(;;){
212 81 csantifort
        if ((socket->tcp_connection_state == TCP_PENDING ||
213
             socket->tcp_connection_state == TCP_OPEN)      &&
214 80 csantifort
            socket->rx_packet->tcp_src_port == rx_packet->tcp_src_port) {
215
            found=1;
216
            break;
217
            }
218
        if (socket->next!=NULL)
219
            socket=socket->next;
220
        else
221
            break;
222
        }
223 61 csantifort
 
224
 
225 81 csantifort
    /* Search for a listening socket */
226 80 csantifort
    if (!found){
227
        socket = first_socket_g;
228 81 csantifort
        trace("search for listening socket");
229
 
230 80 csantifort
        for(;;){
231 81 csantifort
            if (socket->tcp_connection_state == TCP_LISTENING) {
232
                if (socket->listen_port == rx_packet->tcp_dst_port)  {
233
                    found=1;
234
                    break;
235
                    }
236 80 csantifort
                }
237
            if (socket->next!=NULL)
238
                socket=socket->next;
239
            else
240
                break;
241
            }
242
        }
243 61 csantifort
 
244
 
245 80 csantifort
    /* All available sockets being used. Add a new one to the end of the chain */
246
    if (!found) {
247 81 csantifort
        trace("not found");
248
        return;
249
     }
250 61 csantifort
 
251
    /* Copy the rx_packet structure into the socket */
252
    memcpy(socket->rx_packet, rx_packet, sizeof(packet_t));
253 80 csantifort
 
254 61 csantifort
    tcp_response(buf, socket);
255
}
256
 
257
 
258
/* Get the tcp source time stamp by walking through the options */
259
void parse_tcp_options(char * buf, packet_t* rx_packet)
260
{
261
    int ptr;
262
 
263
    ptr = 20;
264
    while (ptr < rx_packet->tcp_hdr_len-1) {
265
        switch (buf[ptr]) {
266
            case 0:  ptr=rx_packet->tcp_hdr_len; break; // end of options
267
            case 1:  ptr++; break;
268 80 csantifort
            case 2:  ptr = ptr + buf[ptr+1]; break;  // max segment size
269 81 csantifort
            case 3:
270
                // Window Scale
271
                trace("%s:L%d window scale bytes %d, 0x%x", buf[ptr+1], buf[ptr+2]);
272
                rx_packet->tcp_window_scale = buf[ptr+2];
273
                ptr = ptr + buf[ptr+1];
274
                break;
275
 
276 61 csantifort
            case 4:  ptr = ptr + buf[ptr+1]; break;  // SACK Permitted
277
            case 5:  ptr = ptr + buf[ptr+1]; break;  // SACK
278 80 csantifort
            case 8:
279
                // Time Stamp Option
280 61 csantifort
                rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5];
281 80 csantifort
                ptr = ptr + buf[ptr+1];
282 61 csantifort
                break;
283 80 csantifort
 
284 61 csantifort
            case 28:  // User Timeout Option
285 80 csantifort
                ptr = ptr + buf[ptr+1]; break;
286
 
287 61 csantifort
            default:
288 80 csantifort
                ptr++; break;
289
            }
290 61 csantifort
        }
291
}
292
 
293
 
294
void tcp_response(char * buf, socket_t* socket)
295
{
296
    socket->packets_received++;
297 81 csantifort
    trace("tcp_response");
298 80 csantifort
 
299 61 csantifort
    /* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */
300 80 csantifort
    if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ?
301 61 csantifort
        tcp_ack(socket);
302
 
303 80 csantifort
 
304 61 csantifort
    // Other side requesting to reset a connection ?
305 80 csantifort
    if (socket->rx_packet->tcp_flags & 0x04) { // RST
306 61 csantifort
        // Reset the connection
307
        socket->tcp_disconnect = 1;
308
        }
309 80 csantifort
 
310 61 csantifort
    // open a connection
311 81 csantifort
    else if (socket->tcp_connection_state == TCP_LISTENING) {
312 80 csantifort
 
313
        if (socket->rx_packet->tcp_flags & 0x02) { // SYN
314 81 csantifort
            trace("tcp_open");
315 61 csantifort
            // Open connection
316
            tcp_open(socket);
317
            socket->tcp_connection_state = TCP_PENDING;
318
            }
319 80 csantifort
 
320 61 csantifort
        /* ACK any FIN received */
321 80 csantifort
        else if (socket->rx_packet->tcp_flags & 0x01) // FIN
322
            tcp_reply(socket, NULL, 0);
323 61 csantifort
        }
324
 
325 80 csantifort
 
326 61 csantifort
    // Sent the first ack packet to establish a connection.
327 80 csantifort
    // Have just received the second packet from the server
328
    else if (socket->tcp_connection_state == TCP_PENDING) {
329 61 csantifort
        /* Add 1 to the sequence number as a special case to open
330
           the connection */
331 81 csantifort
        socket->tcp_tx_seq++;
332 80 csantifort
        socket->tcp_connection_state = TCP_OPEN;
333 61 csantifort
        }
334 80 csantifort
 
335
 
336 61 csantifort
    // connection is already open
337
    else {
338 80 csantifort
 
339 61 csantifort
        /* contains tcp payload */
340
        if (socket->rx_packet->tcp_payload_len != 0) {
341 81 csantifort
 
342
            socket->tcp_bytes_received += socket->rx_packet->tcp_payload_len;
343
            trace("socket %d received total %d bytes", socket->id, socket->tcp_bytes_received);
344
 
345 61 csantifort
            /* Ack the packet only if the payload length is non-zero */
346
            tcp_reply(socket, NULL, 0);
347 80 csantifort
 
348 61 csantifort
            /* Process the tcp contents */
349
            if (socket->rx_packet->tcp_dst_port == TELNET_PORT)
350
                /* telnet */
351
                parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket);
352 80 csantifort
            }
353 61 csantifort
        }
354
}
355
 
356
 
357
void tcp_disconnect(socket_t * socket)
358
{
359 81 csantifort
    telnet_t* telnet;
360
 
361 61 csantifort
    if (socket->tcp_connection_state != TCP_CLOSED) {
362
        socket->tcp_connection_state = TCP_CLOSED;
363
        tcp_reply(socket, NULL, 0);
364 81 csantifort
 
365
        /* app level disconnect function */
366
        switch(socket->app->type) {
367
            case APP_TELNET: telnet_disconnect(socket->app);
368
                              break;
369
            default:
370
                trace("Unknown app type");
371
        }
372 61 csantifort
        socket->tcp_disconnect = 0;
373
    }
374
}
375
 
376
 
377
 
378
/* Transmit a string of length line_len
379 80 csantifort
   Suspend interrupts so this process does not get interrupted */
380 61 csantifort
void tcp_tx(socket_t* socket, char* buf, int len)
381
{
382 80 csantifort
    /* Disable ethmac_int interrupt */
383
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
384
 
385
    tcp_reply(socket, buf, len);
386
 
387
    /* Enable ethmac_int interrupt */
388
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
389 61 csantifort
}
390
 
391
 
392
 
393
/* TODO merge this into tcp_reply */
394
void tcp_open(socket_t* socket)
395
{
396
 
397
    int i, j;
398
    unsigned short header_checksum;
399
    int ip_length;
400
    char * buf;
401
 
402
    buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
403 80 csantifort
 
404 81 csantifort
    strncpy(&socket->dest_ip,  socket->rx_packet->src_ip, 4);
405
    strncpy(&socket->dest_mac, socket->rx_packet->src_mac, 6);
406 80 csantifort
 
407 61 csantifort
    /* Include 20 bytes of tcp options */
408
    ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */
409 80 csantifort
 
410 81 csantifort
    /* fill in the information about the packet about to be sent */
411 61 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
412
    socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
413 80 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW);
414 61 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->ending_seq   = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1;
415 81 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
416 61 csantifort
    set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
417 80 csantifort
 
418 81 csantifort
    ip_header(&buf[14], &socket->dest_ip, ip_length, 6); /* 20 byes of tcp  options, bytes 14 to 33, ip_proto = 6, TCP*/
419
    ethernet_header(buf, &socket->dest_mac, 0x0800);  /* bytes 0 to 13*/
420 80 csantifort
 
421 81 csantifort
    /* transmit an ethernet frame */
422
    //trace("tx_packet buf 0x%d, len %d",
423
    //    (unsigned int)buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
424
    ethmac_tx_packet(buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
425 61 csantifort
    socket->packets_sent++;
426
 
427
 
428 80 csantifort
    /* Pick the next tx buffer to use */
429 61 csantifort
    if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
430
        socket->tcp_current_buf=0;
431
    else
432
        socket->tcp_current_buf++;
433
}
434
 
435
 
436
 
437
void tcp_reply(socket_t* socket, char* telnet_payload, int telnet_payload_length)
438
{
439
 
440
    int i, j;
441
    int ip_length;
442
    char * buf;
443
 
444
    buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
445 80 csantifort
 
446 61 csantifort
    ip_length = 20+20 + telnet_payload_length;
447 80 csantifort
 
448 61 csantifort
    /* Copy the payload into the transmit buffer */
449
    if (telnet_payload_length != 0) {
450
        for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) {
451
            buf[i] = telnet_payload[j];
452
            }
453
        }
454 80 csantifort
 
455 61 csantifort
    if (telnet_payload_length)
456
        socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
457
    else
458
        socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0;
459 80 csantifort
 
460 81 csantifort
    /* fill in the information about the packet about to be sent */
461 61 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
462 80 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL);
463 61 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->ending_seq   = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length;
464 81 csantifort
    socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
465 61 csantifort
    set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
466
 
467 81 csantifort
    /* Create the IP header */
468
    /* 20 byes of tcp  options, bytes 14 to 33, ip_proto = 6, TCP*/
469
    ip_header(&buf[14], &socket->dest_ip, ip_length, 6); /* 20 byes of tcp  options, bytes 14 to 33, ip_proto = 6, TCP*/
470
    ethernet_header(buf, &socket->dest_mac, 0x0800);  /* bytes 0 to 13*/
471 61 csantifort
 
472 81 csantifort
    /* transmit an ethernet frame */
473
    ethmac_tx_packet(buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
474 61 csantifort
    socket->packets_sent++;
475
 
476
 
477 80 csantifort
    /* Pick the next tx buffer to use */
478 61 csantifort
    if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
479
        socket->tcp_current_buf=0;
480
    else
481
        socket->tcp_current_buf++;
482
}
483
 
484
 
485
 
486
/* Find the packets lower than or equal to seq and mark them as acked */
487
void tcp_ack(socket_t* socket)
488
{
489
    int i, ack_valid;
490
    unsigned int ack      = socket->rx_packet->tcp_ack;
491 81 csantifort
    unsigned int last_ack = socket->tcp_rx_ack;
492 80 csantifort
 
493 61 csantifort
    for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
494
        if (socket->tcp_buf[i]->payload_valid) {
495 80 csantifort
 
496 61 csantifort
            if (ack > last_ack) {
497 80 csantifort
                ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) &&
498 61 csantifort
                            (socket->tcp_buf[i]->ending_seq <= ack);
499
                }
500
            else { /* ack is a little after 0, last_ack is a little before 0 */
501
                if (socket->tcp_buf[i]->ending_seq < last_ack)
502
                    /* ending sequence is a little after 0 */
503
                    ack_valid = socket->tcp_buf[i]->ending_seq <= ack;
504
                else
505
                    ack_valid = 1;
506
                }
507 80 csantifort
 
508 61 csantifort
            if (ack_valid)  {
509
                socket->tcp_buf[i]->ack_received = 1;
510
                if (socket->tcp_buf[i]->ending_seq == ack) break;
511
                }
512
            }
513
        }
514 80 csantifort
 
515 81 csantifort
   socket->tcp_rx_ack = ack;
516 61 csantifort
}
517
 
518
 
519
/* Check if any tcp packets need to be re-transmitted */
520 80 csantifort
void tcp_retransmit(socket_t* socket)
521 61 csantifort
{
522
    int i;
523 80 csantifort
 
524 61 csantifort
    /* Find the packet that matches seq */
525
    for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
526
        if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) {
527
            if (timer_expired(&socket->tcp_buf[i]->resend_time))  {
528 80 csantifort
 
529 61 csantifort
                /* Update the timer to trigger again in another little while */
530
                set_timer(&socket->tcp_buf[i]->resend_time, 500);
531 80 csantifort
 
532 61 csantifort
                socket->packets_resent++;
533 80 csantifort
 
534 61 csantifort
                /* Disable ethmac_int interrupt */
535
                *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
536 80 csantifort
 
537 81 csantifort
                /* transmit an ethernet frame */
538
                ethmac_tx_packet(socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes);
539 61 csantifort
                socket->packets_sent++;
540 80 csantifort
 
541
 
542 61 csantifort
                /* Enable ethmac_int interrupt */
543
                *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
544
                break;
545
                }
546
            }
547
        }
548
}
549
 
550
 
551
/* return the starting seq number for this packet */
552
unsigned int tcp_header(char *buf, socket_t* socket, int payload_length, int options)
553
{
554
    unsigned short header_checksum;
555
    unsigned int seq_num;
556
    unsigned int ack_num;
557
    char flags = 0;
558
    unsigned short len_tcp;
559
    unsigned int starting_seq;
560 80 csantifort
 
561 61 csantifort
    /* Source Port */
562 80 csantifort
    buf[0] = socket->rx_packet->tcp_dst_port >>8;
563
    buf[1] = socket->rx_packet->tcp_dst_port &0xff;
564 61 csantifort
 
565
    /* Destination Port */
566 80 csantifort
    buf[2] = socket->rx_packet->tcp_src_port >>8;
567
    buf[3] = socket->rx_packet->tcp_src_port &0xff;
568 61 csantifort
 
569
    /* Sequence Number */
570
    /* Increment the sequence number for the next packet */
571 81 csantifort
    starting_seq = socket->tcp_tx_seq;
572
    socket->tcp_tx_seq += payload_length;
573 80 csantifort
 
574
 
575 61 csantifort
    buf[4] =  starting_seq>>24;
576
    buf[5] = (starting_seq>>16)&0xff;
577
    buf[6] = (starting_seq>>8)&0xff;
578
    buf[7] =  starting_seq&0xff;
579
 
580 80 csantifort
 
581 61 csantifort
    /* Ack Number */
582 81 csantifort
    if (options == TCP_NEW) {
583 61 csantifort
        ack_num = socket->rx_packet->tcp_seq + 1;
584 81 csantifort
        socket->tcp_rx_init_seq = socket->rx_packet->tcp_seq;
585
    }
586 80 csantifort
    else if (socket->rx_packet->tcp_flags & 0x01) // FIN
587 61 csantifort
        // +1 to the final ack
588
        ack_num = socket->rx_packet->tcp_seq + 1;
589
    else
590
        ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len;
591 80 csantifort
 
592 81 csantifort
    socket->tcp_rx_seq= ack_num;
593
    //trace("socket %d received seq %d",
594
    //    socket->id, socket->tcp_rx_seq - socket->tcp_rx_init_seq);
595
 
596
 
597 61 csantifort
    buf[8]  =  ack_num>>24;
598
    buf[9]  = (ack_num>>16)&0xff;
599
    buf[10] = (ack_num>>8)&0xff;
600
    buf[11] =  ack_num&0xff;
601
 
602
 
603
    /* Data offset with OPTIONS */
604
    if (options == TCP_NEW)
605
        buf[12] = 0xa0;  /* upper 4 bits, min is 5 */
606
    else
607
        buf[12] = 0x50;  /* upper 4 bits, min is 5 */
608
 
609 80 csantifort
 
610 61 csantifort
    /* Flags */
611 80 csantifort
    flags = 0x10;       /* ACK */
612 61 csantifort
    if (options == TCP_NEW)    /* Valid in first reply in new connection only */
613
        flags |= 0x02;  /* SYNchronise */
614 80 csantifort
    if (socket->tcp_disconnect)
615 61 csantifort
        flags |= 0x01;  /* FINish */
616 80 csantifort
    if (socket->tcp_reset)
617 61 csantifort
        flags |= 0x04;  /* Reset */
618 80 csantifort
 
619 61 csantifort
    buf[13] = flags;
620 80 csantifort
 
621 61 csantifort
    /* Window Size */
622
    buf[14] = socket->rx_packet->tcp_window_size >> 8;
623
    buf[15] = socket->rx_packet->tcp_window_size & 0xff;
624 80 csantifort
 
625 61 csantifort
    /* Checksum */
626
    buf[16] = 0;
627
    buf[17] = 0;
628 80 csantifort
 
629 61 csantifort
    /* Urgent Pointer */
630
    buf[18] = 0;
631
    buf[19] = 0;
632 80 csantifort
 
633
 
634 61 csantifort
    if (options == TCP_NEW) {
635
        /* OPTION: max seg size */
636
        buf[20] = 0x02;
637 80 csantifort
        buf[21] = 0x04;
638 61 csantifort
        buf[22] = 0x05;
639
        buf[23] = 0xb4;
640 80 csantifort
 
641 61 csantifort
        /* OPTION Sack OK */
642
        buf[24] = 0x04;
643
        buf[25] = 0x02;
644 80 csantifort
 
645 61 csantifort
        /* OPTION Time Stamp */
646
        buf[26] = 0x08;
647
        buf[27] = 0x0a;
648
        buf[28] = 0x00;
649
        buf[29] = 0x61;
650
        buf[30] = 0x1f;
651
        buf[31] = 0xc6;
652
        buf[32] =  socket->rx_packet->tcp_src_time_stamp>>24;
653
        buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff;
654
        buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff;
655
        buf[35] =  socket->rx_packet->tcp_src_time_stamp&0xff;
656 80 csantifort
 
657 61 csantifort
        /* OPTION: NOP */
658
        buf[36] = 0x01;
659
 
660
        /* OPTION Window Scale */
661
        buf[37] = 0x03;
662
        buf[38] = 0x03;
663
        buf[39] = 0x06;
664
        }
665
 
666 80 csantifort
 
667 61 csantifort
    /* Length */
668
    if (options == TCP_NEW)
669
        len_tcp = 40+payload_length;
670
    else
671
        len_tcp = 20+payload_length;
672 80 csantifort
 
673
 
674 61 csantifort
    /* header checksum */
675 80 csantifort
    header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp);
676 61 csantifort
    buf[16] = (header_checksum>>8)&0xff;
677
    buf[17] = header_checksum&0xff;
678 80 csantifort
 
679 61 csantifort
    return starting_seq;
680
}
681
 
682
 
683
unsigned short tcp_checksum(unsigned char *buf, packet_t* rx_packet, unsigned short len_tcp)
684
{
685
    unsigned short prot_tcp=6;
686
    unsigned short word16;
687 80 csantifort
    unsigned long  sum;
688 61 csantifort
    int i;
689 80 csantifort
 
690 61 csantifort
    //initialize sum to zero
691
    sum=0;
692
    if (!len_tcp) len_tcp = rx_packet->tcp_len;
693 80 csantifort
 
694
 
695 61 csantifort
    // add the TCP pseudo header which contains:
696
    // the IP source and destinationn addresses,
697
    for (i=0;i<4;i=i+2){
698
            word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF);
699 80 csantifort
            sum=sum+word16;
700 61 csantifort
    }
701
    for (i=0;i<4;i=i+2){
702
            word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF);
703 80 csantifort
            sum=sum+word16;
704 61 csantifort
    }
705
    // the protocol number and the length of the TCP packet
706
    sum = sum + prot_tcp + len_tcp;
707
 
708
 
709
    return header_checksum16(buf, len_tcp, sum);
710
}
711
 
712 80 csantifort
 
713
/* handle tcp connections and process buffers
714
   Poll all sockets in turn for activity */
715
void process_tcp(socket_t* socket)
716
{
717 81 csantifort
    telnet_t* telnet;
718
 
719 80 csantifort
    /* Check if any tcp packets need to be re-transmitted */
720
    tcp_retransmit(socket);
721
 
722
    /* Handle exit command */
723
    if (socket->tcp_disconnect && socket->tcp_connection_state == TCP_OPEN) {
724 81 csantifort
        trace("calling tcp disconnect %d",
725
            socket->tcp_rx_seq - socket->tcp_rx_init_seq);
726 80 csantifort
        tcp_disconnect(socket);
727
        }
728
 
729
    /* Reset connection */
730
    else if (socket->tcp_reset) {
731
        socket->tcp_connection_state = TCP_CLOSED;
732 81 csantifort
 
733
        telnet = (telnet_t*) socket->app->telnet;
734
        telnet->connection_state = TELNET_CLOSED;
735
        telnet->options_sent = 0;
736
 
737 80 csantifort
        tcp_reply(socket, NULL, 0);
738
        socket->tcp_reset = 0;
739
        }
740
 
741
    /* handle telnet messages */
742
    else if (socket->tcp_connection_state == TCP_OPEN){
743 81 csantifort
 
744
        /* app level process function */
745
        switch(socket->app->type) {
746
            case APP_TELNET: process_telnet(socket);
747
                             break;
748
            default:
749
                trace("Unknown app type");
750
        }
751 80 csantifort
    }
752
}
753
 
754 81 csantifort
 
755
 
756
void process_sockets()
757
{
758
    socket_t* socket;
759
 
760
    /* handle tcp connections and process buffers */
761
    /* Poll all sockets in turn for activity */
762
    socket = first_socket_g;
763
    for(;;){
764
        process_tcp(socket);
765
        if (socket->next!=NULL)
766
            socket=socket->next;
767
        else
768
            break;
769
        }
770
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.