-
Notifications
You must be signed in to change notification settings - Fork 36
/
Copy pathbindings.c
179 lines (140 loc) · 4.19 KB
/
bindings.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
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <arpa/inet.h>
#include "queue.h"
#include "bindings.h"
/*
* Initialize the binding list.
*/
void
init_binding_list (binding_list *list)
{
LIST_INIT(list);
}
/*
* Create a new binding
*
* The binding is added to the binding list,
* and a pointer to the binding is returned for further manipulations.
*/
address_binding *
add_binding (binding_list *list, uint32_t address,
uint8_t *cident, uint8_t cident_len, int is_static)
{
// fill binding
address_binding *binding = calloc(1, sizeof(*binding));
binding->address = address;
binding->cident_len = cident_len;
memcpy(binding->cident, cident, cident_len);
binding->is_static = is_static;
// add to binding list
LIST_INSERT_HEAD(list, binding, pointers);
return binding;
}
/*
* Updated bindings status, i.e. set to EXPIRED the status of the
* expired bindings.
*/
void
update_bindings_statuses (binding_list *list)
{
address_binding *binding, *binding_temp;
LIST_FOREACH_SAFE(binding, list, pointers, binding_temp) {
if(binding->binding_time + binding->lease_time < time(NULL)) {
binding->status = EXPIRED;
}
}
}
/*
* Search a static or dynamic binding having the given client identifier.
*
* If the is_static option is true a static binding will be searched,
* otherwise a dynamic one. If status is not zero, an binding with that
* status will be searched.
*/
address_binding *
search_binding (binding_list *list, uint8_t *cident, uint8_t cident_len,
int is_static, int status)
{
address_binding *binding, *binding_temp;
LIST_FOREACH_SAFE(binding, list, pointers, binding_temp) {
if((binding->is_static == is_static || is_static == STATIC_OR_DYNAMIC) &&
binding->cident_len == cident_len &&
memcmp(binding->cident, cident, cident_len) == 0) {
if(status == 0)
return binding;
else if(status == binding->status)
return binding;
}
}
return NULL;
}
/*
* Get an available free address
*
* If a zero address is returned, no more address are available.
*/
static uint32_t
take_free_address (pool_indexes *indexes)
{
if(indexes->current <= indexes->last) {
uint32_t address = indexes->current;
indexes->current = htonl(ntohl(indexes->current) + 1);
return address;
} else
return 0;
}
/*
* Create a new dynamic binding or reuse an expired one.
*
* An attemp will be made to assign to the client the requested IP address
* contained in the address option. An address equals to zero means that no
* specific address has been requested.
*
* If the dynamic pool of addresses is full a NULL pointer will be returned.
*/
address_binding *
new_dynamic_binding (binding_list *list, pool_indexes *indexes, uint32_t address,
uint8_t *cident, uint8_t cident_len)
{
address_binding *binding, *binding_temp;
address_binding *found_binding = NULL;
if (address != 0) {
LIST_FOREACH_SAFE(binding, list, pointers, binding_temp) {
// search a previous binding using the requested IP address
if(binding->address == address) {
found_binding = binding;
break;
}
}
}
if(found_binding != NULL &&
!found_binding->is_static &&
found_binding->status != PENDING &&
found_binding->status != ASSOCIATED) {
// the requested IP address is available (reuse an expired association)
return found_binding;
} else {
/* the requested IP address is already in use, or no address has been
requested, or the address requested has never been allocated
(we do not support this last case and just return the next
available address!). */
uint32_t address = take_free_address(indexes);
if(address != 0)
return add_binding(list, address, cident, cident_len, 0);
else { // search any previously assigned address which is expired
LIST_FOREACH_SAFE(binding, list, pointers, binding_temp) {
if(!binding->is_static &&
found_binding->status != PENDING &&
found_binding->status != ASSOCIATED)
return binding;
}
// if executions reach here no more addresses are available
return NULL;
}
}
// execution should not reach here...
return NULL;
}