-
Notifications
You must be signed in to change notification settings - Fork 5
/
arp.cpp
191 lines (169 loc) · 5.76 KB
/
arp.cpp
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
#include "arduino_app.h"
#include <cstring>
#include "arp.h"
#include "ethernet.h"
#include "util.h"
#include "netconf.h"
#include "protohdr.h"
using namespace std;
arpentry arptable[MAX_ARPTABLE];
static int next_register = 0; //次の登録位置
#define RESULT_FOUND 0
#define RESULT_NOT_FOUND 1
#define RESULT_ADD_LIST 2
static int search_arptable(uint32_t ipaddr, uint8_t macaddr[], hdrstack *flm){
wai_sem(ARPTBL_SEM);
for(int i=0;i<MAX_ARPTABLE;i++){
if(arptable[i].ipaddr == ipaddr && arptable[i].timeout>0){
int result;
if(arptable[i].pending==NULL){
//保留無し->アドレス解決できてる
memcpy(macaddr, arptable[i].macaddr, ETHER_ADDR_LEN);
result = RESULT_FOUND;
}else{
//保留となっているフレームが他にもある
flist *pf = new flist;
pf->flm = flm; pf->next = NULL;
flist *ptr = arptable[i].pending;
//受付順に送信するため、末尾に挿入
while(ptr->next!=NULL)
ptr=ptr->next;
ptr->next = pf;
result = RESULT_ADD_LIST;
}
sig_sem(ARPTBL_SEM);
return result;
}
}
//登録なしなので、IPアドレスだけ登録。保留リストに入れる
if(arptable[next_register].pending!=NULL){
delete arptable[next_register].pending;
arptable[next_register].pending = NULL;
}
flist *pf = new flist;
pf->flm = flm; pf->next = NULL;
arptable[next_register].pending = pf;
arptable[next_register].timeout=ARBTBL_TIMEOUT_CLC;
arptable[next_register].ipaddr = ipaddr;
next_register = (next_register+1) % MAX_ARPTABLE;
sig_sem(ARPTBL_SEM);
return RESULT_NOT_FOUND;
}
void register_arptable(uint32_t ipaddr, uint8_t macaddr[], bool is_permanent){
wai_sem(ARPTBL_SEM);
//IPアドレスだけ登録されている(アドレス解決待ち)エントリを探す
for(int i=0;i<MAX_ARPTABLE;i++){
if(arptable[i].ipaddr == ipaddr && arptable[i].timeout>0){
arptable[i].timeout=is_permanent?ARPTBL_PERMANENT:ARBTBL_TIMEOUT_CLC; //延長
if(arptable[i].pending!=NULL){
memcpy(arptable[i].macaddr, macaddr,ETHER_ADDR_LEN);
flist *ptr = arptable[i].pending;
while(ptr!=NULL){
ether_hdr *ehdr = (ether_hdr*)ptr->flm->buf;
//宛先MACアドレス欄を埋める
memcpy(ehdr->ether_dhost, macaddr, ETHER_ADDR_LEN);
ethernet_send(ptr->flm);
ptr=ptr->next;
}
delete arptable[i].pending;
arptable[i].pending = NULL;
}
sig_sem(ARPTBL_SEM);
return;
}
}
if(arptable[next_register].pending!=NULL){
delete arptable[next_register].pending;
arptable[next_register].pending = NULL;
}
arptable[next_register].timeout=is_permanent?ARPTBL_PERMANENT:ARBTBL_TIMEOUT_CLC;
arptable[next_register].ipaddr = ipaddr;
memcpy(arptable[next_register].macaddr, macaddr, ETHER_ADDR_LEN);
next_register = (next_register+1) % MAX_ARPTABLE;
sig_sem(ARPTBL_SEM);
return;
}
void arp_process(ether_flame *flm, ether_arp *earp){
ether_hdr *ehdr = (ether_hdr*)flm->buf;
//正しいヘッダかチェック
if(flm->size < sizeof(ether_hdr)+sizeof(ether_arp) ||
ntoh16(earp->arp_hrd) != ARPHRD_ETHER ||
ntoh16(earp->arp_pro) != ETHERTYPE_IP ||
earp->arp_hln != ETHER_ADDR_LEN || earp->arp_pln != 4 ||
(ntoh16(earp->arp_op) != ARPOP_REQUEST && ntoh16(earp->arp_op) !=ARPOP_REPLY) ){
goto exit;
}
switch(ntoh16(earp->arp_op)){
case ARPOP_REQUEST:
if(memcmp(earp->arp_tpa, IPADDR,IP_ADDR_LEN)==0){
//相手のIPアドレスとMACアドレスを登録
register_arptable(IPADDR_TO_UINT32(earp->arp_spa), earp->arp_sha, false);
//パケットを改変
memcpy(earp->arp_tha, earp->arp_sha, ETHER_ADDR_LEN);
memcpy(earp->arp_tpa, earp->arp_spa, IP_ADDR_LEN);
memcpy(earp->arp_sha, MACADDR, ETHER_ADDR_LEN);
memcpy(earp->arp_spa, IPADDR, IP_ADDR_LEN);
earp->arp_op = hton16(ARPOP_REPLY);
memcpy(ehdr->ether_dhost, ehdr->ether_shost, ETHER_ADDR_LEN);
memcpy(ehdr->ether_shost, MACADDR, ETHER_ADDR_LEN);
//送り返す
ethernet_send(flm);
}
break;
case ARPOP_REPLY:
register_arptable(IPADDR_TO_UINT32(earp->arp_spa), earp->arp_sha, false);
break;
}
exit:
delete flm;
return;
}
ether_flame *make_arprequest_flame(uint8_t dstaddr[]){
ether_flame *flm = new ether_flame;
flm->size = sizeof(ether_hdr) + sizeof(ether_arp);
flm->buf = new char[flm->size];
ether_hdr *ehdr = (ether_hdr*)flm->buf;
ether_arp *earp = (ether_arp*)(ehdr+1);
ehdr->ether_type = hton16(ETHERTYPE_ARP);
memcpy(ehdr->ether_shost, MACADDR, ETHER_ADDR_LEN);
memset(ehdr->ether_dhost, 0xff, ETHER_ADDR_LEN); //ブロードキャスト
earp->arp_hrd = hton16(ARPHRD_ETHER);
earp->arp_pro = hton16(ETHERTYPE_IP);
earp->arp_hln = 6;
earp->arp_pln = 4;
earp->arp_op = hton16(ARPOP_REQUEST);
memcpy(earp->arp_sha, MACADDR, ETHER_ADDR_LEN);
memcpy(earp->arp_spa, IPADDR, IP_ADDR_LEN);
memset(earp->arp_tha, 0x00, ETHER_ADDR_LEN);
memcpy(earp->arp_tpa, dstaddr, IP_ADDR_LEN);
return flm;
}
void arp_send(hdrstack *packet, uint8_t dstaddr[], uint16_t proto){
//Ethernetヘッダはここで作っておく
hdrstack *ehdr_item = new hdrstack(true);
ehdr_item->next = packet;
ehdr_item->size = sizeof(ether_hdr);
ehdr_item->buf = new char[ehdr_item->size];
ether_hdr *ehdr = (ether_hdr*)ehdr_item->buf;
ehdr->ether_type = hton16(proto);
memcpy(ehdr->ether_shost, MACADDR, ETHER_ADDR_LEN);
switch(search_arptable(IPADDR_TO_UINT32(dstaddr), ehdr->ether_dhost, ehdr_item)){
case RESULT_FOUND:
//ARPテーブルに...ある時!
ethernet_send(ehdr_item);
delete ehdr_item;
break;
case RESULT_NOT_FOUND:
//無いとき... はsearch_arptableが保留リストに登録しておいてくれる
//ARPリクエストを送信する
{
ether_flame *request = make_arprequest_flame(dstaddr);
ethernet_send(request);
delete request;
break;
}
case RESULT_ADD_LIST:
//以前から保留状態にあった
break;
}
}