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

Subversion Repositories amber

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

Go to most recent revision | 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
//  application is embedded in the FPGA's SRAM and is used      //
11
//  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
 
54
 
55
/* Global variables */
56
int         tcp_checksum_errors_g = 0;
57
 
58
 
59
void parse_tcp_packet(char * buf, packet_t* rx_packet)
60
{
61
    int i;
62
    int ptr;
63
    socket_t* socket;
64
 
65
    /* TCP Length */
66
    rx_packet->tcp_len         = rx_packet->ip_len - rx_packet->ip_header_len*4;
67
    rx_packet->tcp_hdr_len     = (buf[12]>>4)*4;
68
 
69
    // Guard against incorrect tcp_hdr_len value
70
    if (rx_packet->tcp_hdr_len < rx_packet->tcp_len)
71
        rx_packet->tcp_payload_len = rx_packet->tcp_len - rx_packet->tcp_hdr_len;
72
    else
73
        rx_packet->tcp_payload_len = 0;
74
 
75
    /* Verify the TCP checksum is correct */
76
    if (tcp_checksum(buf, rx_packet, 0)) {
77
        tcp_checksum_errors_g++;
78
        goto error_out;
79
    }
80
 
81
 
82
    rx_packet->tcp_src_port    = buf[0]<<8|buf[1];
83
    rx_packet->tcp_dst_port    = buf[2]<<8|buf[3];
84
    rx_packet->tcp_seq         = buf[4]<<24|buf[5]<<16|buf[6]<<8|buf[7];
85
    rx_packet->tcp_ack         = buf[8]<<24|buf[9]<<16|buf[10]<<8|buf[11];
86
    rx_packet->tcp_flags       = buf[13];
87
    rx_packet->tcp_window_size = buf[14]<<8|buf[15];
88
 
89
 
90
    if (rx_packet->tcp_hdr_len > 20) {
91
        /* Get the source time stamp */
92
        parse_tcp_options(buf, rx_packet);
93
        }
94
 
95
 
96
    /*  --------------------------------------------------
97
        Assign the received packet to a socket
98
        -------------------------------------------------- */
99
 
100
    /* socket 0 open and matches ? */
101
    if (socket0_g->tcp_connection_state != TCP_CLOSED &&
102
        socket0_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port)
103
        socket = socket0_g;
104
 
105
    /* socket 1 open and matches ? */
106
    else if (socket1_g->tcp_connection_state != TCP_CLOSED &&
107
        socket1_g->rx_packet->tcp_src_port == rx_packet->tcp_src_port)
108
        socket = socket1_g;
109
 
110
    /* no matches. Pick an unused socket */
111
    else if (socket0_g->tcp_connection_state == TCP_CLOSED)
112
        socket = socket0_g;
113
    else if (socket1_g->tcp_connection_state == TCP_CLOSED)
114
        socket = socket1_g;
115
    else
116
        goto error_out;
117
 
118
 
119
    /* Copy the rx_packet structure into the socket */
120
    memcpy(socket->rx_packet, rx_packet, sizeof(packet_t));
121
 
122
    tcp_response(buf, socket);
123
 
124
    error_out:
125
        return;
126
}
127
 
128
 
129
/* Get the tcp source time stamp by walking through the options */
130
void parse_tcp_options(char * buf, packet_t* rx_packet)
131
{
132
    int ptr;
133
 
134
    ptr = 20;
135
    while (ptr < rx_packet->tcp_hdr_len-1) {
136
        switch (buf[ptr]) {
137
            case 0:  ptr=rx_packet->tcp_hdr_len; break; // end of options
138
            case 1:  ptr++; break;
139
            case 2:  ptr = ptr + buf[ptr+1]; break;  // max segment size 
140
            case 3:  ptr = ptr + buf[ptr+1]; break;  // Window Scale
141
            case 4:  ptr = ptr + buf[ptr+1]; break;  // SACK Permitted
142
            case 5:  ptr = ptr + buf[ptr+1]; break;  // SACK
143
            case 8:
144
                // Time Stamp Option 
145
                rx_packet->tcp_src_time_stamp = buf[ptr+2]<<24|buf[ptr+3]<<16|buf[ptr+4]<<8|buf[ptr+5];
146
                ptr = ptr + buf[ptr+1];
147
                break;
148
 
149
            case 28:  // User Timeout Option
150
                ptr = ptr + buf[ptr+1]; break;
151
 
152
            default:
153
                ptr++; break;
154
            }
155
        }
156
}
157
 
158
 
159
void tcp_response(char * buf, socket_t* socket)
160
{
161
    socket->packets_received++;
162
 
163
    /* Mark the ack in the tcp tx packet buffer so the tx packet does not get resent */
164
    if (socket->rx_packet->tcp_flags & 0x10) // ack flag set ?    
165
        tcp_ack(socket);
166
 
167
 
168
    // Other side requesting to reset a connection ?
169
    if (socket->rx_packet->tcp_flags & 0x04) { // RST 
170
        // Reset the connection
171
        socket->tcp_disconnect = 1;
172
        }
173
 
174
    // open a connection
175
    else if (socket->tcp_connection_state == TCP_CLOSED) {
176
 
177
        if (socket->rx_packet->tcp_flags & 0x02) { // SYN 
178
            // Open connection
179
            tcp_open(socket);
180
            socket->tcp_connection_state = TCP_PENDING;
181
            }
182
 
183
        /* ACK any FIN received */
184
        else if (socket->rx_packet->tcp_flags & 0x01) // FIN 
185
            tcp_reply(socket, NULL, 0);
186
        }
187
 
188
 
189
    // Sent the first ack packet to establish a connection.
190
    // Have just received the second packet from the server    
191
    else if (socket->tcp_connection_state == TCP_PENDING) {
192
        /* Add 1 to the sequence number as a special case to open
193
           the connection */
194
        socket->tcp_seq++;
195
        socket->tcp_connection_state = TCP_OPEN;
196
        }
197
 
198
 
199
    // connection is already open
200
    else {
201
 
202
        /* contains tcp payload */
203
        if (socket->rx_packet->tcp_payload_len != 0) {
204
            /* Ack the packet only if the payload length is non-zero */
205
            tcp_reply(socket, NULL, 0);
206
 
207
            /* Process the tcp contents */
208
            if (socket->rx_packet->tcp_dst_port == TELNET_PORT)
209
                /* telnet */
210
                parse_telnet_options(&buf[socket->rx_packet->tcp_hdr_len], socket);
211
            }
212
        }
213
}
214
 
215
 
216
void tcp_disconnect(socket_t * socket)
217
{
218
    if (socket->tcp_connection_state != TCP_CLOSED) {
219
        socket->tcp_connection_state = TCP_CLOSED;
220
        socket->telnet_connection_state = TELNET_CLOSED;
221
        socket->telnet_options_sent = 0;
222
        socket->telnet_sent_opening_message = 0;
223
        tcp_reply(socket, NULL, 0);
224
        socket->tcp_disconnect = 0;
225
        socket->telnet_echo_mode = 0;  // reset this setting
226
    }
227
}
228
 
229
 
230
 
231
/* Transmit a string of length line_len
232
   Suspend interrupts so this process does not get interrupted */
233
void tcp_tx(socket_t* socket, char* buf, int len)
234
{
235
    /* Disable ethmac_int interrupt */
236
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
237
 
238
    tcp_reply(socket, buf, len);
239
 
240
    /* Enable ethmac_int interrupt */
241
    *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
242
}
243
 
244
 
245
 
246
/* TODO merge this into tcp_reply */
247
void tcp_open(socket_t* socket)
248
{
249
 
250
    int i, j;
251
    unsigned short header_checksum;
252
    mac_ip_t target;
253
    int ip_length;
254
    char * buf;
255
 
256
 
257
    buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
258
 
259
 
260
    target.mac[0] = socket->rx_packet->src_mac[0];
261
    target.mac[1] = socket->rx_packet->src_mac[1];
262
    target.mac[2] = socket->rx_packet->src_mac[2];
263
    target.mac[3] = socket->rx_packet->src_mac[3];
264
    target.mac[4] = socket->rx_packet->src_mac[4];
265
    target.mac[5] = socket->rx_packet->src_mac[5];
266
    target.ip[0]  = socket->rx_packet->src_ip[0];
267
    target.ip[1]  = socket->rx_packet->src_ip[1];
268
    target.ip[2]  = socket->rx_packet->src_ip[2];
269
    target.ip[3]  = socket->rx_packet->src_ip[3];
270
 
271
 
272
    /* Include 20 bytes of tcp options */
273
    ip_length = 20+20+20; /* 20 bytes ip header, 20 bytes tcp header, 20 bytes tcp options */
274
 
275
    socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
276
    socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
277
    socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, 0, TCP_NEW);
278
    socket->tcp_buf[socket->tcp_current_buf]->ending_seq   = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + 1;
279
    set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
280
 
281
    ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp  options, bytes 14 to 33, ip_proto = 6, TCP*/
282
    ethernet_header(buf, &target, 0x0800);  /* bytes 0 to 13*/
283
 
284
    socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
285
 
286
    strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
287
 
288
    tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes);  // MAC header, IP header, TCP header, TCP options
289
    socket->packets_sent++;
290
 
291
 
292
    /* Pick the next tx buffer to use */
293
    if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
294
        socket->tcp_current_buf=0;
295
    else
296
        socket->tcp_current_buf++;
297
}
298
 
299
 
300
 
301
void tcp_reply(socket_t* socket, char* telnet_payload, int telnet_payload_length)
302
{
303
 
304
    int i, j;
305
    mac_ip_t target;
306
    int ip_length;
307
    char * buf;
308
 
309
 
310
    buf = socket->tcp_buf[socket->tcp_current_buf]->buf;
311
 
312
    target.mac[0] = socket->rx_packet->src_mac[0];
313
    target.mac[1] = socket->rx_packet->src_mac[1];
314
    target.mac[2] = socket->rx_packet->src_mac[2];
315
    target.mac[3] = socket->rx_packet->src_mac[3];
316
    target.mac[4] = socket->rx_packet->src_mac[4];
317
    target.mac[5] = socket->rx_packet->src_mac[5];
318
    target.ip[0]  = socket->rx_packet->src_ip[0];
319
    target.ip[1]  = socket->rx_packet->src_ip[1];
320
    target.ip[2]  = socket->rx_packet->src_ip[2];
321
    target.ip[3]  = socket->rx_packet->src_ip[3];
322
 
323
    ip_length = 20+20 + telnet_payload_length;
324
 
325
    /* Copy the payload into the transmit buffer */
326
    if (telnet_payload_length != 0) {
327
        for (i=14+ip_length-telnet_payload_length, j=0; i<14+ip_length;i++,j++) {
328
            buf[i] = telnet_payload[j];
329
            }
330
        }
331
 
332
    if (telnet_payload_length)
333
        socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 1;
334
    else
335
        socket->tcp_buf[socket->tcp_current_buf]->payload_valid = 0;
336
 
337
    socket->tcp_buf[socket->tcp_current_buf]->ack_received = 0;
338
    socket->tcp_buf[socket->tcp_current_buf]->starting_seq = tcp_header(&buf[34], socket, telnet_payload_length, TCP_NORMAL);
339
    socket->tcp_buf[socket->tcp_current_buf]->ending_seq   = socket->tcp_buf[socket->tcp_current_buf]->starting_seq + telnet_payload_length;
340
    set_timer(&socket->tcp_buf[socket->tcp_current_buf]->resend_time, 500);
341
 
342
    ip_header(&buf[14], &target, ip_length, 6); /* 20 byes of tcp  options, bytes 14 to 33, ip_proto = 6, TCP*/
343
    ethernet_header(buf, &target, 0x0800);  /*bytes 0 to 13*/
344
 
345
    socket->tcp_buf[socket->tcp_current_buf]->len_bytes = 14+ip_length;
346
 
347
    strncpy((char*)ETHMAC_TX_BUFFER, buf, socket->tcp_buf[socket->tcp_current_buf]->len_bytes);
348
 
349
    tx_packet(socket->tcp_buf[socket->tcp_current_buf]->len_bytes);  // MAC header, IP header, TCP header, TCP options
350
    socket->packets_sent++;
351
 
352
 
353
    /* Pick the next tx buffer to use */
354
    if (socket->tcp_current_buf == TCP_TX_BUFFERS-1)
355
        socket->tcp_current_buf=0;
356
    else
357
        socket->tcp_current_buf++;
358
}
359
 
360
 
361
 
362
 
363
/* Find the packets lower than or equal to seq and mark them as acked */
364
void tcp_ack(socket_t* socket)
365
{
366
    int i, ack_valid;
367
    unsigned int ack      = socket->rx_packet->tcp_ack;
368
    unsigned int last_ack = socket->tcp_last_ack;
369
 
370
    for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
371
        if (socket->tcp_buf[i]->payload_valid) {
372
 
373
            if (ack > last_ack) {
374
                ack_valid = (socket->tcp_buf[i]->ending_seq > last_ack) &&
375
                            (socket->tcp_buf[i]->ending_seq <= ack);
376
                }
377
            else { /* ack is a little after 0, last_ack is a little before 0 */
378
                if (socket->tcp_buf[i]->ending_seq < last_ack)
379
                    /* ending sequence is a little after 0 */
380
                    ack_valid = socket->tcp_buf[i]->ending_seq <= ack;
381
                else
382
                    ack_valid = 1;
383
                }
384
 
385
            if (ack_valid)  {
386
                socket->tcp_buf[i]->ack_received = 1;
387
                if (socket->tcp_buf[i]->ending_seq == ack) break;
388
                }
389
            }
390
        }
391
 
392
   socket->tcp_last_ack = ack;
393
}
394
 
395
 
396
/* Check if any tcp packets need to be re-transmitted */
397
void tcp_retransmit(socket_t* socket)
398
{
399
    int i;
400
 
401
    /* Find the packet that matches seq */
402
    for (i=0;i<TCP_TX_BUFFERS;i=i+1) {
403
        if (socket->tcp_buf[i]->payload_valid && !socket->tcp_buf[i]->ack_received) {
404
            if (timer_expired(&socket->tcp_buf[i]->resend_time))  {
405
 
406
                /* Update the timer to trigger again in another little while */
407
                set_timer(&socket->tcp_buf[i]->resend_time, 500);
408
 
409
                socket->packets_resent++;
410
 
411
                /* Disable ethmac_int interrupt */
412
                *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLECLR ) = 0x100;
413
 
414
                strncpy((char*)ETHMAC_TX_BUFFER, socket->tcp_buf[i]->buf, socket->tcp_buf[i]->len_bytes);
415
                tx_packet(socket->tcp_buf[i]->len_bytes);  // MAC header, IP header, TCP header, TCP options
416
                socket->packets_sent++;
417
 
418
 
419
                /* Enable ethmac_int interrupt */
420
                *(unsigned int *) ( ADR_AMBER_IC_IRQ0_ENABLESET ) = 0x100;
421
                break;
422
                }
423
            }
424
        }
425
}
426
 
427
 
428
/* return the starting seq number for this packet */
429
unsigned int tcp_header(char *buf, socket_t* socket, int payload_length, int options)
430
{
431
    unsigned short header_checksum;
432
    unsigned int seq_num;
433
    unsigned int ack_num;
434
    char flags = 0;
435
    unsigned short len_tcp;
436
    unsigned int starting_seq;
437
 
438
    /* Source Port */
439
    buf[0] = socket->rx_packet->tcp_dst_port >>8;
440
    buf[1] = socket->rx_packet->tcp_dst_port &0xff;
441
 
442
    /* Destination Port */
443
    buf[2] = socket->rx_packet->tcp_src_port >>8;
444
    buf[3] = socket->rx_packet->tcp_src_port &0xff;
445
 
446
    /* Sequence Number */
447
    /* Increment the sequence number for the next packet */
448
    starting_seq = socket->tcp_seq;
449
    socket->tcp_last_seq = socket->tcp_seq;
450
    socket->tcp_seq += payload_length;
451
 
452
 
453
    buf[4] =  starting_seq>>24;
454
    buf[5] = (starting_seq>>16)&0xff;
455
    buf[6] = (starting_seq>>8)&0xff;
456
    buf[7] =  starting_seq&0xff;
457
 
458
 
459
    /* Ack Number */
460
    if (options == TCP_NEW)
461
        ack_num = socket->rx_packet->tcp_seq + 1;
462
    else if (socket->rx_packet->tcp_flags & 0x01) // FIN 
463
        // +1 to the final ack
464
        ack_num = socket->rx_packet->tcp_seq + 1;
465
    else
466
        ack_num = socket->rx_packet->tcp_seq + socket->rx_packet->tcp_payload_len;
467
 
468
    buf[8]  =  ack_num>>24;
469
    buf[9]  = (ack_num>>16)&0xff;
470
    buf[10] = (ack_num>>8)&0xff;
471
    buf[11] =  ack_num&0xff;
472
 
473
 
474
    /* Data offset with OPTIONS */
475
    if (options == TCP_NEW)
476
        buf[12] = 0xa0;  /* upper 4 bits, min is 5 */
477
    else
478
        buf[12] = 0x50;  /* upper 4 bits, min is 5 */
479
 
480
 
481
    /* Flags */
482
    flags = 0x10;       /* ACK */
483
    if (options == TCP_NEW)    /* Valid in first reply in new connection only */
484
        flags |= 0x02;  /* SYNchronise */
485
    if (socket->tcp_disconnect)
486
        flags |= 0x01;  /* FINish */
487
    if (socket->tcp_reset)
488
        flags |= 0x04;  /* Reset */
489
 
490
    buf[13] = flags;
491
 
492
    /* Window Size */
493
    buf[14] = socket->rx_packet->tcp_window_size >> 8;
494
    buf[15] = socket->rx_packet->tcp_window_size & 0xff;
495
 
496
    /* Checksum */
497
    buf[16] = 0;
498
    buf[17] = 0;
499
 
500
    /* Urgent Pointer */
501
    buf[18] = 0;
502
    buf[19] = 0;
503
 
504
 
505
    if (options == TCP_NEW) {
506
        /* OPTION: max seg size */
507
        buf[20] = 0x02;
508
        buf[21] = 0x04;
509
        buf[22] = 0x05;
510
        buf[23] = 0xb4;
511
 
512
        /* OPTION Sack OK */
513
        buf[24] = 0x04;
514
        buf[25] = 0x02;
515
 
516
        /* OPTION Time Stamp */
517
        buf[26] = 0x08;
518
        buf[27] = 0x0a;
519
        buf[28] = 0x00;
520
        buf[29] = 0x61;
521
        buf[30] = 0x1f;
522
        buf[31] = 0xc6;
523
        buf[32] =  socket->rx_packet->tcp_src_time_stamp>>24;
524
        buf[33] = (socket->rx_packet->tcp_src_time_stamp>>16)&0xff;
525
        buf[34] = (socket->rx_packet->tcp_src_time_stamp>>8)&0xff;
526
        buf[35] =  socket->rx_packet->tcp_src_time_stamp&0xff;
527
 
528
        /* OPTION: NOP */
529
        buf[36] = 0x01;
530
 
531
        /* OPTION Window Scale */
532
        buf[37] = 0x03;
533
        buf[38] = 0x03;
534
        buf[39] = 0x06;
535
        }
536
 
537
 
538
    /* Length */
539
    if (options == TCP_NEW)
540
        len_tcp = 40+payload_length;
541
    else
542
        len_tcp = 20+payload_length;
543
 
544
 
545
    /* header checksum */
546
    header_checksum = tcp_checksum(buf, socket->rx_packet, len_tcp);
547
    buf[16] = (header_checksum>>8)&0xff;
548
    buf[17] = header_checksum&0xff;
549
 
550
    return starting_seq;
551
}
552
 
553
 
554
unsigned short tcp_checksum(unsigned char *buf, packet_t* rx_packet, unsigned short len_tcp)
555
{
556
    unsigned short prot_tcp=6;
557
    unsigned short word16;
558
    unsigned long  sum;
559
    int i;
560
 
561
    //initialize sum to zero
562
    sum=0;
563
    if (!len_tcp) len_tcp = rx_packet->tcp_len;
564
 
565
 
566
    // add the TCP pseudo header which contains:
567
    // the IP source and destinationn addresses,
568
    for (i=0;i<4;i=i+2){
569
            word16 =((rx_packet->src_ip[i]<<8)&0xFF00)+(rx_packet->src_ip[i+1]&0xFF);
570
            sum=sum+word16;
571
    }
572
    for (i=0;i<4;i=i+2){
573
            word16 =((rx_packet->dst_ip[i]<<8)&0xFF00)+(rx_packet->dst_ip[i+1]&0xFF);
574
            sum=sum+word16;
575
    }
576
    // the protocol number and the length of the TCP packet
577
    sum = sum + prot_tcp + len_tcp;
578
 
579
 
580
    return header_checksum16(buf, len_tcp, sum);
581
}
582
 

powered by: WebSVN 2.1.0

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