]>
Commit | Line | Data |
---|---|---|
12e41d03 DL |
1 | /* |
2 | PIM for Quagga | |
3 | Copyright (C) 2008 Everton da Silva Marques | |
4 | ||
5 | This program is free software; you can redistribute it and/or modify | |
6 | it under the terms of the GNU General Public License as published by | |
7 | the Free Software Foundation; either version 2 of the License, or | |
8 | (at your option) any later version. | |
9 | ||
10 | This program is distributed in the hope that it will be useful, but | |
11 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 | General Public License for more details. | |
14 | ||
15 | You should have received a copy of the GNU General Public License | |
16 | along with this program; see the file COPYING; if not, write to the | |
17 | Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, | |
18 | MA 02110-1301 USA | |
19 | ||
20 | $QuaggaId: $Format:%an, %ai, %h$ $ | |
21 | */ | |
22 | ||
23 | #include <zebra.h> | |
24 | ||
25 | #include "log.h" | |
26 | #include "prefix.h" | |
744d91b3 | 27 | #include "if.h" |
12e41d03 DL |
28 | |
29 | #include "pimd.h" | |
30 | #include "pim_int.h" | |
31 | #include "pim_tlv.h" | |
32 | #include "pim_str.h" | |
33 | #include "pim_msg.h" | |
34 | ||
35 | uint8_t *pim_tlv_append_uint16(uint8_t *buf, | |
36 | const uint8_t *buf_pastend, | |
37 | uint16_t option_type, | |
38 | uint16_t option_value) | |
39 | { | |
40 | uint16_t option_len = 2; | |
41 | ||
aea6cb94 DS |
42 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
43 | return NULL; | |
12e41d03 DL |
44 | |
45 | *(uint16_t *) buf = htons(option_type); | |
46 | buf += 2; | |
47 | *(uint16_t *) buf = htons(option_len); | |
48 | buf += 2; | |
49 | *(uint16_t *) buf = htons(option_value); | |
50 | buf += option_len; | |
51 | ||
52 | return buf; | |
53 | } | |
54 | ||
55 | uint8_t *pim_tlv_append_2uint16(uint8_t *buf, | |
56 | const uint8_t *buf_pastend, | |
57 | uint16_t option_type, | |
58 | uint16_t option_value1, | |
59 | uint16_t option_value2) | |
60 | { | |
61 | uint16_t option_len = 4; | |
62 | ||
aea6cb94 DS |
63 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
64 | return NULL; | |
12e41d03 DL |
65 | |
66 | *(uint16_t *) buf = htons(option_type); | |
67 | buf += 2; | |
68 | *(uint16_t *) buf = htons(option_len); | |
69 | buf += 2; | |
70 | *(uint16_t *) buf = htons(option_value1); | |
71 | buf += 2; | |
72 | *(uint16_t *) buf = htons(option_value2); | |
73 | buf += 2; | |
74 | ||
75 | return buf; | |
76 | } | |
77 | ||
78 | uint8_t *pim_tlv_append_uint32(uint8_t *buf, | |
79 | const uint8_t *buf_pastend, | |
80 | uint16_t option_type, | |
81 | uint32_t option_value) | |
82 | { | |
83 | uint16_t option_len = 4; | |
84 | ||
aea6cb94 DS |
85 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
86 | return NULL; | |
12e41d03 DL |
87 | |
88 | *(uint16_t *) buf = htons(option_type); | |
89 | buf += 2; | |
90 | *(uint16_t *) buf = htons(option_len); | |
91 | buf += 2; | |
92 | pim_write_uint32(buf, option_value); | |
93 | buf += option_len; | |
94 | ||
95 | return buf; | |
96 | } | |
97 | ||
98 | #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) | |
99 | ||
4416b1f6 DS |
100 | static int |
101 | pim_encode_unicast_address (uint8_t *buf, struct prefix *p) | |
102 | { | |
103 | switch (p->family) | |
104 | { | |
105 | case AF_INET: | |
106 | *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
107 | ++buf; | |
108 | *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ | |
109 | ++buf; | |
110 | memcpy (buf, &p->u.prefix4, sizeof (struct in_addr)); | |
111 | return ucast_ipv4_encoding_len; | |
112 | break; | |
113 | default: | |
114 | return 0; | |
115 | break; | |
116 | } | |
117 | } | |
118 | ||
12e41d03 DL |
119 | uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, |
120 | const uint8_t *buf_pastend, | |
121 | struct list *ifconnected) | |
122 | { | |
123 | struct listnode *node; | |
124 | uint16_t option_len = 0; | |
125 | ||
126 | uint8_t *curr; | |
127 | ||
128 | node = listhead(ifconnected); | |
129 | ||
130 | /* Empty address list ? */ | |
131 | if (!node) { | |
132 | return buf; | |
133 | } | |
134 | ||
135 | /* Skip first address (primary) */ | |
136 | node = listnextnode(node); | |
137 | ||
138 | /* Scan secondary address list */ | |
139 | curr = buf + 4; /* skip T and L */ | |
140 | for (; node; node = listnextnode(node)) { | |
141 | struct connected *ifc = listgetdata(node); | |
142 | struct prefix *p = ifc->address; | |
4416b1f6 | 143 | int l_encode; |
12e41d03 | 144 | |
aea6cb94 | 145 | if ((curr + ucast_ipv4_encoding_len) > buf_pastend) |
12e41d03 | 146 | return 0; |
12e41d03 | 147 | |
4416b1f6 DS |
148 | l_encode = pim_encode_unicast_address (curr, p); |
149 | curr += l_encode; | |
150 | option_len += l_encode; | |
12e41d03 DL |
151 | } |
152 | ||
169edb7f | 153 | if (PIM_DEBUG_PIM_TRACE_DETAIL) { |
aea6cb94 DS |
154 | zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", |
155 | __PRETTY_FUNCTION__, | |
156 | option_len / ucast_ipv4_encoding_len); | |
12e41d03 DL |
157 | } |
158 | ||
159 | if (option_len < 1) { | |
160 | /* Empty secondary unicast IPv4 address list */ | |
161 | return buf; | |
162 | } | |
163 | ||
164 | /* | |
165 | * Write T and L | |
166 | */ | |
167 | *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); | |
168 | *(uint16_t *) (buf + 2) = htons(option_len); | |
169 | ||
170 | return curr; | |
171 | } | |
172 | ||
173 | static int check_tlv_length(const char *label, const char *tlv_name, | |
174 | const char *ifname, struct in_addr src_addr, | |
175 | int correct_len, int option_len) | |
176 | { | |
177 | if (option_len != correct_len) { | |
178 | char src_str[100]; | |
179 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
180 | zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", | |
181 | label, tlv_name, | |
182 | option_len, correct_len, | |
183 | src_str, ifname); | |
184 | return -1; | |
185 | } | |
186 | ||
187 | return 0; | |
188 | } | |
189 | ||
190 | static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, | |
191 | const char *ifname, struct in_addr src_addr, | |
192 | pim_hello_options options, | |
193 | pim_hello_options opt_mask, | |
194 | uint16_t new, uint16_t old) | |
195 | { | |
196 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
197 | char src_str[100]; | |
198 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
199 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
200 | label, tlv_name, | |
201 | new, old, | |
202 | src_str, ifname); | |
203 | } | |
204 | } | |
205 | ||
206 | static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, | |
207 | const char *ifname, struct in_addr src_addr, | |
208 | pim_hello_options options, | |
209 | pim_hello_options opt_mask, | |
210 | uint32_t new, uint32_t old) | |
211 | { | |
212 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
213 | char src_str[100]; | |
214 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
215 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
216 | label, tlv_name, | |
217 | new, old, | |
218 | src_str, ifname); | |
219 | } | |
220 | } | |
221 | ||
222 | static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, | |
223 | const char *ifname, struct in_addr src_addr, | |
224 | pim_hello_options options, | |
225 | pim_hello_options opt_mask, | |
226 | uint32_t new, uint32_t old) | |
227 | { | |
228 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
229 | char src_str[100]; | |
230 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
231 | zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", | |
232 | label, tlv_name, | |
233 | new, old, | |
234 | src_str, ifname); | |
235 | } | |
236 | } | |
237 | ||
238 | int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, | |
239 | pim_hello_options *hello_options, | |
240 | uint16_t *hello_option_holdtime, | |
241 | uint16_t option_len, | |
242 | const uint8_t *tlv_curr) | |
243 | { | |
244 | const char *label = "holdtime"; | |
245 | ||
246 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
247 | ifname, src_addr, | |
248 | sizeof(uint16_t), option_len)) { | |
249 | return -1; | |
250 | } | |
251 | ||
252 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, | |
253 | ifname, src_addr, | |
254 | *hello_options, PIM_OPTION_MASK_HOLDTIME, | |
255 | PIM_TLV_GET_HOLDTIME(tlv_curr), | |
256 | *hello_option_holdtime); | |
257 | ||
258 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); | |
259 | ||
260 | *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); | |
261 | ||
262 | return 0; | |
263 | } | |
264 | ||
265 | int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, | |
266 | pim_hello_options *hello_options, | |
267 | uint16_t *hello_option_propagation_delay, | |
268 | uint16_t *hello_option_override_interval, | |
269 | uint16_t option_len, | |
270 | const uint8_t *tlv_curr) | |
271 | { | |
272 | if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", | |
273 | ifname, src_addr, | |
274 | sizeof(uint32_t), option_len)) { | |
275 | return -1; | |
276 | } | |
277 | ||
278 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", | |
279 | ifname, src_addr, | |
280 | *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, | |
281 | PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), | |
282 | *hello_option_propagation_delay); | |
283 | ||
284 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); | |
285 | ||
286 | *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); | |
287 | if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { | |
288 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
289 | } | |
290 | else { | |
291 | PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
292 | } | |
293 | ++tlv_curr; | |
294 | ++tlv_curr; | |
295 | *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); | |
296 | ||
297 | return 0; | |
298 | } | |
299 | ||
300 | int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, | |
301 | pim_hello_options *hello_options, | |
302 | uint32_t *hello_option_dr_priority, | |
303 | uint16_t option_len, | |
304 | const uint8_t *tlv_curr) | |
305 | { | |
306 | const char *label = "dr_priority"; | |
307 | ||
308 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
309 | ifname, src_addr, | |
310 | sizeof(uint32_t), option_len)) { | |
311 | return -1; | |
312 | } | |
313 | ||
314 | check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, | |
315 | ifname, src_addr, | |
316 | *hello_options, PIM_OPTION_MASK_DR_PRIORITY, | |
317 | PIM_TLV_GET_DR_PRIORITY(tlv_curr), | |
318 | *hello_option_dr_priority); | |
319 | ||
320 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); | |
321 | ||
322 | *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); | |
323 | ||
324 | return 0; | |
325 | } | |
326 | ||
327 | int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, | |
328 | pim_hello_options *hello_options, | |
329 | uint32_t *hello_option_generation_id, | |
330 | uint16_t option_len, | |
331 | const uint8_t *tlv_curr) | |
332 | { | |
333 | const char *label = "generation_id"; | |
334 | ||
335 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
336 | ifname, src_addr, | |
337 | sizeof(uint32_t), option_len)) { | |
338 | return -1; | |
339 | } | |
340 | ||
341 | check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, | |
342 | ifname, src_addr, | |
343 | *hello_options, PIM_OPTION_MASK_GENERATION_ID, | |
344 | PIM_TLV_GET_GENERATION_ID(tlv_curr), | |
345 | *hello_option_generation_id); | |
346 | ||
347 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); | |
348 | ||
349 | *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); | |
350 | ||
351 | return 0; | |
352 | } | |
353 | ||
4416b1f6 DS |
354 | int |
355 | pim_parse_addr_ucast (struct prefix *p, | |
356 | const uint8_t *buf, | |
357 | int buf_size) | |
12e41d03 DL |
358 | { |
359 | const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ | |
360 | const uint8_t *addr; | |
361 | const uint8_t *pastend; | |
362 | int family; | |
363 | int type; | |
364 | ||
365 | if (buf_size < ucast_encoding_min_len) { | |
4416b1f6 | 366 | zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d", |
12e41d03 | 367 | __PRETTY_FUNCTION__, |
4416b1f6 | 368 | buf_size, ucast_encoding_min_len); |
12e41d03 DL |
369 | return -1; |
370 | } | |
371 | ||
372 | addr = buf; | |
373 | pastend = buf + buf_size; | |
374 | ||
375 | family = *addr++; | |
376 | type = *addr++; | |
377 | ||
4416b1f6 DS |
378 | if (type) { |
379 | zlog_warn("%s: unknown unicast address encoding type=%d", | |
380 | __PRETTY_FUNCTION__, | |
381 | type); | |
382 | return -2; | |
383 | } | |
384 | ||
12e41d03 DL |
385 | switch (family) { |
386 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
12e41d03 | 387 | if ((addr + sizeof(struct in_addr)) > pastend) { |
4416b1f6 | 388 | zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu", |
12e41d03 | 389 | __PRETTY_FUNCTION__, |
4416b1f6 | 390 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
391 | return -3; |
392 | } | |
393 | ||
394 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
395 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
396 | ||
397 | addr += sizeof(struct in_addr); | |
398 | ||
399 | break; | |
400 | default: | |
401 | { | |
4416b1f6 | 402 | zlog_warn("%s: unknown unicast address encoding family=%d from", |
12e41d03 | 403 | __PRETTY_FUNCTION__, |
4416b1f6 | 404 | family); |
12e41d03 DL |
405 | return -4; |
406 | } | |
407 | } | |
408 | ||
409 | return addr - buf; | |
410 | } | |
411 | ||
4416b1f6 DS |
412 | int |
413 | pim_parse_addr_group (struct prefix *p, | |
414 | const uint8_t *buf, | |
415 | int buf_size) | |
12e41d03 DL |
416 | { |
417 | const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
418 | const uint8_t *addr; | |
419 | const uint8_t *pastend; | |
420 | int family; | |
421 | int type; | |
422 | int mask_len; | |
423 | ||
424 | if (buf_size < grp_encoding_min_len) { | |
4416b1f6 | 425 | zlog_warn("%s: group address encoding overflow: left=%d needed=%d", |
12e41d03 | 426 | __PRETTY_FUNCTION__, |
4416b1f6 | 427 | buf_size, grp_encoding_min_len); |
12e41d03 DL |
428 | return -1; |
429 | } | |
430 | ||
431 | addr = buf; | |
432 | pastend = buf + buf_size; | |
433 | ||
434 | family = *addr++; | |
435 | type = *addr++; | |
436 | //++addr; | |
437 | ++addr; /* skip b_reserved_z fields */ | |
438 | mask_len = *addr++; | |
439 | ||
440 | switch (family) { | |
441 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
442 | if (type) { | |
4416b1f6 DS |
443 | zlog_warn("%s: unknown group address encoding type=%d from", |
444 | __PRETTY_FUNCTION__, type); | |
12e41d03 DL |
445 | return -2; |
446 | } | |
447 | ||
448 | if ((addr + sizeof(struct in_addr)) > pastend) { | |
4416b1f6 | 449 | zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from", |
12e41d03 | 450 | __PRETTY_FUNCTION__, |
4416b1f6 | 451 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
452 | return -3; |
453 | } | |
454 | ||
455 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
456 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
457 | p->prefixlen = mask_len; | |
458 | ||
459 | addr += sizeof(struct in_addr); | |
460 | ||
461 | break; | |
462 | default: | |
463 | { | |
4416b1f6 DS |
464 | zlog_warn("%s: unknown group address encoding family=%d from", |
465 | __PRETTY_FUNCTION__, family); | |
12e41d03 DL |
466 | return -4; |
467 | } | |
468 | } | |
469 | ||
470 | return addr - buf; | |
471 | } | |
472 | ||
4416b1f6 DS |
473 | int |
474 | pim_parse_addr_source(struct prefix *p, | |
475 | uint8_t *flags, | |
476 | const uint8_t *buf, | |
477 | int buf_size) | |
12e41d03 DL |
478 | { |
479 | const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
480 | const uint8_t *addr; | |
481 | const uint8_t *pastend; | |
482 | int family; | |
483 | int type; | |
484 | int mask_len; | |
485 | ||
486 | if (buf_size < src_encoding_min_len) { | |
4416b1f6 | 487 | zlog_warn("%s: source address encoding overflow: left=%d needed=%d", |
12e41d03 | 488 | __PRETTY_FUNCTION__, |
4416b1f6 | 489 | buf_size, src_encoding_min_len); |
12e41d03 DL |
490 | return -1; |
491 | } | |
492 | ||
493 | addr = buf; | |
494 | pastend = buf + buf_size; | |
495 | ||
496 | family = *addr++; | |
497 | type = *addr++; | |
498 | *flags = *addr++; | |
499 | mask_len = *addr++; | |
500 | ||
4416b1f6 DS |
501 | if (type) { |
502 | zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", | |
503 | __PRETTY_FUNCTION__, | |
504 | type, | |
505 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | |
506 | return -2; | |
507 | } | |
508 | ||
12e41d03 DL |
509 | switch (family) { |
510 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
12e41d03 | 511 | if ((addr + sizeof(struct in_addr)) > pastend) { |
4416b1f6 | 512 | zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu", |
12e41d03 | 513 | __PRETTY_FUNCTION__, |
4416b1f6 | 514 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
515 | return -3; |
516 | } | |
517 | ||
518 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
519 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
520 | p->prefixlen = mask_len; | |
521 | ||
522 | /* | |
523 | RFC 4601: 4.9.1 Encoded Source and Group Address Formats | |
524 | ||
525 | Encoded-Source Address | |
526 | ||
527 | The mask length MUST be equal to the mask length in bits for | |
528 | the given Address Family and Encoding Type (32 for IPv4 native | |
529 | and 128 for IPv6 native). A router SHOULD ignore any messages | |
530 | received with any other mask length. | |
531 | */ | |
532 | if (p->prefixlen != 32) { | |
4416b1f6 DS |
533 | zlog_warn("%s: IPv4 bad source address mask: %d", |
534 | __PRETTY_FUNCTION__, p->prefixlen); | |
12e41d03 DL |
535 | return -4; |
536 | } | |
537 | ||
538 | addr += sizeof(struct in_addr); | |
539 | ||
540 | break; | |
541 | default: | |
542 | { | |
4416b1f6 | 543 | zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", |
12e41d03 | 544 | __PRETTY_FUNCTION__, |
4416b1f6 | 545 | family, |
12e41d03 DL |
546 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); |
547 | return -5; | |
548 | } | |
549 | } | |
550 | ||
551 | return addr - buf; | |
552 | } | |
553 | ||
554 | #define FREE_ADDR_LIST(hello_option_addr_list) \ | |
555 | { \ | |
556 | if (hello_option_addr_list) { \ | |
557 | list_delete(hello_option_addr_list); \ | |
558 | hello_option_addr_list = 0; \ | |
559 | } \ | |
560 | } | |
561 | ||
562 | int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, | |
563 | pim_hello_options *hello_options, | |
564 | struct list **hello_option_addr_list, | |
565 | uint16_t option_len, | |
566 | const uint8_t *tlv_curr) | |
567 | { | |
568 | const uint8_t *addr; | |
569 | const uint8_t *pastend; | |
570 | ||
571 | zassert(hello_option_addr_list); | |
572 | ||
573 | /* | |
574 | Scan addr list | |
575 | */ | |
576 | addr = tlv_curr; | |
577 | pastend = tlv_curr + option_len; | |
578 | while (addr < pastend) { | |
579 | struct prefix tmp; | |
580 | int addr_offset; | |
581 | ||
582 | /* | |
583 | Parse ucast addr | |
584 | */ | |
4416b1f6 | 585 | addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); |
12e41d03 DL |
586 | if (addr_offset < 1) { |
587 | char src_str[100]; | |
588 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
589 | zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", | |
590 | __PRETTY_FUNCTION__, | |
591 | src_str, ifname); | |
592 | FREE_ADDR_LIST(*hello_option_addr_list); | |
593 | return -1; | |
594 | } | |
595 | addr += addr_offset; | |
596 | ||
597 | /* | |
598 | Debug | |
599 | */ | |
600 | if (PIM_DEBUG_PIM_TRACE) { | |
601 | switch (tmp.family) { | |
602 | case AF_INET: | |
603 | { | |
604 | char addr_str[100]; | |
605 | char src_str[100]; | |
606 | pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); | |
607 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
608 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", | |
609 | __PRETTY_FUNCTION__, | |
610 | *hello_option_addr_list ? | |
611 | ((int) listcount(*hello_option_addr_list)) : -1, | |
612 | addr_str, src_str, ifname); | |
613 | } | |
614 | break; | |
615 | default: | |
616 | { | |
617 | char src_str[100]; | |
618 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
619 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", | |
620 | __PRETTY_FUNCTION__, | |
621 | *hello_option_addr_list ? | |
622 | ((int) listcount(*hello_option_addr_list)) : -1, | |
623 | src_str, ifname); | |
624 | } | |
625 | } | |
626 | } | |
627 | ||
628 | /* | |
629 | Exclude neighbor's primary address if incorrectly included in | |
630 | the secondary address list | |
631 | */ | |
632 | if (tmp.family == AF_INET) { | |
633 | if (tmp.u.prefix4.s_addr == src_addr.s_addr) { | |
634 | char src_str[100]; | |
635 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
636 | zlog_warn("%s: ignoring primary address in secondary list from %s on %s", | |
637 | __PRETTY_FUNCTION__, | |
638 | src_str, ifname); | |
639 | continue; | |
640 | } | |
641 | } | |
642 | ||
643 | /* | |
644 | Allocate list if needed | |
645 | */ | |
646 | if (!*hello_option_addr_list) { | |
647 | *hello_option_addr_list = list_new(); | |
648 | if (!*hello_option_addr_list) { | |
649 | zlog_err("%s %s: failure: hello_option_addr_list=list_new()", | |
650 | __FILE__, __PRETTY_FUNCTION__); | |
651 | return -2; | |
652 | } | |
653 | (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; | |
654 | } | |
655 | ||
656 | /* | |
657 | Attach addr to list | |
658 | */ | |
659 | { | |
660 | struct prefix *p; | |
661 | p = prefix_new(); | |
662 | if (!p) { | |
663 | zlog_err("%s %s: failure: prefix_new()", | |
664 | __FILE__, __PRETTY_FUNCTION__); | |
665 | FREE_ADDR_LIST(*hello_option_addr_list); | |
666 | return -3; | |
667 | } | |
668 | p->family = tmp.family; | |
669 | p->u.prefix4 = tmp.u.prefix4; | |
670 | listnode_add(*hello_option_addr_list, p); | |
671 | } | |
672 | ||
673 | } /* while (addr < pastend) */ | |
674 | ||
675 | /* | |
676 | Mark hello option | |
677 | */ | |
678 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); | |
679 | ||
680 | return 0; | |
681 | } |