]>
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 | ||
100 | uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, | |
101 | const uint8_t *buf_pastend, | |
102 | struct list *ifconnected) | |
103 | { | |
104 | struct listnode *node; | |
105 | uint16_t option_len = 0; | |
106 | ||
107 | uint8_t *curr; | |
108 | ||
109 | node = listhead(ifconnected); | |
110 | ||
111 | /* Empty address list ? */ | |
112 | if (!node) { | |
113 | return buf; | |
114 | } | |
115 | ||
116 | /* Skip first address (primary) */ | |
117 | node = listnextnode(node); | |
118 | ||
119 | /* Scan secondary address list */ | |
120 | curr = buf + 4; /* skip T and L */ | |
121 | for (; node; node = listnextnode(node)) { | |
122 | struct connected *ifc = listgetdata(node); | |
123 | struct prefix *p = ifc->address; | |
124 | ||
125 | if (p->family != AF_INET) | |
126 | continue; | |
127 | ||
aea6cb94 | 128 | if ((curr + ucast_ipv4_encoding_len) > buf_pastend) |
12e41d03 | 129 | return 0; |
12e41d03 DL |
130 | |
131 | /* Write encoded unicast IPv4 address */ | |
132 | *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
133 | ++curr; | |
134 | *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ | |
135 | ++curr; | |
136 | memcpy(curr, &p->u.prefix4, sizeof(struct in_addr)); | |
137 | curr += sizeof(struct in_addr); | |
138 | ||
139 | option_len += ucast_ipv4_encoding_len; | |
140 | } | |
141 | ||
142 | if (PIM_DEBUG_PIM_TRACE) { | |
aea6cb94 DS |
143 | zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", |
144 | __PRETTY_FUNCTION__, | |
145 | option_len / ucast_ipv4_encoding_len); | |
12e41d03 DL |
146 | } |
147 | ||
148 | if (option_len < 1) { | |
149 | /* Empty secondary unicast IPv4 address list */ | |
150 | return buf; | |
151 | } | |
152 | ||
153 | /* | |
154 | * Write T and L | |
155 | */ | |
156 | *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); | |
157 | *(uint16_t *) (buf + 2) = htons(option_len); | |
158 | ||
159 | return curr; | |
160 | } | |
161 | ||
162 | static int check_tlv_length(const char *label, const char *tlv_name, | |
163 | const char *ifname, struct in_addr src_addr, | |
164 | int correct_len, int option_len) | |
165 | { | |
166 | if (option_len != correct_len) { | |
167 | char src_str[100]; | |
168 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
169 | zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", | |
170 | label, tlv_name, | |
171 | option_len, correct_len, | |
172 | src_str, ifname); | |
173 | return -1; | |
174 | } | |
175 | ||
176 | return 0; | |
177 | } | |
178 | ||
179 | static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, | |
180 | const char *ifname, struct in_addr src_addr, | |
181 | pim_hello_options options, | |
182 | pim_hello_options opt_mask, | |
183 | uint16_t new, uint16_t old) | |
184 | { | |
185 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
186 | char src_str[100]; | |
187 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
188 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
189 | label, tlv_name, | |
190 | new, old, | |
191 | src_str, ifname); | |
192 | } | |
193 | } | |
194 | ||
195 | static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, | |
196 | const char *ifname, struct in_addr src_addr, | |
197 | pim_hello_options options, | |
198 | pim_hello_options opt_mask, | |
199 | uint32_t new, uint32_t old) | |
200 | { | |
201 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
202 | char src_str[100]; | |
203 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
204 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
205 | label, tlv_name, | |
206 | new, old, | |
207 | src_str, ifname); | |
208 | } | |
209 | } | |
210 | ||
211 | static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, | |
212 | const char *ifname, struct in_addr src_addr, | |
213 | pim_hello_options options, | |
214 | pim_hello_options opt_mask, | |
215 | uint32_t new, uint32_t old) | |
216 | { | |
217 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
218 | char src_str[100]; | |
219 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
220 | zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", | |
221 | label, tlv_name, | |
222 | new, old, | |
223 | src_str, ifname); | |
224 | } | |
225 | } | |
226 | ||
227 | int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, | |
228 | pim_hello_options *hello_options, | |
229 | uint16_t *hello_option_holdtime, | |
230 | uint16_t option_len, | |
231 | const uint8_t *tlv_curr) | |
232 | { | |
233 | const char *label = "holdtime"; | |
234 | ||
235 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
236 | ifname, src_addr, | |
237 | sizeof(uint16_t), option_len)) { | |
238 | return -1; | |
239 | } | |
240 | ||
241 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, | |
242 | ifname, src_addr, | |
243 | *hello_options, PIM_OPTION_MASK_HOLDTIME, | |
244 | PIM_TLV_GET_HOLDTIME(tlv_curr), | |
245 | *hello_option_holdtime); | |
246 | ||
247 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); | |
248 | ||
249 | *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); | |
250 | ||
251 | return 0; | |
252 | } | |
253 | ||
254 | int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, | |
255 | pim_hello_options *hello_options, | |
256 | uint16_t *hello_option_propagation_delay, | |
257 | uint16_t *hello_option_override_interval, | |
258 | uint16_t option_len, | |
259 | const uint8_t *tlv_curr) | |
260 | { | |
261 | if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", | |
262 | ifname, src_addr, | |
263 | sizeof(uint32_t), option_len)) { | |
264 | return -1; | |
265 | } | |
266 | ||
267 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", | |
268 | ifname, src_addr, | |
269 | *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, | |
270 | PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), | |
271 | *hello_option_propagation_delay); | |
272 | ||
273 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); | |
274 | ||
275 | *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); | |
276 | if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { | |
277 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
278 | } | |
279 | else { | |
280 | PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
281 | } | |
282 | ++tlv_curr; | |
283 | ++tlv_curr; | |
284 | *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); | |
285 | ||
286 | return 0; | |
287 | } | |
288 | ||
289 | int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, | |
290 | pim_hello_options *hello_options, | |
291 | uint32_t *hello_option_dr_priority, | |
292 | uint16_t option_len, | |
293 | const uint8_t *tlv_curr) | |
294 | { | |
295 | const char *label = "dr_priority"; | |
296 | ||
297 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
298 | ifname, src_addr, | |
299 | sizeof(uint32_t), option_len)) { | |
300 | return -1; | |
301 | } | |
302 | ||
303 | check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, | |
304 | ifname, src_addr, | |
305 | *hello_options, PIM_OPTION_MASK_DR_PRIORITY, | |
306 | PIM_TLV_GET_DR_PRIORITY(tlv_curr), | |
307 | *hello_option_dr_priority); | |
308 | ||
309 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); | |
310 | ||
311 | *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); | |
312 | ||
313 | return 0; | |
314 | } | |
315 | ||
316 | int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, | |
317 | pim_hello_options *hello_options, | |
318 | uint32_t *hello_option_generation_id, | |
319 | uint16_t option_len, | |
320 | const uint8_t *tlv_curr) | |
321 | { | |
322 | const char *label = "generation_id"; | |
323 | ||
324 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
325 | ifname, src_addr, | |
326 | sizeof(uint32_t), option_len)) { | |
327 | return -1; | |
328 | } | |
329 | ||
330 | check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, | |
331 | ifname, src_addr, | |
332 | *hello_options, PIM_OPTION_MASK_GENERATION_ID, | |
333 | PIM_TLV_GET_GENERATION_ID(tlv_curr), | |
334 | *hello_option_generation_id); | |
335 | ||
336 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); | |
337 | ||
338 | *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); | |
339 | ||
340 | return 0; | |
341 | } | |
342 | ||
343 | int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr, | |
344 | struct prefix *p, | |
345 | const uint8_t *buf, | |
346 | int buf_size) | |
347 | { | |
348 | const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ | |
349 | const uint8_t *addr; | |
350 | const uint8_t *pastend; | |
351 | int family; | |
352 | int type; | |
353 | ||
354 | if (buf_size < ucast_encoding_min_len) { | |
355 | char src_str[100]; | |
356 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
357 | zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s", | |
358 | __PRETTY_FUNCTION__, | |
359 | buf_size, ucast_encoding_min_len, | |
360 | src_str, ifname); | |
361 | return -1; | |
362 | } | |
363 | ||
364 | addr = buf; | |
365 | pastend = buf + buf_size; | |
366 | ||
367 | family = *addr++; | |
368 | type = *addr++; | |
369 | ||
370 | switch (family) { | |
371 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
372 | if (type) { | |
373 | char src_str[100]; | |
374 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
375 | zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s", | |
376 | __PRETTY_FUNCTION__, | |
377 | type, src_str, ifname); | |
378 | return -2; | |
379 | } | |
380 | ||
381 | if ((addr + sizeof(struct in_addr)) > pastend) { | |
382 | char src_str[100]; | |
383 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
384 | zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s", | |
385 | __PRETTY_FUNCTION__, | |
386 | pastend - addr, sizeof(struct in_addr), | |
387 | src_str, ifname); | |
388 | return -3; | |
389 | } | |
390 | ||
391 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
392 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
393 | ||
394 | addr += sizeof(struct in_addr); | |
395 | ||
396 | break; | |
397 | default: | |
398 | { | |
399 | char src_str[100]; | |
400 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
401 | zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s", | |
402 | __PRETTY_FUNCTION__, | |
403 | family, src_str, ifname); | |
404 | return -4; | |
405 | } | |
406 | } | |
407 | ||
408 | return addr - buf; | |
409 | } | |
410 | ||
411 | int pim_parse_addr_group(const char *ifname, struct in_addr src_addr, | |
412 | struct prefix *p, | |
413 | const uint8_t *buf, | |
414 | int buf_size) | |
415 | { | |
416 | const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
417 | const uint8_t *addr; | |
418 | const uint8_t *pastend; | |
419 | int family; | |
420 | int type; | |
421 | int mask_len; | |
422 | ||
423 | if (buf_size < grp_encoding_min_len) { | |
424 | char src_str[100]; | |
425 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
426 | zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s", | |
427 | __PRETTY_FUNCTION__, | |
428 | buf_size, grp_encoding_min_len, | |
429 | src_str, ifname); | |
430 | return -1; | |
431 | } | |
432 | ||
433 | addr = buf; | |
434 | pastend = buf + buf_size; | |
435 | ||
436 | family = *addr++; | |
437 | type = *addr++; | |
438 | //++addr; | |
439 | ++addr; /* skip b_reserved_z fields */ | |
440 | mask_len = *addr++; | |
441 | ||
442 | switch (family) { | |
443 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
444 | if (type) { | |
445 | char src_str[100]; | |
446 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
447 | zlog_warn("%s: unknown group address encoding type=%d from %s on %s", | |
448 | __PRETTY_FUNCTION__, | |
449 | type, src_str, ifname); | |
450 | return -2; | |
451 | } | |
452 | ||
453 | if ((addr + sizeof(struct in_addr)) > pastend) { | |
454 | char src_str[100]; | |
455 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
456 | zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s", | |
457 | __PRETTY_FUNCTION__, | |
458 | pastend - addr, sizeof(struct in_addr), | |
459 | src_str, ifname); | |
460 | return -3; | |
461 | } | |
462 | ||
463 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
464 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
465 | p->prefixlen = mask_len; | |
466 | ||
467 | addr += sizeof(struct in_addr); | |
468 | ||
469 | break; | |
470 | default: | |
471 | { | |
472 | char src_str[100]; | |
473 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
474 | zlog_warn("%s: unknown group address encoding family=%d from %s on %s", | |
475 | __PRETTY_FUNCTION__, | |
476 | family, src_str, ifname); | |
477 | return -4; | |
478 | } | |
479 | } | |
480 | ||
481 | return addr - buf; | |
482 | } | |
483 | ||
484 | int pim_parse_addr_source(const char *ifname, | |
485 | struct in_addr src_addr, | |
486 | struct prefix *p, | |
487 | uint8_t *flags, | |
488 | const uint8_t *buf, | |
489 | int buf_size) | |
490 | { | |
491 | const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
492 | const uint8_t *addr; | |
493 | const uint8_t *pastend; | |
494 | int family; | |
495 | int type; | |
496 | int mask_len; | |
497 | ||
498 | if (buf_size < src_encoding_min_len) { | |
499 | char src_str[100]; | |
500 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
501 | zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s", | |
502 | __PRETTY_FUNCTION__, | |
503 | buf_size, src_encoding_min_len, | |
504 | src_str, ifname); | |
505 | return -1; | |
506 | } | |
507 | ||
508 | addr = buf; | |
509 | pastend = buf + buf_size; | |
510 | ||
511 | family = *addr++; | |
512 | type = *addr++; | |
513 | *flags = *addr++; | |
514 | mask_len = *addr++; | |
515 | ||
516 | switch (family) { | |
517 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
518 | if (type) { | |
519 | char src_str[100]; | |
520 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
521 | zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", | |
522 | __PRETTY_FUNCTION__, | |
523 | type, src_str, ifname, | |
524 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | |
525 | return -2; | |
526 | } | |
527 | ||
528 | if ((addr + sizeof(struct in_addr)) > pastend) { | |
529 | char src_str[100]; | |
530 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
531 | zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s", | |
532 | __PRETTY_FUNCTION__, | |
533 | pastend - addr, sizeof(struct in_addr), | |
534 | src_str, ifname); | |
535 | return -3; | |
536 | } | |
537 | ||
538 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
539 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
540 | p->prefixlen = mask_len; | |
541 | ||
542 | /* | |
543 | RFC 4601: 4.9.1 Encoded Source and Group Address Formats | |
544 | ||
545 | Encoded-Source Address | |
546 | ||
547 | The mask length MUST be equal to the mask length in bits for | |
548 | the given Address Family and Encoding Type (32 for IPv4 native | |
549 | and 128 for IPv6 native). A router SHOULD ignore any messages | |
550 | received with any other mask length. | |
551 | */ | |
552 | if (p->prefixlen != 32) { | |
553 | char src_str[100]; | |
554 | pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str)); | |
555 | zlog_warn("%s: IPv4 bad source address mask: %s/%d", | |
556 | __PRETTY_FUNCTION__, src_str, p->prefixlen); | |
557 | return -4; | |
558 | } | |
559 | ||
560 | addr += sizeof(struct in_addr); | |
561 | ||
562 | break; | |
563 | default: | |
564 | { | |
565 | char src_str[100]; | |
566 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
567 | zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x", | |
568 | __PRETTY_FUNCTION__, | |
569 | family, src_str, ifname, | |
570 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | |
571 | return -5; | |
572 | } | |
573 | } | |
574 | ||
575 | return addr - buf; | |
576 | } | |
577 | ||
578 | #define FREE_ADDR_LIST(hello_option_addr_list) \ | |
579 | { \ | |
580 | if (hello_option_addr_list) { \ | |
581 | list_delete(hello_option_addr_list); \ | |
582 | hello_option_addr_list = 0; \ | |
583 | } \ | |
584 | } | |
585 | ||
586 | int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, | |
587 | pim_hello_options *hello_options, | |
588 | struct list **hello_option_addr_list, | |
589 | uint16_t option_len, | |
590 | const uint8_t *tlv_curr) | |
591 | { | |
592 | const uint8_t *addr; | |
593 | const uint8_t *pastend; | |
594 | ||
595 | zassert(hello_option_addr_list); | |
596 | ||
597 | /* | |
598 | Scan addr list | |
599 | */ | |
600 | addr = tlv_curr; | |
601 | pastend = tlv_curr + option_len; | |
602 | while (addr < pastend) { | |
603 | struct prefix tmp; | |
604 | int addr_offset; | |
605 | ||
606 | /* | |
607 | Parse ucast addr | |
608 | */ | |
609 | addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp, | |
610 | addr, pastend - addr); | |
611 | if (addr_offset < 1) { | |
612 | char src_str[100]; | |
613 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
614 | zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", | |
615 | __PRETTY_FUNCTION__, | |
616 | src_str, ifname); | |
617 | FREE_ADDR_LIST(*hello_option_addr_list); | |
618 | return -1; | |
619 | } | |
620 | addr += addr_offset; | |
621 | ||
622 | /* | |
623 | Debug | |
624 | */ | |
625 | if (PIM_DEBUG_PIM_TRACE) { | |
626 | switch (tmp.family) { | |
627 | case AF_INET: | |
628 | { | |
629 | char addr_str[100]; | |
630 | char src_str[100]; | |
631 | pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); | |
632 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
633 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", | |
634 | __PRETTY_FUNCTION__, | |
635 | *hello_option_addr_list ? | |
636 | ((int) listcount(*hello_option_addr_list)) : -1, | |
637 | addr_str, src_str, ifname); | |
638 | } | |
639 | break; | |
640 | default: | |
641 | { | |
642 | char src_str[100]; | |
643 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
644 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", | |
645 | __PRETTY_FUNCTION__, | |
646 | *hello_option_addr_list ? | |
647 | ((int) listcount(*hello_option_addr_list)) : -1, | |
648 | src_str, ifname); | |
649 | } | |
650 | } | |
651 | } | |
652 | ||
653 | /* | |
654 | Exclude neighbor's primary address if incorrectly included in | |
655 | the secondary address list | |
656 | */ | |
657 | if (tmp.family == AF_INET) { | |
658 | if (tmp.u.prefix4.s_addr == src_addr.s_addr) { | |
659 | char src_str[100]; | |
660 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
661 | zlog_warn("%s: ignoring primary address in secondary list from %s on %s", | |
662 | __PRETTY_FUNCTION__, | |
663 | src_str, ifname); | |
664 | continue; | |
665 | } | |
666 | } | |
667 | ||
668 | /* | |
669 | Allocate list if needed | |
670 | */ | |
671 | if (!*hello_option_addr_list) { | |
672 | *hello_option_addr_list = list_new(); | |
673 | if (!*hello_option_addr_list) { | |
674 | zlog_err("%s %s: failure: hello_option_addr_list=list_new()", | |
675 | __FILE__, __PRETTY_FUNCTION__); | |
676 | return -2; | |
677 | } | |
678 | (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; | |
679 | } | |
680 | ||
681 | /* | |
682 | Attach addr to list | |
683 | */ | |
684 | { | |
685 | struct prefix *p; | |
686 | p = prefix_new(); | |
687 | if (!p) { | |
688 | zlog_err("%s %s: failure: prefix_new()", | |
689 | __FILE__, __PRETTY_FUNCTION__); | |
690 | FREE_ADDR_LIST(*hello_option_addr_list); | |
691 | return -3; | |
692 | } | |
693 | p->family = tmp.family; | |
694 | p->u.prefix4 = tmp.u.prefix4; | |
695 | listnode_add(*hello_option_addr_list, p); | |
696 | } | |
697 | ||
698 | } /* while (addr < pastend) */ | |
699 | ||
700 | /* | |
701 | Mark hello option | |
702 | */ | |
703 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); | |
704 | ||
705 | return 0; | |
706 | } |