[国嵌攻略][068][tftp网络协议实现]

IP协议结构

UDP协议结构

TFTP协议结构

 

TFTP端口

读写请求端口: 69

其他请求端口:1024~65535

 

 

主程序

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
/********************************************************************
*名称:menu
*参数:
*   none
*返回:
*   none
*功能:菜单命令
*********************************************************************/
void menu(){
    int num = 0;   //输入选项
 
    //显示菜单
    printf("\n");
    printf("**********************************************************************\n");
    printf("*                             Bootloader                             *\n");
    printf("*[1]Get MAC Address.                                                 *\n");
    printf("*[2]Download Kernel.                                                 *\n");
    printf("*[3]                                                                 *\n");
    printf("**********************************************************************\n");
    printf("Please Select: ");
     
    //选择菜单
    scanf("%d", &num);
    switch(num){
        case 1:   //获取物理地址
            send_arp_req();
            isDisplay = 0;   //关闭显示菜单,等待获取物理地址
            break;
         
        case 2:   //下载内核文件
            send_tftp_read_req();
            isDisplay = 0;   //关闭显示菜单,等待下载内核文件
            break;
             
        default:
            break;
    }
}

 

 

 

网络头文件

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
/********************************************************************
*名称:net.h
*作者:D
*时间:2015.11.28
*功能:网络协议头文件
*********************************************************************/
 
/********************************************************************
*宏定义
*********************************************************************/
//MAC协议
#define ETH_IP   0x0800  //IP
#define ETH_ARP  0x0806  //ARP
#define ETH_RARP 0x0805  //RARP
 
//ARP协议
#define ARP_ETH 0x0001   //Ethernet
#define ARP_REQ 0x0001   //Request
#define ARP_ACK 0x0002   //Acknowledge
 
//IP协议
#define IP_VHL 0x45     //version:4, header length:20byte
#define IP_TOS 0x00     //type of service
#define IP_ID  0x0000   //identifiier
#define IP_OFF 0x4000   //flags and fragment offset
#define IP_TTL 0xFF     //time of live
#define IP_TCP 0x06     //TCP
#define IP_UDP 0x11     //UDP
#define IP_SUM 0x0000   //clear checksum
#define IP_LEN 20       //header length
 
//UDP协议
#define UDP_TFTP_SRC 48915   //源端口
#define UDP_TFTP_DST 69      //目的端口
#define UDP_SUM 0            //假校验和
 
//TFTP协议
#define TFTP_RRQ 0x0001   //Read Request
#define TFTP_WRQ 0x0002   //Write Request
#define TFTP_DAT 0x0003   //File Data
#define TFTP_ACK 0x0004   //Data Acknowledge
#define TFTP_ERR 0x0005   //Error
 
#define TFTP_DONWLOAD 0x31000000   //TFTP下载地址
 
/*----------------------------------------分割线----------------------------------------*/
 
#define EH_ADR_LEN 6       //物理地址长度
#define IP_ADR_LEN 4       //协议地址长度
#define ETH_PKT_MIN 64     //以太网帧最小长度
#define ETH_PKT_MAX 1518   //以太网帧最大长度
 
#define ETH_DAT_LEN  (ETH_PKT_MAX - sizeof(EHHDR))             //MAC数据部分长度
#define IP_DAT_LEN   (ETH_DAT_LEN - sizeof(IPHDR))             //IP数据部分长度
#define UDP_DAT_LEN  (IP_DAT_LEN - sizeof(UDPHDR))             //UDP数据部分长度
#define TFTP_REQ_LEN (UDP_DAT_LEN - sizeof(TFTPHDR))           //TFTP请求数据部分长度
#define TFTP_ACK_LEN (TFTP_REQ_LEN - sizeof(unsigned short))   //TFTP响应数据部分长度
#define TFTP_DAT_LEN 512                                       //TFTP数据响应最大长度
 
/*----------------------------------------分割线----------------------------------------*/
 
#define HTONS(n) ( (((n)&0xFF00)>>8) | (((n)&0x00FF)<<8) )   //把unsigned short类型的主机序转换到网络序
#define NTOHS(n) ( (((n)&0xFF00)>>8) | (((n)&0x00FF)<<8) )   //把unsigned short类型的网络序转换到主机序
 
/********************************************************************
*类型定义
*********************************************************************/
//MAC头部
typedef struct ehhdr
{
    unsigned char eh_dst[6];   //destination ethernet addrress
    unsigned char eh_src[6];   //source ethernet addresss
    unsigned short eh_type;    //ethernet packet type
}EHHDR;
 
//MAC帧
typedef struct ehPacket
{
    EHHDR ehhdr;             //MAC头部
     
    unsigned char data[ETH_DAT_LEN];   //MAC数据
}EHPACKET;
 
/*----------------------------------------分割线----------------------------------------*/
 
//ARP头部
typedef struct arphdr
{
    unsigned short arp_hrd;   //format of hardware address
    unsigned short arp_pro;   //format of protocol address
     
    unsigned char  arp_hln;   //length of hardware address
    unsigned char  arp_pln;   //length of protocol address
    unsigned short arp_op;    //ARP/RARP operation
 
    unsigned char arp_sha[6];   //sender hardware address
    unsigned char arp_spa[4];   //sender protocol address
    unsigned char arp_tha[6];   //target hardware address
    unsigned char arp_tpa[4];   //target protocol address
}ARPHDR;
 
//ARP报文包
typedef struct arpPacket
{
    EHHDR ehhdr;     //MAC头部
    ARPHDR arphdr;   //ARP头部
}ARPPACKET;
 
/*----------------------------------------分割线----------------------------------------*/
 
//IP头部
typedef struct iphdr
{
    unsigned char  ip_vhl;   //version and header length
    unsigned char  ip_tos;   //type of service
    unsigned short ip_len;   //total length
     
    unsigned short ip_id;    //identifiier
    unsigned short ip_off;   //flags and fragment offset
     
    unsigned char  ip_ttl;   //time of live
    unsigned char  ip_pro;   //protocol
    unsigned short ip_sum;   //header checksum
     
    unsigned char ip_src[IP_ADR_LEN];   //source address
    unsigned char ip_dst[IP_ADR_LEN];   //destination address
}IPHDR;
 
//IP报文包
typedef struct ipPacket
{
    EHHDR ehhdr;             //MAC头部
    IPHDR iphdr;             //IP头部
     
    unsigned char data[IP_DAT_LEN];   //IP数据
}IPPACKET;
 
/*----------------------------------------分割线----------------------------------------*/
 
//UDP头部
typedef struct udphdr
{
    unsigned short udp_sport;   //source port
    unsigned short udp_dport;   //destination port
     
    unsigned short udp_len;     //length
    unsigned short udp_sum;     //checksum
}UDPHDR;
 
//UDP报文包
typedef struct udpPacket
{
    EHHDR ehhdr;             //MAC头部
    IPHDR iphdr;             //IP头部
    UDPHDR udphdr;           //UDP头部
     
    unsigned char data[UDP_DAT_LEN];   //UDP数据
}UDPPACKET;
 
/*----------------------------------------分割线----------------------------------------*/
 
//TFTP头部
typedef struct tftphdr
{
    unsigned short tftp_op;   //opcode
}TFTPHDR;
 
//TFTP请求包
typedef struct tftpReqPacket
{
    EHHDR ehhdr;             //MAC头部
    IPHDR iphdr;             //IP头部
    UDPHDR udphdr;           //UDP头部
    TFTPHDR tftphdr;         //TFTP头部
     
    unsigned char data[TFTP_REQ_LEN];   //TFTP数据
}TFTPREQPACKET;
 
//TFTP响应包
typedef struct tftpAckPacket
{
    EHHDR ehhdr;             //MAC头部
    IPHDR iphdr;             //IP头部
    UDPHDR udphdr;           //UDP头部
    TFTPHDR tftphdr;         //TFTP头部
     
    unsigned short blocknum;            //TFTP块号
    unsigned char data[TFTP_ACK_LEN];   //TFTP数据
}TFTPACKPACKET;

 

 

 

网卡中断

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
/********************************************************************
*名称:dm9000_irq
*参数:
*   none
*返回:
*   none
*功能:网卡中断服务
*********************************************************************/
void dm9000_irq(){
    int state;             //接收状态
    EHPACKET *eh_packet;   //MAC帧
     
    //接收网卡数据
    state = rx_dm9000(packet);
     
    //处理网卡数据
    if(state){   //如果接收成功,那么处理数据
        //转换成MAC帧
        eh_packet = (EHPACKET *)packet;
         
        //提供网络接口层服务
        switch(NTOHS(eh_packet->ehhdr.eh_type)){   //判断网络层协议
            case ETH_IP:    //IP协议
                rece_ip_pro(eh_packet);
                break;
                 
            case ETH_ARP:   //ARP协议
                rece_arp_pro(eh_packet);
                break;
                 
            default:
                break;
        }
    }
     
    //清除外部中断请求
    EINTPEND |= (1<<7);   //EINT8:cleard
     
    //清除中断源请求
    SRCPND |= (1<<4);   //EINT4_7:cleard
     
    //清除中断请求
    INTPND |= (1<<4);   //EINT4_7:cleard
}

 

 

 

ARP协议

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
/********************************************************************
*名称:arp.c
*作者:D
*时间:2015.11.26
*功能:ARP协议
*********************************************************************/
 
/********************************************************************
*头文件
*********************************************************************/
#include "net.h"
 
/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char eh_src[EH_ADR_LEN];   //物理源地址
extern unsigned char eh_dst[EH_ADR_LEN];   //物理目的地址
extern unsigned char ip_src[IP_ADR_LEN];   //协议源地址
extern unsigned char ip_dst[IP_ADR_LEN];   //协议目的地址
 
extern int isDisplay;   //是否显示菜单标志
 
/********************************************************************
*函数原型声明
*********************************************************************/
void send_arp_req();
void rece_arp_pro(ARPPACKET *arp_packet);
void send_arp_ack(ARPPACKET *arp_packet);
void rece_arp_ack(ARPPACKET *arp_packet);
 
int create_arp_packet(ARPPACKET *arp_packet, unsigned short arp_op);
int get_arp_dst_adr(ARPPACKET *arp_packet);
void get_arp_src_adr(ARPPACKET *arp_packet);
void put_arp_src_adr();
 
/********************************************************************
*名称:send_arp_req
*参数:
*   none
*返回:
*   none
*功能:发送ARP请求包
*********************************************************************/
void send_arp_req(){
    int length = 0;             //MAC帧长度
    ARPPACKET arp_req_packet;   //ARP请求包
     
    //创建ARP请求包
    length = create_arp_packet(&arp_req_packet, ARP_REQ);
     
    //发送ARP请求包
    tx_dm9000(&arp_req_packet, length);
}
 
/********************************************************************
*名称:rece_arp_pro
*参数:
*   arp_packet   ARP报文包
*返回:
*   none
*功能:接收ARP协议
*********************************************************************/
void rece_arp_pro(ARPPACKET *arp_packet){
    //提取目的地址
    if( !get_arp_dst_adr(arp_packet) ){   //如果IP目的地址不匹配,那么返回
        return ;
    }
     
    //提供网络层服务
    switch(NTOHS(arp_packet->arphdr.arp_op)){   //判断ARP操作码
        case ARP_REQ:   //ARP请求
            send_arp_ack(arp_packet);
            break;
             
        case ARP_ACK:   //ARP响应
            rece_arp_ack(arp_packet);
            break;
         
        default:
            break;
    }
}
 
/********************************************************************
*名称:send_arp_ack
*参数:
*   arp_packet   ARP报文包
*返回:
*   none
*功能:发送ARP响应包
*********************************************************************/
void send_arp_ack(ARPPACKET *arp_packet){
    int length = 0;             //MAC帧长度
    ARPPACKET arp_ack_packet;   //ARP响应包
     
    //提取源地址
    get_arp_src_adr(arp_packet);
     
    //创建ARP响应包
    length = create_arp_packet(&arp_ack_packet, ARP_ACK);
     
    //发送ARP响应包
    tx_dm9000(&arp_ack_packet, length);
}
 
/********************************************************************
*名称:rece_arp_ack
*参数:
*   arp_packet   ARP报文包
*返回:
*   none
*功能:接收ARP响应包
*********************************************************************/
void rece_arp_ack(ARPPACKET *arp_packet){
    //提取源地址
    get_arp_src_adr(arp_packet);
     
    //打印源地址
    put_arp_src_adr();
     
    //打开显示菜单
    isDisplay = 1;
}
 
/*----------------------------------------分割线----------------------------------------*/
 
/********************************************************************
*名称:create_arp_packet
*参数:
*   arp_packet   ARP报文包
*   arp_op       ARP操作码
*返回:
*   length       MAC帧长度
*功能:创建ARP报文包
*********************************************************************/
int create_arp_packet(ARPPACKET *arp_packet, unsigned short arp_op){
    int length = 0;
 
    //填充ARP头部
    length = length + sizeof(ARPHDR);              //ARP报文长度
    arp_packet->arphdr.arp_hrd = HTONS(ARP_ETH);   //硬件类型
    arp_packet->arphdr.arp_pro = HTONS(ETH_IP);    //协议类型
    arp_packet->arphdr.arp_hln = EH_ADR_LEN;       //MAC地址长度
    arp_packet->arphdr.arp_pln = IP_ADR_LEN;       //IP地址长度
    arp_packet->arphdr.arp_op  = HTONS(arp_op);    //操作类型
     
    memcpy(arp_packet->arphdr.arp_sha, eh_src, EH_ADR_LEN);   //MAC源地址
    memcpy(arp_packet->arphdr.arp_spa, ip_src, IP_ADR_LEN);   //IP源地址
    memcpy(arp_packet->arphdr.arp_tha, eh_dst, EH_ADR_LEN);   //MAC目的地址
    memcpy(arp_packet->arphdr.arp_tpa, ip_dst, IP_ADR_LEN);   //IP目的地址
     
    //填充MAC头部
    length = length + sizeof(EHHDR);                        //MAC帧长度
    memcpy(arp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
    memcpy(arp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
    arp_packet->ehhdr.eh_type = HTONS(ETH_ARP);             //MAC帧类型
     
    return length;
}
 
/********************************************************************
*名称:get_arp_dst_adr
*参数:
*   arp_packet   ARP报文包
*返回:
*   return       1 匹配成功
*                0 匹配失败
*功能:提取目的地址
*********************************************************************/
int get_arp_dst_adr(ARPPACKET *arp_packet){
    unsigned char arp_ip_dst[IP_ADR_LEN];   //IP目的地址
     
    //提取IP目的地址
    memcpy(arp_ip_dst, arp_packet->arphdr.arp_tpa, IP_ADR_LEN);
     
    //判断IP目的地址
    if(memcmp(arp_ip_dst, ip_src, IP_ADR_LEN) != 0){   //如果目的地址不等于该主机IP地址,那么匹配失败
        return 0;
    }
     
    return 1;   //匹配成功
}
 
/********************************************************************
*名称:get_arp_src_adr
*参数:
*   arp_packet   ARP报文包
*返回:
*   none
*功能:提取源地址
*********************************************************************/
void get_arp_src_adr(ARPPACKET *arp_packet){
    memcpy(eh_dst, arp_packet->arphdr.arp_sha, EH_ADR_LEN);   //提取MAC源地址,并写到目的地址
    memcpy(ip_dst, arp_packet->arphdr.arp_spa, IP_ADR_LEN);   //提取IP源地址,并写到目的地址
}
 
/********************************************************************
*名称:put_arp_src_adr
*参数:
*   none
*返回:
*   none
*功能:打印源地址
*********************************************************************/
void put_arp_src_adr(){
    int i;
 
    printf("\nIP  Address : ");
    for(i = 0; i < IP_ADR_LEN; i++){
        printf("%d.", ip_dst[i]);   //打印IP源地址
    }
    printf("\b \n");
     
    printf("MAC Address : ");
    for(i = 0; i < EH_ADR_LEN; i++){
        printf("%02X:", eh_dst[i]);   //打印MAC源地址
    }
    printf("\b \n");
}

 

 

 

IP协议

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
/********************************************************************
*名称:ip.c
*作者:D
*时间:2015.11.28
*功能:IP协议
*********************************************************************/
 
/********************************************************************
*头文件
*********************************************************************/
#include "net.h"
 
/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char ip_src[IP_ADR_LEN];   //IP源地址
 
/********************************************************************
*函数原型声明
*********************************************************************/
void rece_ip_pro(IPPACKET *ip_packet);
int get_ip_dst_adr(IPPACKET *ip_packet);
 
/********************************************************************
*名称:rece_ip_pro
*参数:
*   ip_packet   IP报文包
*返回:
*   none
*功能:接收IP协议
*********************************************************************/
void rece_ip_pro(IPPACKET *ip_packet){
    //提取目的地址
    if( !get_ip_dst_adr(ip_packet) ){   //如果IP目的地址不匹配,那么返回
        return ;
    }
 
    //提供网络层服务
    switch(ip_packet->iphdr.ip_pro){   //判断运输层协议
        case IP_UDP:   //UDP协议
            rece_udp_pro(ip_packet);
            break;
         
        default:
            break;
    }
}
 
/********************************************************************
*名称:get_ip_dst_adr
*参数:
*   ip_packet   IP报文包
*返回:
*   return      1 匹配成功
*               0 匹配失败
*功能:提取目的地址
*********************************************************************/
int get_ip_dst_adr(IPPACKET *ip_packet){
    unsigned char ip_dst_adr[IP_ADR_LEN];   //IP目的地址
     
    //提取IP目的地址
    memcpy(ip_dst_adr, ip_packet->iphdr.ip_dst, IP_ADR_LEN);
     
    //判断IP目的地址
    if(memcmp(ip_dst_adr, ip_src, IP_ADR_LEN) != 0){   //如果目的地址不等于该主机IP地址,那么匹配失败
        return 0;
    }
     
    return 1;   //匹配成功
}

 

 

 

UDP协议

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
/********************************************************************
*名称:udp.c
*作者:D
*时间:2015.11.30
*功能:UDP协议
*********************************************************************/
 
/********************************************************************
*头文件
*********************************************************************/
#include "net.h"
 
/********************************************************************
*函数原型声明
*********************************************************************/
void rece_udp_pro(UDPPACKET *udp_packet);
 
/********************************************************************
*名称:rece_udp_pro
*参数:
*   udp_packet   UDP报文包
*返回:
*   none
*功能:接收UDP协议
*********************************************************************/
void rece_udp_pro(UDPPACKET *udp_packet){
    //提供运输层服务
    switch(NTOHS(udp_packet->udphdr.udp_dport)){   //判断应用层端口
        case UDP_TFTP_SRC:   //TFTP协议源端口
            rece_tftp_pro(udp_packet);
            break;
         
        default:
            break;
    }
}

 

 

 

TFTP协议

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
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
/********************************************************************
*名称:tftp.c
*作者:D
*时间:2015.11.29
*功能:TFTP协议
*********************************************************************/
 
/********************************************************************
*头文件
*********************************************************************/
#include "net.h"
 
/********************************************************************
*全局变量声明
*********************************************************************/
//外部变量,定义在DM9000.c中
extern unsigned char eh_src[EH_ADR_LEN];   //物理源地址
extern unsigned char eh_dst[EH_ADR_LEN];   //物理目的地址
extern unsigned char ip_src[IP_ADR_LEN];   //协议源地址
extern unsigned char ip_dst[IP_ADR_LEN];   //协议目的地址
 
extern int isDisplay;   //是否显示菜单标志
 
unsigned short reqblknum;       //TFTP请求块号
unsigned char *tftp_download;   //TFTP下载地址
 
/********************************************************************
*函数原型声明
*********************************************************************/
void send_tftp_read_req();
void rece_tftp_pro(TFTPACKPACKET *tftp_packet);
void rece_tftp_data_ack(TFTPACKPACKET *tftp_packet);
 
int get_tftp_data_ack(TFTPACKPACKET *tftp_packet, unsigned short *blocknum, unsigned short *udpdport);
int create_tftp_req_packet(TFTPREQPACKET *tftp_packet, unsigned short tftp_op, const char *filename, const char *mode);
int create_tftp_ack_packet(TFTPACKPACKET *tftp_packet, unsigned short tftp_op, unsigned short blocknum, unsigned short udpdport);
unsigned short checksum(unsigned short* iphdr, int size);
 
/********************************************************************
*名称:send_tftp_read_req
*参数:
*   none
*返回:
*   none
*功能:发送TFTP读请求包
*********************************************************************/
void send_tftp_read_req(){
    int length = 0;                  //MAC帧长度
    TFTPREQPACKET tftp_req_packet;   //TFTP请求包
     
    //设置TFTP请求块号
    reqblknum = 1;
     
    //设置TFTP下载地址
    tftp_download = (unsigned char *)TFTP_DONWLOAD;
 
    //创建TFTP读请求包
    length = create_tftp_req_packet(&tftp_req_packet, TFTP_RRQ, "boot.bin", "octet");
     
    //发送TFTP读请求包
    tx_dm9000(&tftp_req_packet, length);
}
 
/********************************************************************
*名称:rece_tftp_pro
*参数:
*   rece_tftp_pro   TFTP响应包
*返回:
*   none
*功能:接收TFTP协议
*********************************************************************/
void rece_tftp_pro(TFTPACKPACKET *tftp_packet){
    //提供应用层服务
    switch(NTOHS(tftp_packet->tftphdr.tftp_op)){   //判断TFTP操作码
        case TFTP_DAT:   //TFTP文件数据
            rece_tftp_data_ack(tftp_packet);
            break;
         
        default:
            break;
    }
}
 
/********************************************************************
*名称:rece_tftp_data_ack
*参数:
*   tftp_packet   TFTP响应包
*返回:
*   none
*功能:接收TFTP数据响应包
*********************************************************************/
void rece_tftp_data_ack(TFTPACKPACKET *tftp_packet){
    int length = 0;                  //MAC帧长度
    unsigned short blocknum = 0;     //TFTP块号
    unsigned short udpdport = 0;     //UDP目的端口
    TFTPACKPACKET tftp_ack_packet;   //TFTP响应包
     
    //提取数据响应包
    if( !get_tftp_data_ack(tftp_packet, &blocknum, &udpdport) ){   //如果提取失败,那么返回
        return ;
    }
     
    //创建TFTP响应包
    length  = create_tftp_ack_packet(&tftp_ack_packet, TFTP_ACK, blocknum, udpdport);
     
    //发送TFTP响应包
    tx_dm9000(&tftp_ack_packet, length);
}
 
/*----------------------------------------分割线----------------------------------------*/
 
/********************************************************************
*名称:get_tftp_data_ack
*参数:
*   tftp_packet   TFTP响应包
*   blocknum      TFTP块号
*   udpdport      UDP目的端口
*返回:
*   return        1 提取成功
*                 0 提取失败
*功能:提取TFTP数据响应包
*********************************************************************/
int get_tftp_data_ack(TFTPACKPACKET *tftp_packet, unsigned short *blocknum, unsigned short *udpdport){
    int i;
    int length = 0;   //TFTP数据长度
 
    //提取TFTP响应块号
    *blocknum = NTOHS(tftp_packet->blocknum);
    if(*blocknum != reqblknum){   //如果TFTP块号不等于请求块号,那么返回
        return 0;
    }
     
    //增加TFTP请求块号
    reqblknum++;
     
    //提取UDP目的端口
    *udpdport = NTOHS(tftp_packet->udphdr.udp_sport);
     
    //计算TFTP数据长度
    length = NTOHS(tftp_packet->udphdr.udp_len);   //提取UDP报文长度
    length = length - sizeof(UDPHDR);              //计算TFTP报文长度
    length = length - sizeof(TFTPHDR);             //计算TFTP数据长度
    length = length - sizeof(unsigned short);
     
    //提取TFTP响应数据
    for(i = 0; i < length; i++){
        *(tftp_download++) = tftp_packet->data[i];   //下载到指定内存地址
    }
     
    //判断最后数据响应
    if(length < TFTP_DAT_LEN){   //如果数据长度小于最大长度,那么发出最后响应包
        printf("\nTFTP Donwload Success!\n");
        isDisplay = 1;   //打开显示菜单
    }
     
    return 1;
}
 
/********************************************************************
*名称:create_tftp_req_packet
*参数:
*   tftp_packet   TFTP请求包
*   tftp_op       TFTP操作码
*   filename      请求文件名
*   mode          请求模式
*返回:
*   length        MAC帧长度
*功能:创建TFTP请求包
*********************************************************************/
int create_tftp_req_packet(TFTPREQPACKET *tftp_packet, unsigned short tftp_op, const char *filename, const char *mode){
    int i;
    int length = 0;
    unsigned char data[TFTP_REQ_LEN];   //TFTP数据
    unsigned short *iphdr;              //IP起始地址
    unsigned short chksum;              //IP头校验和
 
    //填充TFTP数据
    for(i = 0; i < strlen(filename); i++){   //填充请求文件名
        data[length++] = filename[i];
    }
    data[length++] = '\0';   //结束标志
     
    for(i = 0; i < strlen(mode); i++){   //填充请求模式
        data[length++] = mode[i];
    }
    data[length++] = '\0';   //结束标志
 
    memcpy(tftp_packet->data, data, length);   //填充TFTP数据
 
    //填充TFTP头部
    length = length + sizeof(TFTPHDR);                //TFTP报文长度
    tftp_packet->tftphdr.tftp_op = HTONS(tftp_op);    //填充操作码
 
    //填充UDP头部
    length =length + sizeof(UDPHDR);                       //UDP报文长度
    tftp_packet->udphdr.udp_sport = HTONS(UDP_TFTP_SRC);   //UDP源端口
    tftp_packet->udphdr.udp_dport = HTONS(UDP_TFTP_DST);   //UDP目的端口
    tftp_packet->udphdr.udp_len = HTONS(length);           //UDP报文长度
    tftp_packet->udphdr.udp_sum = HTONS(UDP_SUM);          //UDP头假校验和
 
    //填充IP头部
    length = length + sizeof(IPHDR);             //IP报文长度
    tftp_packet->iphdr.ip_vhl = IP_VHL;          //版本号:IPv4,协议头长度:20字节
    tftp_packet->iphdr.ip_tos = IP_TOS;          //普通服务类型
    tftp_packet->iphdr.ip_len = HTONS(length);   //IP报文长度
     
    tftp_packet->iphdr.ip_id = HTONS(IP_ID);    //标识符
    tftp_packet->iphdr.ip_off = HTONS(IP_OFF);  //标记
     
    tftp_packet->iphdr.ip_ttl = IP_TTL;   //生存时间
    tftp_packet->iphdr.ip_pro = IP_UDP;   //UDP协议
     
    memcpy(tftp_packet->iphdr.ip_src, ip_src, IP_ADR_LEN);   //IP源地址
    memcpy(tftp_packet->iphdr.ip_dst, ip_dst, IP_ADR_LEN);   //IP目的地址
     
    tftp_packet->iphdr.ip_sum = HTONS(IP_SUM);          //清零校验和
    iphdr = (unsigned short *)&(tftp_packet->iphdr);    //获取IP指针
    chksum = checksum(iphdr, IP_LEN);                   //计算校验和
    tftp_packet->iphdr.ip_sum = chksum;                 //头部校验和,注意不需要网络序转换,计算的本来就是网络序的校验和
     
    //填充MAC头部
    length = length + sizeof(EHHDR);                         //MAC帧长度
    memcpy(tftp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
    memcpy(tftp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
    tftp_packet->ehhdr.eh_type = HTONS(ETH_IP);              //MAC帧类型
     
    return length;
}
 
 
/********************************************************************
*名称:create_tftp_ack_packet
*参数:
*   tftp_packet   TFTP响应包
*   tftp_op       TFTP操作码
*   blocknum      TFTP块号
*   udpdport      UDP目的端口
*返回:
*   length        MAC帧长度
*功能:创建TFTP响应包
*********************************************************************/
int create_tftp_ack_packet(TFTPACKPACKET *tftp_packet, unsigned short tftp_op, unsigned short blocknum, unsigned short udpdport){
    int i;
    int length = 0;          //数据长度
    unsigned short *iphdr;   //IP起始地址
    unsigned short chksum;   //IP头校验和
 
    //填充TFTP块号
    length = length + sizeof(unsigned short);   //TFTP数据长度
    tftp_packet->blocknum = HTONS(blocknum);    //填充TFTP块号
 
    //填充TFTP头部
    length = length + sizeof(TFTPHDR);               //TFTP报文长度
    tftp_packet->tftphdr.tftp_op = HTONS(tftp_op);   //填充操作码
 
    //填充UDP头部
    length =length + sizeof(UDPHDR);                       //UDP报文长度
    tftp_packet->udphdr.udp_sport = HTONS(UDP_TFTP_SRC);   //UDP源端口
    tftp_packet->udphdr.udp_dport = HTONS(udpdport);       //UDP目的端口
    tftp_packet->udphdr.udp_len = HTONS(length);           //UDP数据包长度
    tftp_packet->udphdr.udp_sum = HTONS(UDP_SUM);          //UDP头假校验和
 
    //填充IP头部
    length = length + sizeof(IPHDR);             //IP报文长度
    tftp_packet->iphdr.ip_vhl = IP_VHL;          //版本号:IPv4,协议头长度:20字节
    tftp_packet->iphdr.ip_tos = IP_TOS;          //普通服务类型
    tftp_packet->iphdr.ip_len = HTONS(length);   //IP报文长度
     
    tftp_packet->iphdr.ip_id = HTONS(IP_ID);    //标识符
    tftp_packet->iphdr.ip_off = HTONS(IP_OFF);  //标记
     
    tftp_packet->iphdr.ip_ttl = IP_TTL;   //生存时间
    tftp_packet->iphdr.ip_pro = IP_UDP;   //UDP协议
     
    memcpy(tftp_packet->iphdr.ip_src, ip_src, IP_ADR_LEN);   //IP源地址
    memcpy(tftp_packet->iphdr.ip_dst, ip_dst, IP_ADR_LEN);   //IP目的地址
     
    tftp_packet->iphdr.ip_sum = HTONS(IP_SUM);          //清零校验和
    iphdr = (unsigned short *)&(tftp_packet->iphdr);    //获取IP地址
    chksum = checksum(iphdr, IP_LEN);                   //计算校验和
    tftp_packet->iphdr.ip_sum = chksum;                 //头部校验和,注意不需要网络序转换,计算的本来就是网络序的校验和
     
    //填充以太网帧头部
    length = length + sizeof(EHHDR);                         //MAC帧长度
    memcpy(tftp_packet->ehhdr.eh_dst, eh_dst, EH_ADR_LEN);   //MAC目的地址
    memcpy(tftp_packet->ehhdr.eh_src, eh_src, EH_ADR_LEN);   //MAC源地址
    tftp_packet->ehhdr.eh_type = HTONS(ETH_IP);              //MAC帧类型
     
    return length;
}
 
/********************************************************************
*名称:checksum
*参数:
*   iphdr    IP起始地址
*   size     IP头部长度
*返回:
*   chksum   IP头校验和
*功能:计算IP头校验和
*********************************************************************/
unsigned short checksum(unsigned short* iphdr, int size){
    unsigned long chksum = 0;
     
    while(size > 1){   //16位二进制求和
        chksum += *iphdr++;
        size -= sizeof(unsigned short);
    }
    if(size == 1){    //如果头部长度为奇数,那么再加上最后8位
        chksum += *((unsigned char*)iphdr);
    }
     
    chksum = (chksum>>16) + (chksum&0xFFFF);   //加上进位
    chksum += (chksum>>16);                    //加上进位产生的进位
     
    return (unsigned short)(~chksum);   //返回反码
}

 

posted @   盛夏夜  阅读(386)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
点击右上角即可分享
微信分享提示