-
Notifications
You must be signed in to change notification settings - Fork 2
/
neigh.c
363 lines (287 loc) · 8.02 KB
/
neigh.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
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
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- */
/* Copyright (C) Uppsala University
*
* This file is distributed under the terms of the GNU general Public
* License (GPL), see the file LICENSE
*
* Author: Erik Nordström, <[email protected]>
*/
#ifdef __KERNEL__
#include <linux/proc_fs.h>
#endif
#ifdef NS2
#include "ns-agent.h"
#endif /* NS2 */
#include "tbl.h"
#include "neigh.h"
#include "debug.h"
#include "timer.h"
#define NEIGH_TBL_MAX_LEN 50
/* We calculate RTO in milliseconds */
#define DSR_SRTTBASE 0
#define DSR_SRTTDFLT 60
#define DSR_MIN 20
#define DSR_REXMTMAX 1280
#define DSR_RTTDFLT 30
#define PR_SLOWHZ 2
#define RTT_SHIFT 3
#define RTTVAR_SHIFT 2
#define NEIGH_TBL_GARBAGE_COLLECT_TIMEOUT 3000
#define NEIGH_TBL_TIMEOUT 2000
#define DSR_RANGESET(tv, value, tvmin, tvmax) { \
(tv) = (value); \
if ((tv) < (tvmin)) \
(tv) = (tvmin); \
else if ((tv) > (tvmax)) \
(tv) = (tvmax); \
}
#define VALMAX(a,b) ( a > b ? a : b)
#define K 4
#define DSR_REXMTVAL(val) \
(((val) >> RTT_SHIFT) + (val))
#ifdef __KERNEL__
static TBL(neigh_tbl, NEIGH_TBL_MAX_LEN);
#define NEIGH_TBL_PROC_NAME "dsr_neigh_tbl"
static DSRUUTimer neigh_tbl_timer;
#endif
struct neighbor {
list_t l;
struct in_addr addr;
struct sockaddr hw_addr;
unsigned short id;
struct timeval last_ack_req;
usecs_t t_srtt, rto, t_rxtcur, t_rttmin, t_rttvar, jitter; /* RTT in usec */
};
struct neighbor_query {
struct in_addr *addr;
struct neighbor_info *info;
};
static inline int crit_addr(void *pos, void *query)
{
struct neighbor_query *q = (struct neighbor_query *)query;
struct neighbor *n = (struct neighbor *)pos;
usecs_t rto;
if (n->addr.s_addr == q->addr->s_addr) {
if (q->info) {
q->info->id = n->id;
q->info->last_ack_req = n->last_ack_req;
memcpy(&q->info->hw_addr, &n->hw_addr,
sizeof(struct sockaddr));
rto = ConfValToUsecs(RoundTripTimeout);
/* Return current RTO */
if (rto == 0) {
q->info->rto = n->t_rxtcur * 1000 / PR_SLOWHZ;
} else {
/* Fixed RTO (defaults to 2 secs) */
q->info->rto = rto;
}
}
return 1;
}
return 0;
}
static inline int crit_addr_id_inc(void *pos, void *addr)
{
struct in_addr *a = (struct in_addr *)addr;
struct neighbor *n = (struct neighbor *)pos;
if (n->addr.s_addr == a->s_addr) {
n->id++;
//gettime(&n->last_ack_req);
return 1;
}
return 0;
}
static inline int set_ack_req_time(void *pos, void *addr)
{
struct in_addr *a = (struct in_addr *)addr;
struct neighbor *n = (struct neighbor *)pos;
if (n->addr.s_addr == a->s_addr) {
gettime(&n->last_ack_req);
return 1;
}
return 0;
}
static inline int rto_calc(void *pos, void *query)
{
struct neighbor_query *q = (struct neighbor_query *)query;
struct neighbor *n = (struct neighbor *)pos;
if (n->addr.s_addr == q->addr->s_addr) {
struct timeval now;
usecs_t rtt = q->info->rtt;
int delta;
gettime(&now);
/* Should verify for sure that this does the right
* thing... */
if (n->t_srtt != 0) {
delta = rtt - 1 - (n->t_srtt >> RTT_SHIFT);
if ((n->t_srtt += delta) <= 0)
n->t_srtt = 1;
if (delta < 0)
delta = -delta;
delta -= (n->t_rttvar >> RTTVAR_SHIFT);
if ((n->t_rttvar += delta) <= 0)
n->t_rttvar = 1;
} else {
n->t_srtt = rtt << RTT_SHIFT;
n->t_rttvar = rtt << (RTTVAR_SHIFT - 1);
}
DSR_RANGESET(n->t_rxtcur, DSR_REXMTVAL(n->t_srtt),
n->t_rttmin, DSR_REXMTMAX);
return 1;
}
return 0;
}
/* TODO: Implement neighbor table garbage collection */
void NSCLASS neigh_tbl_garbage_timeout(unsigned long data)
{
/* tbl_for_each_del(&neigh_tbl, NULL, crit_garbage); */
/* if (!tbl_empty(&neigh_tbl)) { */
/* garbage_timer.expires = TimeNow + */
/* MSECS_TO_TIMENOW(NEIGH_TBL_GARBAGE_COLLECT_TIMEOUT); */
/* add_timer(&garbage_timer); */
/* } */
}
static struct neighbor *neigh_tbl_create(struct in_addr addr,
struct sockaddr *hw_addr,
unsigned short id)
{
struct neighbor *neigh;
neigh = (struct neighbor *)kmalloc(sizeof(struct neighbor), GFP_ATOMIC);
if (!neigh)
return NULL;
memset(neigh, 0, sizeof(struct neighbor));
neigh->id = id;
neigh->addr = addr;
neigh->t_srtt = DSR_SRTTBASE;
neigh->t_rttvar = DSR_RTTDFLT * PR_SLOWHZ << 2;
neigh->t_rttmin = DSR_MIN;
DSR_RANGESET(neigh->t_rxtcur,
((DSR_SRTTBASE >> 2) + (DSR_SRTTDFLT << 2)) >> 1,
DSR_MIN, DSR_REXMTMAX);
memset(&neigh->last_ack_req, 0, sizeof(struct timeval));
memcpy(&neigh->hw_addr, hw_addr, sizeof(struct sockaddr));
/* garbage_timer.expires = TimeNow + NEIGH_TBL_GARBAGE_COLLECT_TIMEOUT / 1000*HZ; */
/* add_timer(&garbage_timer); */
return neigh;
}
#ifdef NS2
int NSCLASS neigh_tbl_add(struct in_addr neigh_addr, struct hdr_mac *mach)
#else
int NSCLASS neigh_tbl_add(struct in_addr neigh_addr, struct ethhdr *ethh)
#endif
{
struct sockaddr hw_addr;
struct neighbor *neigh;
struct neighbor_query q;
q.addr = &neigh_addr;
q.info = NULL;
if (in_tbl(&neigh_tbl, &q, crit_addr))
return 0;
#ifdef NS2
/* This should probably be changed to lookup the MAC type
* dynamically in case the simulation is run over a non 802.11
* mac layer... Or is there a uniform way to get hold of the mac
* source for all mac headers? */
struct hdr_mac802_11 *mh_802_11 = (struct hdr_mac802_11 *)mach;
int mac_src = ETHER_ADDR(mh_802_11->dh_ta);
inttoeth(&mac_src, (char *)&hw_addr);
LOG_DBG("ADD %s, %d\n", print_ip(neigh_addr), mac_src);
#else
memcpy(hw_addr.sa_data, ethh->h_source, ETH_ALEN);
#endif
neigh = neigh_tbl_create(neigh_addr, &hw_addr, 1);
if (!neigh) {
LOG_DBG("Could not create new neighbor entry\n");
return -1;
}
tbl_add(&neigh_tbl, &neigh->l, crit_none);
return 1;
}
int NSCLASS neigh_tbl_del(struct in_addr neigh_addr)
{
return tbl_for_each_del(&neigh_tbl, &neigh_addr, crit_addr);
}
int NSCLASS neigh_tbl_set_ack_req_time(struct in_addr neigh_addr)
{
return tbl_find_do(&neigh_tbl, &neigh_addr, set_ack_req_time);
}
int NSCLASS
neigh_tbl_set_rto(struct in_addr neigh_addr, struct neighbor_info *neigh_info)
{
struct neighbor_query q;
q.addr = &neigh_addr;
q.info = neigh_info;
return tbl_find_do(&neigh_tbl, &q, rto_calc);
}
int NSCLASS
neigh_tbl_query(struct in_addr neigh_addr, struct neighbor_info *neigh_info)
{
struct neighbor_query q;
q.addr = &neigh_addr;
q.info = neigh_info;
return in_tbl(&neigh_tbl, &q, crit_addr);
}
int NSCLASS neigh_tbl_id_inc(struct in_addr neigh_addr)
{
return tbl_find_do(&neigh_tbl, &neigh_addr, crit_addr_id_inc);
}
#ifdef __KERNEL__
static int neigh_tbl_print(char *buf)
{
list_t *pos;
int len = 0;
read_lock_bh(&neigh_tbl.lock);
len +=
sprintf(buf, "# %-15s %-17s %-10s %-6s\n", "Addr", "HwAddr",
"RTO (usec)", "Id" /*, "AckRxTime","AckTxTime" */ );
list_for_each(pos, &neigh_tbl.head) {
struct neighbor *neigh = (struct neighbor *)pos;
len += sprintf(buf + len, " %-15s %-17s %-10lu %-6u\n",
print_ip(neigh->addr),
print_eth(neigh->hw_addr.sa_data),
neigh->t_rxtcur, neigh->id);
}
read_unlock_bh(&neigh_tbl.lock);
return len;
}
static int
neigh_tbl_proc_info(char *buffer, char **start, off_t offset, int length, int *eof, void *data)
{
int len;
len = neigh_tbl_print(buffer);
*start = buffer + offset;
len -= offset;
if (len > length)
len = length;
else if (len < 0)
len = 0;
return len;
}
#endif /* __KERNEL__ */
int __init NSCLASS neigh_tbl_init(void)
{
#ifdef __KERNEL__
struct proc_dir_entry *proc;
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,23))
#define proc_net init_net.proc_net
#endif
proc = create_proc_read_entry(NEIGH_TBL_PROC_NAME, 0, proc_net, neigh_tbl_proc_info, NULL);
if (!proc)
return -1;
#endif
INIT_TBL(&neigh_tbl, NEIGH_TBL_MAX_LEN);
init_timer(&neigh_tbl_timer);
neigh_tbl_timer.function = &NSCLASS neigh_tbl_garbage_timeout;
return 0;
}
void __exit NSCLASS neigh_tbl_cleanup(void)
{
tbl_flush(&neigh_tbl, crit_none);
#ifdef __KERNEL__
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24))
proc_net_remove(NEIGH_TBL_PROC_NAME);
#else
proc_net_remove(&init_net, NEIGH_TBL_PROC_NAME);
#endif
#endif
}