-
Notifications
You must be signed in to change notification settings - Fork 8
/
tcp.c
246 lines (224 loc) · 9.79 KB
/
tcp.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
//********************************************************************************************
//
// File : tcp.c implement for Transmission Control Protocol
//
//********************************************************************************************
//
// Copyright (C) 2007
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software
// Foundation; either version 2 of the License, or (at your option) any later
// version.
// This program is distributed in the hope that it will be useful, but
//
// WITHOUT ANY WARRANTY;
//
// without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
// PURPOSE. See the GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin St, Fifth Floor, Boston, MA 02110, USA
//
// http://www.gnu.de/gpl-ger.html
//
//********************************************************************************************
#include "includes.h"
//********************************************************************************************
//
// +------------+-----------+------------+----------+
// + MAC header + IP header + TCP header + Data ::: +
// +------------+-----------+------------+----------+
//
// TCP Header
//
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +00+01+02+03+04+05+06+07+08+09+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Source Port + Destination Port +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Sequence Number +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Acknowledgment Number +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +Data Offset+reserved+ ECN + Control Bits + Window size +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Checksum + Urgent Pointer +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Options and padding ::: +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Data ::: +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
//
//********************************************************************************************
// global variables ***********************************************************************
static BYTE seqnum=0xa; // my initial tcp sequence number
//static DWORD_BYTES tcp_sequence_number;
//*****************************************************************************************
//
// Function : tcp_get_dlength
// Description : claculate tcp received data length
//
//*****************************************************************************************
WORD tcp_get_dlength ( BYTE *rxtx_buffer )
{
int dlength, hlength;
dlength = ( rxtx_buffer[ IP_TOTLEN_H_P ] <<8 ) | ( rxtx_buffer[ IP_TOTLEN_L_P ] );
dlength -= sizeof(IP_HEADER);
hlength = (rxtx_buffer[ TCP_HEADER_LEN_P ]>>4) * 4; // generate len in bytes;
dlength -= hlength;
if ( dlength <= 0 )
dlength=0;
return ((WORD)dlength);
}
//*****************************************************************************************
//
// Function : tcp_get_hlength
// Description : claculate tcp received header length
//
//*****************************************************************************************
BYTE tcp_get_hlength ( BYTE *rxtx_buffer )
{
return ((rxtx_buffer[ TCP_HEADER_LEN_P ]>>4) * 4); // generate len in bytes;
}
//********************************************************************************************
//
// Function : tcp_puts_data_p
// Description : puts data from program memory to tx buffer
//
//********************************************************************************************
WORD tcp_puts_data_p ( BYTE *rxtx_buffer, PGM_P data, WORD offset )
{
BYTE ch;
while( (ch = pgm_read_byte(data++)) )
{
rxtx_buffer[ TCP_DATA_P + offset ] = ch;
offset++;
}
return offset;
}
//********************************************************************************************
//
// Function : tcp_puts_data
// Description : puts data from RAM to tx buffer
//
//********************************************************************************************
WORD tcp_puts_data ( BYTE *rxtx_buffer, BYTE *data, WORD offset )
{
while( *data )
{
rxtx_buffer[ TCP_DATA_P + offset ] = *data++;
offset++;
}
return offset;
}
//********************************************************************************************
//
// Function : tcp_send_packet
// Description : send tcp packet to network.
//
//********************************************************************************************
void tcp_send_packet (
BYTE *rxtx_buffer,
WORD_BYTES dest_port,
WORD_BYTES src_port,
BYTE flags,
BYTE max_segment_size,
BYTE clear_seqack,
WORD next_ack_num,
WORD dlength,
BYTE *dest_mac,
BYTE *dest_ip )
{
BYTE i, tseq;
WORD_BYTES ck;
// generate ethernet header
eth_generate_header ( rxtx_buffer, (WORD_BYTES){ETH_TYPE_IP_V}, dest_mac );
// sequence numbers:
// add the rel ack num to SEQACK
if ( next_ack_num )
{
for( i=4; i>0; i-- )
{
next_ack_num = rxtx_buffer [ TCP_SEQ_P + i - 1] + next_ack_num;
tseq = rxtx_buffer [ TCP_SEQACK_P + i - 1];
rxtx_buffer [ TCP_SEQACK_P + i - 1] = 0xff & next_ack_num;
// copy the acknum sent to us into the sequence number
rxtx_buffer[ TCP_SEQ_P + i - 1 ] = tseq;
next_ack_num >>= 8;
}
}
// initial tcp sequence number
// setup maximum segment size
// require to setup first packet is receive or transmit only
if ( max_segment_size )
{
// initial sequence number
rxtx_buffer[ TCP_SEQ_P + 0 ] = 0;
rxtx_buffer[ TCP_SEQ_P + 1 ] = 0;
rxtx_buffer[ TCP_SEQ_P + 2 ] = seqnum;
rxtx_buffer[ TCP_SEQ_P + 3 ] = 0;
seqnum += 2;
// setup maximum segment size
rxtx_buffer[ TCP_OPTIONS_P + 0 ] = 2;
rxtx_buffer[ TCP_OPTIONS_P + 1 ] = 4;
rxtx_buffer[ TCP_OPTIONS_P + 2 ] = HIGH(1408);
rxtx_buffer[ TCP_OPTIONS_P + 3 ] = LOW(1408);
// setup tcp header length 24 bytes: 6*32/8 = 24
rxtx_buffer[ TCP_HEADER_LEN_P ] = 0x60;
dlength += 4;
}
else
{
// no options: 20 bytes: 5*32/8 = 20
rxtx_buffer[ TCP_HEADER_LEN_P ] = 0x50;
}
// generate ip header and checksum
ip_generate_header ( rxtx_buffer, (WORD_BYTES){(sizeof(IP_HEADER) + sizeof(TCP_HEADER) + dlength)}, IP_PROTO_TCP_V, dest_ip );
// clear sequence ack number before send tcp SYN packet
if ( clear_seqack )
{
rxtx_buffer[ TCP_SEQACK_P + 0 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 1 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 2 ] = 0;
rxtx_buffer[ TCP_SEQACK_P + 3 ] = 0;
}
// setup tcp flags
rxtx_buffer [ TCP_FLAGS_P ] = flags;
// setup destination port
rxtx_buffer [ TCP_DST_PORT_H_P ] = dest_port.byte.high;
rxtx_buffer [ TCP_DST_PORT_L_P ] = dest_port.byte.low;
// setup source port
rxtx_buffer [ TCP_SRC_PORT_H_P ] = src_port.byte.high;
rxtx_buffer [ TCP_SRC_PORT_L_P ] = src_port.byte.low;
// setup maximum windows size
rxtx_buffer [ TCP_WINDOWSIZE_H_P ] = HIGH((MAX_RX_BUFFER-sizeof(IP_HEADER)-sizeof(ETH_HEADER)));
rxtx_buffer [ TCP_WINDOWSIZE_L_P ] = LOW((MAX_RX_BUFFER-sizeof(IP_HEADER)-sizeof(ETH_HEADER)));
// setup urgend pointer (not used -> 0)
rxtx_buffer[ TCP_URGENT_PTR_H_P ] = 0;
rxtx_buffer[ TCP_URGENT_PTR_L_P ] = 0;
// clear old checksum and calculate new checksum
rxtx_buffer[ TCP_CHECKSUM_H_P ] = 0;
rxtx_buffer[ TCP_CHECKSUM_L_P ] = 0;
// This is computed as the 16-bit one's complement of the one's complement
// sum of a pseudo header of information from the
// IP header, the TCP header, and the data, padded
// as needed with zero bytes at the end to make a multiple of two bytes.
// The pseudo header contains the following fields:
//
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// +00+01+02+03+04+05+06+07+08+09+10+11+12+13+14+15+16+17+18+19+20+21+22+23+24+25+26+27+28+29+30+31+
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Source IP address +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + Destination IP address +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
// + 0 + IP Protocol + Total length +
// +--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+--+
ck.word = software_checksum( &rxtx_buffer[IP_SRC_IP_P], sizeof(TCP_HEADER)+dlength+8, IP_PROTO_TCP_V + sizeof(TCP_HEADER) + dlength );
rxtx_buffer[ TCP_CHECKSUM_H_P ] = ck.byte.high;
rxtx_buffer[ TCP_CHECKSUM_L_P ] = ck.byte.low;
// send packet to ethernet media
enc28j60_packet_send ( rxtx_buffer, sizeof(ETH_HEADER)+sizeof(IP_HEADER)+sizeof(TCP_HEADER)+dlength );
}