File: | src/usr.sbin/dvmrpd/neighbor.c |
Warning: | line 143, column 14 Use of memory after it is freed |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: neighbor.c,v 1.7 2009/04/16 20:11:12 michele Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org> | |||
5 | * Copyright (c) 2004, 2005, 2006 Esben Norby <norby@openbsd.org> | |||
6 | * | |||
7 | * Permission to use, copy, modify, and distribute this software for any | |||
8 | * purpose with or without fee is hereby granted, provided that the above | |||
9 | * copyright notice and this permission notice appear in all copies. | |||
10 | * | |||
11 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
12 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
13 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
14 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
15 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
16 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
17 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
18 | */ | |||
19 | ||||
20 | #include <sys/types.h> | |||
21 | #include <sys/ioctl.h> | |||
22 | #include <sys/time.h> | |||
23 | #include <sys/socket.h> | |||
24 | #include <netinet/in.h> | |||
25 | #include <arpa/inet.h> | |||
26 | #include <net/if.h> | |||
27 | ||||
28 | #include <ctype.h> | |||
29 | #include <err.h> | |||
30 | #include <stdio.h> | |||
31 | #include <stdlib.h> | |||
32 | #include <string.h> | |||
33 | #include <event.h> | |||
34 | ||||
35 | #include "igmp.h" | |||
36 | #include "dvmrpd.h" | |||
37 | #include "dvmrp.h" | |||
38 | #include "dvmrpe.h" | |||
39 | #include "log.h" | |||
40 | #include "rde.h" | |||
41 | ||||
42 | LIST_HEAD(nbr_head, nbr)struct nbr_head { struct nbr *lh_first; }; | |||
43 | ||||
44 | struct nbr_table { | |||
45 | struct nbr_head *hashtbl; | |||
46 | u_int32_t hashmask; | |||
47 | } nbrtable; | |||
48 | ||||
49 | #define NBR_HASH(x)&nbrtable.hashtbl[(x) & nbrtable.hashmask] \ | |||
50 | &nbrtable.hashtbl[(x) & nbrtable.hashmask] | |||
51 | ||||
52 | u_int32_t peercnt = NBR_CNTSTART(1 + 1); | |||
53 | ||||
54 | struct { | |||
55 | int state; | |||
56 | enum nbr_event event; | |||
57 | enum nbr_action action; | |||
58 | int new_state; | |||
59 | } nbr_fsm_tbl[] = { | |||
60 | /* current state event that happened action to take resulting state */ | |||
61 | {NBR_STA_DOWN0x01, NBR_EVT_PROBE_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_1_WAY0x02}, | |||
62 | {NBR_STA_ACTIVE(~0x01), NBR_EVT_PROBE_RCVD, NBR_ACT_RST_ITIMER, 0}, | |||
63 | {NBR_STA_1_WAY0x02, NBR_EVT_2_WAY_RCVD, NBR_ACT_STRT_ITIMER, NBR_STA_2_WAY0x04}, | |||
64 | {NBR_STA_ACTIVE(~0x01), NBR_EVT_1_WAY_RCVD, NBR_ACT_RESET, NBR_STA_1_WAY0x02}, | |||
65 | {NBR_STA_ANY0xff, NBR_EVT_KILL_NBR, NBR_ACT_DEL, NBR_STA_DOWN0x01}, | |||
66 | {NBR_STA_ANY0xff, NBR_EVT_ITIMER, NBR_ACT_DEL, NBR_STA_DOWN0x01}, | |||
67 | {-1, NBR_EVT_NOTHING, NBR_ACT_NOTHING, 0}, | |||
68 | }; | |||
69 | ||||
70 | const char * const nbr_event_names[] = { | |||
71 | "NOTHING", | |||
72 | "PROBE RCVD", | |||
73 | "1-WAY RCVD", | |||
74 | "2-WAY RCVD", | |||
75 | "KILL NBR", | |||
76 | "ITIMER", | |||
77 | "LL DOWN" | |||
78 | }; | |||
79 | ||||
80 | const char * const nbr_action_names[] = { | |||
81 | "NOTHING", | |||
82 | "RESET ITIMER", | |||
83 | "START ITIMER", | |||
84 | "RESET", | |||
85 | "DELETE", | |||
86 | "CLEAR LISTS" | |||
87 | }; | |||
88 | ||||
89 | int | |||
90 | nbr_fsm(struct nbr *nbr, enum nbr_event event) | |||
91 | { | |||
92 | struct timeval now; | |||
93 | int old_state; | |||
94 | int new_state = 0; | |||
95 | int i, ret = 0; | |||
96 | ||||
97 | old_state = nbr->state; | |||
98 | for (i = 0; nbr_fsm_tbl[i].state != -1; i++) | |||
99 | if ((nbr_fsm_tbl[i].state & old_state) && | |||
100 | (nbr_fsm_tbl[i].event == event)) { | |||
101 | new_state = nbr_fsm_tbl[i].new_state; | |||
102 | break; | |||
103 | } | |||
104 | ||||
105 | if (nbr_fsm_tbl[i].state == -1) { | |||
106 | /* XXX event outside of the defined fsm, ignore it. */ | |||
107 | log_warnx("nbr_fsm: neighbor ID %s, " | |||
108 | "event '%s' not expected in state '%s'", | |||
109 | inet_ntoa(nbr->id), nbr_event_name(event), | |||
110 | nbr_state_name(old_state)); | |||
111 | return (0); | |||
112 | } | |||
113 | ||||
114 | switch (nbr_fsm_tbl[i].action) { | |||
115 | case NBR_ACT_RST_ITIMER: | |||
116 | ret = nbr_act_reset_itimer(nbr); | |||
117 | break; | |||
118 | case NBR_ACT_STRT_ITIMER: | |||
119 | ret = nbr_act_start_itimer(nbr); | |||
120 | break; | |||
121 | case NBR_ACT_RESET: | |||
122 | /* XXX nbr action reset */ | |||
123 | break; | |||
124 | case NBR_ACT_DEL: | |||
125 | ret = nbr_act_delete(nbr); | |||
126 | break; | |||
127 | case NBR_ACT_CLR_LST: | |||
128 | ret = nbr_act_clear_lists(nbr); | |||
129 | break; | |||
130 | case NBR_ACT_NOTHING: | |||
131 | /* do nothing */ | |||
132 | break; | |||
133 | } | |||
134 | ||||
135 | if (ret
| |||
136 | log_warnx("nbr_fsm: error changing state for neighbor ID %s, " | |||
137 | "event '%s', state '%s'", inet_ntoa(nbr->id), | |||
138 | nbr_event_name(event), nbr_state_name(old_state)); | |||
139 | return (-1); | |||
140 | } | |||
141 | ||||
142 | if (new_state != 0) | |||
143 | nbr->state = new_state; | |||
| ||||
144 | ||||
145 | if (old_state != nbr->state) { | |||
146 | if (old_state & NBR_STA_2_WAY0x04 || nbr->state & NBR_STA_2_WAY0x04) { | |||
147 | /* neighbor changed from/to 2_WAY */ | |||
148 | ||||
149 | gettimeofday(&now, NULL((void *)0)); | |||
150 | nbr->uptime = now.tv_sec; | |||
151 | ||||
152 | if (nbr->state & NBR_STA_2_WAY0x04) | |||
153 | nbr->iface->adj_cnt++; | |||
154 | else | |||
155 | nbr->iface->adj_cnt--; | |||
156 | } | |||
157 | ||||
158 | log_debug("nbr_fsm: event '%s' resulted in action '%s' and " | |||
159 | "changing state for neighbor ID %s from '%s' to '%s'", | |||
160 | nbr_event_name(event), | |||
161 | nbr_action_name(nbr_fsm_tbl[i].action), | |||
162 | inet_ntoa(nbr->id), nbr_state_name(old_state), | |||
163 | nbr_state_name(nbr->state)); | |||
164 | } | |||
165 | ||||
166 | return (ret); | |||
167 | } | |||
168 | ||||
169 | void | |||
170 | nbr_init(u_int32_t hashsize) | |||
171 | { | |||
172 | u_int32_t hs, i; | |||
173 | ||||
174 | for (hs = 1; hs < hashsize; hs <<= 1) | |||
175 | ; | |||
176 | nbrtable.hashtbl = calloc(hs, sizeof(struct nbr_head)); | |||
177 | if (nbrtable.hashtbl == NULL((void *)0)) | |||
178 | fatal("nbr_init"); | |||
179 | ||||
180 | for (i = 0; i < hs; i++) | |||
181 | LIST_INIT(&nbrtable.hashtbl[i])do { ((&nbrtable.hashtbl[i])->lh_first) = ((void *)0); } while (0); | |||
182 | ||||
183 | nbrtable.hashmask = hs - 1; | |||
184 | } | |||
185 | ||||
186 | struct nbr * | |||
187 | nbr_new(u_int32_t nbr_id, struct iface *iface, int self) | |||
188 | { | |||
189 | struct nbr_head *head; | |||
190 | struct nbr *nbr = NULL((void *)0); | |||
191 | ||||
192 | if ((nbr = calloc(1, sizeof(*nbr))) == NULL((void *)0)) | |||
193 | fatal("nbr_new"); | |||
194 | ||||
195 | nbr->state = NBR_STA_DOWN0x01; | |||
196 | nbr->id.s_addr = nbr_id; | |||
197 | ||||
198 | /* get next unused peerid */ | |||
199 | while (nbr_find_peerid(++peercnt)) | |||
200 | ; | |||
201 | nbr->peerid = peercnt; | |||
202 | head = NBR_HASH(nbr->peerid)&nbrtable.hashtbl[(nbr->peerid) & nbrtable.hashmask ]; | |||
203 | LIST_INSERT_HEAD(head, nbr, hash)do { if (((nbr)->hash.le_next = (head)->lh_first) != (( void *)0)) (head)->lh_first->hash.le_prev = &(nbr)-> hash.le_next; (head)->lh_first = (nbr); (nbr)->hash.le_prev = &(head)->lh_first; } while (0); | |||
204 | ||||
205 | /* add to peer list */ | |||
206 | nbr->iface = iface; | |||
207 | LIST_INSERT_HEAD(&iface->nbr_list, nbr, entry)do { if (((nbr)->entry.le_next = (&iface->nbr_list) ->lh_first) != ((void *)0)) (&iface->nbr_list)-> lh_first->entry.le_prev = &(nbr)->entry.le_next; (& iface->nbr_list)->lh_first = (nbr); (nbr)->entry.le_prev = &(&iface->nbr_list)->lh_first; } while (0); | |||
208 | ||||
209 | TAILQ_INIT(&nbr->rr_list)do { (&nbr->rr_list)->tqh_first = ((void *)0); (& nbr->rr_list)->tqh_last = &(&nbr->rr_list)-> tqh_first; } while (0); | |||
210 | ||||
211 | /* set event structures */ | |||
212 | evtimer_set(&nbr->inactivity_timer, nbr_itimer, nbr)event_set(&nbr->inactivity_timer, -1, 0, nbr_itimer, nbr ); | |||
213 | ||||
214 | log_debug("nbr_new: neighbor ID %s, peerid %lu", | |||
215 | inet_ntoa(nbr->id), nbr->peerid); | |||
216 | ||||
217 | return (nbr); | |||
218 | } | |||
219 | ||||
220 | int | |||
221 | nbr_del(struct nbr *nbr) | |||
222 | { | |||
223 | /* clear lists */ | |||
224 | rr_list_clr(&nbr->rr_list); | |||
225 | ||||
226 | LIST_REMOVE(nbr, entry)do { if ((nbr)->entry.le_next != ((void *)0)) (nbr)->entry .le_next->entry.le_prev = (nbr)->entry.le_prev; *(nbr)-> entry.le_prev = (nbr)->entry.le_next; ; ; } while (0); | |||
227 | LIST_REMOVE(nbr, hash)do { if ((nbr)->hash.le_next != ((void *)0)) (nbr)->hash .le_next->hash.le_prev = (nbr)->hash.le_prev; *(nbr)-> hash.le_prev = (nbr)->hash.le_next; ; ; } while (0); | |||
228 | ||||
229 | free(nbr); | |||
230 | ||||
231 | return (0); | |||
232 | } | |||
233 | ||||
234 | struct nbr * | |||
235 | nbr_find_peerid(u_int32_t peerid) | |||
236 | { | |||
237 | struct nbr_head *head; | |||
238 | struct nbr *nbr; | |||
239 | ||||
240 | head = NBR_HASH(peerid)&nbrtable.hashtbl[(peerid) & nbrtable.hashmask]; | |||
241 | ||||
242 | LIST_FOREACH(nbr, head, hash)for((nbr) = ((head)->lh_first); (nbr)!= ((void *)0); (nbr) = ((nbr)->hash.le_next)) { | |||
243 | if (nbr->peerid == peerid) | |||
244 | return (nbr); | |||
245 | } | |||
246 | ||||
247 | return (NULL((void *)0)); | |||
248 | } | |||
249 | ||||
250 | struct nbr * | |||
251 | nbr_find_ip(struct iface *iface, u_int32_t src_ip) | |||
252 | { | |||
253 | struct nbr *nbr = NULL((void *)0); | |||
254 | ||||
255 | LIST_FOREACH(nbr, &iface->nbr_list, entry)for((nbr) = ((&iface->nbr_list)->lh_first); (nbr)!= ((void *)0); (nbr) = ((nbr)->entry.le_next)) { | |||
256 | if (nbr->id.s_addr == src_ip) { | |||
257 | return (nbr); | |||
258 | } | |||
259 | } | |||
260 | ||||
261 | return (NULL((void *)0)); | |||
262 | } | |||
263 | ||||
264 | /* timers */ | |||
265 | void | |||
266 | nbr_itimer(int fd, short event, void *arg) | |||
267 | { | |||
268 | struct nbr *nbr = arg; | |||
269 | ||||
270 | log_debug("nbr_itimer: %s", inet_ntoa(nbr->id)); | |||
271 | ||||
272 | nbr_fsm(nbr, NBR_EVT_ITIMER); | |||
| ||||
273 | } | |||
274 | ||||
275 | int | |||
276 | nbr_start_itimer(struct nbr *nbr) | |||
277 | { | |||
278 | struct timeval tv; | |||
279 | ||||
280 | log_debug("nbr_start_itimer: %s", inet_ntoa(nbr->id)); | |||
281 | ||||
282 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
283 | tv.tv_sec = nbr->iface->dead_interval; | |||
284 | ||||
285 | return (evtimer_add(&nbr->inactivity_timer, &tv)event_add(&nbr->inactivity_timer, &tv)); | |||
286 | } | |||
287 | ||||
288 | int | |||
289 | nbr_stop_itimer(struct nbr *nbr) | |||
290 | { | |||
291 | return (evtimer_del(&nbr->inactivity_timer)event_del(&nbr->inactivity_timer)); | |||
292 | } | |||
293 | ||||
294 | int | |||
295 | nbr_reset_itimer(struct nbr *nbr) | |||
296 | { | |||
297 | struct timeval tv; | |||
298 | ||||
299 | timerclear(&tv)(&tv)->tv_sec = (&tv)->tv_usec = 0; | |||
300 | tv.tv_sec = nbr->iface->dead_interval; | |||
301 | ||||
302 | return (evtimer_add(&nbr->inactivity_timer, &tv)event_add(&nbr->inactivity_timer, &tv)); | |||
303 | } | |||
304 | ||||
305 | /* actions */ | |||
306 | int | |||
307 | nbr_act_start(struct nbr *nbr) | |||
308 | { | |||
309 | log_debug("nbr_act_start: neighbor ID %s", inet_ntoa(nbr->id)); | |||
310 | ||||
311 | return (-1); | |||
312 | } | |||
313 | ||||
314 | int | |||
315 | nbr_act_reset_itimer(struct nbr *nbr) | |||
316 | { | |||
317 | if (nbr_reset_itimer(nbr)) { | |||
318 | log_warnx("nbr_act_reset_itimer: cannot schedule inactivity " | |||
319 | "timer, neighbor ID %s", inet_ntoa(nbr->id)); | |||
320 | return (-1); | |||
321 | } | |||
322 | ||||
323 | return (0); | |||
324 | } | |||
325 | ||||
326 | int | |||
327 | nbr_act_start_itimer(struct nbr *nbr) | |||
328 | { | |||
329 | if (nbr_start_itimer(nbr)) { | |||
330 | log_warnx("nbr_act_start_itimer: cannot schedule inactivity " | |||
331 | "timer, neighbor ID %s", | |||
332 | inet_ntoa(nbr->id)); | |||
333 | return (-1); | |||
334 | } | |||
335 | ||||
336 | if (nbr->state == NBR_STA_1_WAY0x02) { | |||
337 | /* new nbr, send entire route table, unicast */ | |||
338 | log_debug("nbr_act_start_itimer: nbr %s, send route table", | |||
339 | inet_ntoa(nbr->id)); | |||
340 | ||||
341 | dvmrpe_imsg_compose_rde(IMSG_FULL_ROUTE_REPORT, nbr->peerid, 0, | |||
342 | NULL((void *)0), 0); | |||
343 | } | |||
344 | ||||
345 | return (0); | |||
346 | } | |||
347 | ||||
348 | int | |||
349 | nbr_act_delete(struct nbr *nbr) | |||
350 | { | |||
351 | struct nbr_msg nm; | |||
352 | ||||
353 | log_debug("nbr_act_delete: neighbor ID %s", inet_ntoa(nbr->id)); | |||
354 | ||||
355 | /* stop timers */ | |||
356 | if (nbr_stop_itimer(nbr)) { | |||
357 | log_warnx("nbr_act_delete: error removing inactivity timer, " | |||
358 | "neighbor ID %s", inet_ntoa(nbr->id)); | |||
359 | return (-1); | |||
360 | } | |||
361 | ||||
362 | nm.address.s_addr = nbr->addr.s_addr; | |||
363 | nm.ifindex = nbr->iface->ifindex; | |||
364 | ||||
365 | dvmrpe_imsg_compose_rde(IMSG_NBR_DEL, 0, 0, &nm, sizeof(nm)); | |||
366 | ||||
367 | return (nbr_del(nbr)); | |||
368 | } | |||
369 | ||||
370 | int | |||
371 | nbr_act_clear_lists(struct nbr *nbr) | |||
372 | { | |||
373 | log_debug("nbr_act_clear_lists: neighbor ID %s", inet_ntoa(nbr->id)); | |||
374 | rr_list_clr(&nbr->rr_list); | |||
375 | ||||
376 | return (0); | |||
377 | } | |||
378 | ||||
379 | /* names */ | |||
380 | const char * | |||
381 | nbr_event_name(int event) | |||
382 | { | |||
383 | return (nbr_event_names[event]); | |||
384 | } | |||
385 | ||||
386 | const char * | |||
387 | nbr_action_name(int action) | |||
388 | { | |||
389 | return (nbr_action_names[action]); | |||
390 | } | |||
391 | ||||
392 | struct ctl_nbr * | |||
393 | nbr_to_ctl(struct nbr *nbr) | |||
394 | { | |||
395 | static struct ctl_nbr nctl; | |||
396 | struct timeval tv, now, res; | |||
397 | ||||
398 | memcpy(nctl.name, nbr->iface->name, sizeof(nctl.name)); | |||
399 | memcpy(&nctl.id, &nbr->id, sizeof(nctl.id)); | |||
400 | memcpy(&nctl.addr, &nbr->addr, sizeof(nctl.addr)); | |||
401 | ||||
402 | nctl.state = nbr->state; | |||
403 | ||||
404 | gettimeofday(&now, NULL((void *)0)); | |||
405 | if (evtimer_pending(&nbr->inactivity_timer, &tv)event_pending(&nbr->inactivity_timer, 0x01, &tv)) { | |||
406 | timersub(&tv, &now, &res)do { (&res)->tv_sec = (&tv)->tv_sec - (&now )->tv_sec; (&res)->tv_usec = (&tv)->tv_usec - (&now)->tv_usec; if ((&res)->tv_usec < 0) { (&res)->tv_sec--; (&res)->tv_usec += 1000000; } } while (0); | |||
407 | nctl.dead_timer = res.tv_sec; | |||
408 | } else | |||
409 | nctl.dead_timer = 0; | |||
410 | ||||
411 | if (nbr->state == NBR_STA_2_WAY0x04) { | |||
412 | nctl.uptime = now.tv_sec - nbr->uptime; | |||
413 | } else | |||
414 | nctl.uptime = 0; | |||
415 | ||||
416 | return (&nctl); | |||
417 | } |