]>
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 | |
12e41d03 DL |
19 | */ |
20 | ||
21 | #include <zebra.h> | |
22 | ||
23 | #include "log.h" | |
24 | #include "prefix.h" | |
744d91b3 | 25 | #include "if.h" |
12e41d03 DL |
26 | |
27 | #include "pimd.h" | |
28 | #include "pim_int.h" | |
29 | #include "pim_tlv.h" | |
30 | #include "pim_str.h" | |
31 | #include "pim_msg.h" | |
32 | ||
33 | uint8_t *pim_tlv_append_uint16(uint8_t *buf, | |
34 | const uint8_t *buf_pastend, | |
35 | uint16_t option_type, | |
36 | uint16_t option_value) | |
37 | { | |
38 | uint16_t option_len = 2; | |
39 | ||
aea6cb94 DS |
40 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
41 | return NULL; | |
12e41d03 DL |
42 | |
43 | *(uint16_t *) buf = htons(option_type); | |
44 | buf += 2; | |
45 | *(uint16_t *) buf = htons(option_len); | |
46 | buf += 2; | |
47 | *(uint16_t *) buf = htons(option_value); | |
48 | buf += option_len; | |
49 | ||
50 | return buf; | |
51 | } | |
52 | ||
53 | uint8_t *pim_tlv_append_2uint16(uint8_t *buf, | |
54 | const uint8_t *buf_pastend, | |
55 | uint16_t option_type, | |
56 | uint16_t option_value1, | |
57 | uint16_t option_value2) | |
58 | { | |
59 | uint16_t option_len = 4; | |
60 | ||
aea6cb94 DS |
61 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
62 | return NULL; | |
12e41d03 DL |
63 | |
64 | *(uint16_t *) buf = htons(option_type); | |
65 | buf += 2; | |
66 | *(uint16_t *) buf = htons(option_len); | |
67 | buf += 2; | |
68 | *(uint16_t *) buf = htons(option_value1); | |
69 | buf += 2; | |
70 | *(uint16_t *) buf = htons(option_value2); | |
71 | buf += 2; | |
72 | ||
73 | return buf; | |
74 | } | |
75 | ||
76 | uint8_t *pim_tlv_append_uint32(uint8_t *buf, | |
77 | const uint8_t *buf_pastend, | |
78 | uint16_t option_type, | |
79 | uint32_t option_value) | |
80 | { | |
81 | uint16_t option_len = 4; | |
82 | ||
aea6cb94 DS |
83 | if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) |
84 | return NULL; | |
12e41d03 DL |
85 | |
86 | *(uint16_t *) buf = htons(option_type); | |
87 | buf += 2; | |
88 | *(uint16_t *) buf = htons(option_len); | |
89 | buf += 2; | |
90 | pim_write_uint32(buf, option_value); | |
91 | buf += option_len; | |
92 | ||
93 | return buf; | |
94 | } | |
95 | ||
96 | #define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr)) | |
0f4b1d2d | 97 | #define ucast_ipv6_encoding_len (2 + sizeof(struct in6_addr)) |
12e41d03 | 98 | |
984c84f4 DS |
99 | /* |
100 | * An Encoded-Unicast address takes the following format: | |
101 | * | |
102 | * 0 1 2 3 | |
103 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
104 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
105 | * | Addr Family | Encoding Type | Unicast Address | |
106 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+... | |
107 | * | |
108 | * Addr Family | |
109 | * The PIM address family of the 'Unicast Address' field of this | |
110 | * address. | |
111 | * | |
112 | * Values 0-127 are as assigned by the IANA for Internet Address * Families in [7]. Values 128-250 are reserved to be assigned by | |
113 | * the IANA for PIM-specific Address Families. Values 251 though | |
114 | * 255 are designated for private use. As there is no assignment | |
115 | * authority for this space, collisions should be expected. | |
116 | * | |
117 | * Encoding Type | |
118 | * The type of encoding used within a specific Address Family. The | |
119 | * value '0' is reserved for this field and represents the native | |
120 | * encoding of the Address Family. | |
121 | * | |
122 | * Unicast Address | |
123 | * The unicast address as represented by the given Address Family | |
124 | * and Encoding Type. | |
125 | */ | |
8f483f92 DS |
126 | int |
127 | pim_encode_addr_ucast (uint8_t *buf, struct prefix *p) | |
4416b1f6 DS |
128 | { |
129 | switch (p->family) | |
130 | { | |
131 | case AF_INET: | |
132 | *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
133 | ++buf; | |
134 | *(uint8_t *)buf = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */ | |
135 | ++buf; | |
136 | memcpy (buf, &p->u.prefix4, sizeof (struct in_addr)); | |
137 | return ucast_ipv4_encoding_len; | |
138 | break; | |
0f4b1d2d DS |
139 | case AF_INET6: |
140 | *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV6; | |
141 | ++buf; | |
142 | *(uint8_t *)buf = 0; | |
143 | ++buf; | |
144 | memcpy (buf, &p->u.prefix6, sizeof (struct in6_addr)); | |
145 | return ucast_ipv6_encoding_len; | |
146 | break; | |
4416b1f6 DS |
147 | default: |
148 | return 0; | |
149 | break; | |
150 | } | |
151 | } | |
152 | ||
8f483f92 DS |
153 | #define group_ipv4_encoding_len (4 + sizeof (struct in_addr)) |
154 | ||
155 | /* | |
156 | * Encoded-Group addresses take the following format: | |
157 | * | |
158 | * 0 1 2 3 | |
159 | * 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 | |
160 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
161 | * | Addr Family | Encoding Type |B| Reserved |Z| Mask Len | | |
162 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | |
163 | * | Group multicast Address | |
164 | * +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+... | |
165 | * | |
166 | * Addr Family | |
167 | * Described above. | |
168 | * | |
169 | * Encoding Type | |
170 | * Described above. | |
171 | * | |
172 | * [B]idirectional PIM | |
173 | * Indicates the group range should use Bidirectional PIM [13]. | |
174 | * For PIM-SM defined in this specification, this bit MUST be zero. | |
175 | * | |
176 | * Reserved | |
177 | * Transmitted as zero. Ignored upon receipt. | |
178 | * | |
179 | * Admin Scope [Z]one | |
180 | * indicates the group range is an admin scope zone. This is used | |
181 | * in the Bootstrap Router Mechanism [11] only. For all other | |
182 | * purposes, this bit is set to zero and ignored on receipt. | |
183 | * | |
184 | * Mask Len | |
185 | * The Mask length field is 8 bits. The value is the number of | |
186 | * contiguous one bits that are left justified and used as a mask; | |
187 | * when combined with the group address, it describes a range of | |
188 | * groups. It is less than or equal to the address length in bits | |
189 | * for the given Address Family and Encoding Type. If the message | |
190 | * is sent for a single group, then the Mask length must equal the | |
191 | * address length in bits for the given Address Family and Encoding | |
192 | * Type (e.g., 32 for IPv4 native encoding, 128 for IPv6 native | |
193 | * encoding). | |
194 | * | |
195 | * Group multicast Address | |
196 | * Contains the group address. | |
197 | */ | |
198 | int | |
199 | pim_encode_addr_group (uint8_t *buf, afi_t afi, int bidir, int scope, struct in_addr group) | |
200 | { | |
201 | uint8_t flags = 0; | |
202 | ||
203 | flags |= bidir << 8; | |
204 | flags |= scope; | |
205 | ||
206 | switch (afi) | |
207 | { | |
208 | case AFI_IP: | |
209 | *(uint8_t *)buf = PIM_MSG_ADDRESS_FAMILY_IPV4; | |
210 | ++buf; | |
211 | *(uint8_t *)buf = 0; | |
212 | ++buf; | |
213 | *(uint8_t *)buf = flags; | |
214 | ++buf; | |
215 | *(uint8_t *)buf = 32; | |
216 | ++buf; | |
217 | memcpy (buf, &group, sizeof (struct in_addr)); | |
218 | return group_ipv4_encoding_len; | |
219 | break; | |
220 | default: | |
221 | return 0; | |
222 | break; | |
223 | } | |
224 | } | |
225 | ||
12e41d03 DL |
226 | uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf, |
227 | const uint8_t *buf_pastend, | |
0f4b1d2d DS |
228 | struct list *ifconnected, |
229 | int family) | |
12e41d03 DL |
230 | { |
231 | struct listnode *node; | |
232 | uint16_t option_len = 0; | |
12e41d03 | 233 | uint8_t *curr; |
0f4b1d2d | 234 | size_t uel; |
12e41d03 DL |
235 | |
236 | node = listhead(ifconnected); | |
237 | ||
238 | /* Empty address list ? */ | |
239 | if (!node) { | |
240 | return buf; | |
241 | } | |
242 | ||
0f4b1d2d DS |
243 | if (family == AF_INET) |
244 | uel = ucast_ipv4_encoding_len; | |
245 | else | |
246 | uel = ucast_ipv6_encoding_len; | |
12e41d03 DL |
247 | |
248 | /* Scan secondary address list */ | |
249 | curr = buf + 4; /* skip T and L */ | |
250 | for (; node; node = listnextnode(node)) { | |
251 | struct connected *ifc = listgetdata(node); | |
252 | struct prefix *p = ifc->address; | |
4416b1f6 | 253 | int l_encode; |
12e41d03 | 254 | |
0f4b1d2d DS |
255 | if (!CHECK_FLAG(ifc->flags, ZEBRA_IFA_SECONDARY)) |
256 | continue; | |
257 | ||
258 | if ((curr + uel) > buf_pastend) | |
259 | return 0; | |
260 | ||
261 | if (p->family != family) | |
262 | continue; | |
12e41d03 | 263 | |
8f483f92 | 264 | l_encode = pim_encode_addr_ucast (curr, p); |
4416b1f6 DS |
265 | curr += l_encode; |
266 | option_len += l_encode; | |
12e41d03 DL |
267 | } |
268 | ||
169edb7f | 269 | if (PIM_DEBUG_PIM_TRACE_DETAIL) { |
aea6cb94 DS |
270 | zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu", |
271 | __PRETTY_FUNCTION__, | |
0f4b1d2d | 272 | option_len / uel); |
12e41d03 DL |
273 | } |
274 | ||
275 | if (option_len < 1) { | |
276 | /* Empty secondary unicast IPv4 address list */ | |
277 | return buf; | |
278 | } | |
279 | ||
280 | /* | |
281 | * Write T and L | |
282 | */ | |
283 | *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST); | |
284 | *(uint16_t *) (buf + 2) = htons(option_len); | |
285 | ||
286 | return curr; | |
287 | } | |
288 | ||
289 | static int check_tlv_length(const char *label, const char *tlv_name, | |
290 | const char *ifname, struct in_addr src_addr, | |
291 | int correct_len, int option_len) | |
292 | { | |
293 | if (option_len != correct_len) { | |
eaa54bdb | 294 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
295 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
296 | zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s", | |
297 | label, tlv_name, | |
298 | option_len, correct_len, | |
299 | src_str, ifname); | |
300 | return -1; | |
301 | } | |
302 | ||
303 | return 0; | |
304 | } | |
305 | ||
306 | static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name, | |
307 | const char *ifname, struct in_addr src_addr, | |
308 | pim_hello_options options, | |
309 | pim_hello_options opt_mask, | |
310 | uint16_t new, uint16_t old) | |
311 | { | |
312 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
eaa54bdb | 313 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
314 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
315 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
316 | label, tlv_name, | |
317 | new, old, | |
318 | src_str, ifname); | |
319 | } | |
320 | } | |
321 | ||
322 | static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name, | |
323 | const char *ifname, struct in_addr src_addr, | |
324 | pim_hello_options options, | |
325 | pim_hello_options opt_mask, | |
326 | uint32_t new, uint32_t old) | |
327 | { | |
328 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
eaa54bdb | 329 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
330 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
331 | zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s", | |
332 | label, tlv_name, | |
333 | new, old, | |
334 | src_str, ifname); | |
335 | } | |
336 | } | |
337 | ||
338 | static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name, | |
339 | const char *ifname, struct in_addr src_addr, | |
340 | pim_hello_options options, | |
341 | pim_hello_options opt_mask, | |
342 | uint32_t new, uint32_t old) | |
343 | { | |
344 | if (PIM_OPTION_IS_SET(options, opt_mask)) { | |
eaa54bdb | 345 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
346 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
347 | zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s", | |
348 | label, tlv_name, | |
349 | new, old, | |
350 | src_str, ifname); | |
351 | } | |
352 | } | |
353 | ||
354 | int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr, | |
355 | pim_hello_options *hello_options, | |
356 | uint16_t *hello_option_holdtime, | |
357 | uint16_t option_len, | |
358 | const uint8_t *tlv_curr) | |
359 | { | |
360 | const char *label = "holdtime"; | |
361 | ||
362 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
363 | ifname, src_addr, | |
364 | sizeof(uint16_t), option_len)) { | |
365 | return -1; | |
366 | } | |
367 | ||
368 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label, | |
369 | ifname, src_addr, | |
370 | *hello_options, PIM_OPTION_MASK_HOLDTIME, | |
371 | PIM_TLV_GET_HOLDTIME(tlv_curr), | |
372 | *hello_option_holdtime); | |
373 | ||
374 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME); | |
375 | ||
376 | *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr); | |
377 | ||
378 | return 0; | |
379 | } | |
380 | ||
381 | int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr, | |
382 | pim_hello_options *hello_options, | |
383 | uint16_t *hello_option_propagation_delay, | |
384 | uint16_t *hello_option_override_interval, | |
385 | uint16_t option_len, | |
386 | const uint8_t *tlv_curr) | |
387 | { | |
388 | if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay", | |
389 | ifname, src_addr, | |
390 | sizeof(uint32_t), option_len)) { | |
391 | return -1; | |
392 | } | |
393 | ||
394 | check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay", | |
395 | ifname, src_addr, | |
396 | *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY, | |
397 | PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr), | |
398 | *hello_option_propagation_delay); | |
399 | ||
400 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY); | |
401 | ||
402 | *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr); | |
403 | if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) { | |
404 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
405 | } | |
406 | else { | |
407 | PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION); | |
408 | } | |
409 | ++tlv_curr; | |
410 | ++tlv_curr; | |
411 | *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr); | |
412 | ||
413 | return 0; | |
414 | } | |
415 | ||
416 | int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr, | |
417 | pim_hello_options *hello_options, | |
418 | uint32_t *hello_option_dr_priority, | |
419 | uint16_t option_len, | |
420 | const uint8_t *tlv_curr) | |
421 | { | |
422 | const char *label = "dr_priority"; | |
423 | ||
424 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
425 | ifname, src_addr, | |
426 | sizeof(uint32_t), option_len)) { | |
427 | return -1; | |
428 | } | |
429 | ||
430 | check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label, | |
431 | ifname, src_addr, | |
432 | *hello_options, PIM_OPTION_MASK_DR_PRIORITY, | |
433 | PIM_TLV_GET_DR_PRIORITY(tlv_curr), | |
434 | *hello_option_dr_priority); | |
435 | ||
436 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY); | |
437 | ||
438 | *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr); | |
439 | ||
440 | return 0; | |
441 | } | |
442 | ||
443 | int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr, | |
444 | pim_hello_options *hello_options, | |
445 | uint32_t *hello_option_generation_id, | |
446 | uint16_t option_len, | |
447 | const uint8_t *tlv_curr) | |
448 | { | |
449 | const char *label = "generation_id"; | |
450 | ||
451 | if (check_tlv_length(__PRETTY_FUNCTION__, label, | |
452 | ifname, src_addr, | |
453 | sizeof(uint32_t), option_len)) { | |
454 | return -1; | |
455 | } | |
456 | ||
457 | check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label, | |
458 | ifname, src_addr, | |
459 | *hello_options, PIM_OPTION_MASK_GENERATION_ID, | |
460 | PIM_TLV_GET_GENERATION_ID(tlv_curr), | |
461 | *hello_option_generation_id); | |
462 | ||
463 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID); | |
464 | ||
465 | *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr); | |
466 | ||
467 | return 0; | |
468 | } | |
469 | ||
4416b1f6 DS |
470 | int |
471 | pim_parse_addr_ucast (struct prefix *p, | |
472 | const uint8_t *buf, | |
473 | int buf_size) | |
12e41d03 DL |
474 | { |
475 | const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */ | |
476 | const uint8_t *addr; | |
477 | const uint8_t *pastend; | |
478 | int family; | |
479 | int type; | |
480 | ||
481 | if (buf_size < ucast_encoding_min_len) { | |
4416b1f6 | 482 | zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d", |
12e41d03 | 483 | __PRETTY_FUNCTION__, |
4416b1f6 | 484 | buf_size, ucast_encoding_min_len); |
12e41d03 DL |
485 | return -1; |
486 | } | |
487 | ||
488 | addr = buf; | |
489 | pastend = buf + buf_size; | |
490 | ||
491 | family = *addr++; | |
492 | type = *addr++; | |
493 | ||
4416b1f6 DS |
494 | if (type) { |
495 | zlog_warn("%s: unknown unicast address encoding type=%d", | |
496 | __PRETTY_FUNCTION__, | |
497 | type); | |
498 | return -2; | |
499 | } | |
500 | ||
12e41d03 DL |
501 | switch (family) { |
502 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
12e41d03 | 503 | if ((addr + sizeof(struct in_addr)) > pastend) { |
4416b1f6 | 504 | zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu", |
12e41d03 | 505 | __PRETTY_FUNCTION__, |
4416b1f6 | 506 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
507 | return -3; |
508 | } | |
509 | ||
510 | p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */ | |
511 | memcpy(&p->u.prefix4, addr, sizeof(struct in_addr)); | |
0f4b1d2d | 512 | p->prefixlen = IPV4_MAX_PREFIXLEN; |
12e41d03 DL |
513 | addr += sizeof(struct in_addr); |
514 | ||
0f4b1d2d DS |
515 | break; |
516 | case PIM_MSG_ADDRESS_FAMILY_IPV6: | |
517 | if ((addr + sizeof(struct in6_addr)) > pastend) { | |
518 | zlog_warn ("%s: IPv6 unicast address overflow: left=%zd needed %zu", | |
519 | __PRETTY_FUNCTION__, | |
520 | pastend - addr, sizeof(struct in6_addr)); | |
521 | return -3; | |
522 | } | |
523 | ||
524 | p->family = AF_INET6; | |
525 | p->prefixlen = IPV6_MAX_PREFIXLEN; | |
4390fb99 | 526 | memcpy(&p->u.prefix6, addr, sizeof(struct in6_addr)); |
0f4b1d2d DS |
527 | addr += sizeof(struct in6_addr); |
528 | ||
12e41d03 DL |
529 | break; |
530 | default: | |
531 | { | |
4416b1f6 | 532 | zlog_warn("%s: unknown unicast address encoding family=%d from", |
12e41d03 | 533 | __PRETTY_FUNCTION__, |
4416b1f6 | 534 | family); |
12e41d03 DL |
535 | return -4; |
536 | } | |
537 | } | |
538 | ||
539 | return addr - buf; | |
540 | } | |
541 | ||
4416b1f6 | 542 | int |
bce0e645 | 543 | pim_parse_addr_group (struct prefix_sg *sg, |
4416b1f6 DS |
544 | const uint8_t *buf, |
545 | int buf_size) | |
12e41d03 DL |
546 | { |
547 | const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
548 | const uint8_t *addr; | |
549 | const uint8_t *pastend; | |
550 | int family; | |
551 | int type; | |
552 | int mask_len; | |
553 | ||
554 | if (buf_size < grp_encoding_min_len) { | |
4416b1f6 | 555 | zlog_warn("%s: group address encoding overflow: left=%d needed=%d", |
12e41d03 | 556 | __PRETTY_FUNCTION__, |
4416b1f6 | 557 | buf_size, grp_encoding_min_len); |
12e41d03 DL |
558 | return -1; |
559 | } | |
560 | ||
561 | addr = buf; | |
562 | pastend = buf + buf_size; | |
563 | ||
564 | family = *addr++; | |
565 | type = *addr++; | |
566 | //++addr; | |
567 | ++addr; /* skip b_reserved_z fields */ | |
568 | mask_len = *addr++; | |
569 | ||
570 | switch (family) { | |
571 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
572 | if (type) { | |
4416b1f6 DS |
573 | zlog_warn("%s: unknown group address encoding type=%d from", |
574 | __PRETTY_FUNCTION__, type); | |
12e41d03 DL |
575 | return -2; |
576 | } | |
577 | ||
578 | if ((addr + sizeof(struct in_addr)) > pastend) { | |
4416b1f6 | 579 | zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from", |
12e41d03 | 580 | __PRETTY_FUNCTION__, |
4416b1f6 | 581 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
582 | return -3; |
583 | } | |
584 | ||
bce0e645 | 585 | memcpy(&sg->grp.s_addr, addr, sizeof(struct in_addr)); |
12e41d03 DL |
586 | |
587 | addr += sizeof(struct in_addr); | |
588 | ||
589 | break; | |
590 | default: | |
591 | { | |
bce0e645 DS |
592 | zlog_warn("%s: unknown group address encoding family=%d mask_len=%d from", |
593 | __PRETTY_FUNCTION__, family, mask_len); | |
12e41d03 DL |
594 | return -4; |
595 | } | |
596 | } | |
597 | ||
598 | return addr - buf; | |
599 | } | |
600 | ||
4416b1f6 | 601 | int |
a7762e07 | 602 | pim_parse_addr_source(struct prefix_sg *sg, |
4416b1f6 DS |
603 | uint8_t *flags, |
604 | const uint8_t *buf, | |
605 | int buf_size) | |
12e41d03 DL |
606 | { |
607 | const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */ | |
608 | const uint8_t *addr; | |
609 | const uint8_t *pastend; | |
610 | int family; | |
611 | int type; | |
612 | int mask_len; | |
613 | ||
614 | if (buf_size < src_encoding_min_len) { | |
4416b1f6 | 615 | zlog_warn("%s: source address encoding overflow: left=%d needed=%d", |
12e41d03 | 616 | __PRETTY_FUNCTION__, |
4416b1f6 | 617 | buf_size, src_encoding_min_len); |
12e41d03 DL |
618 | return -1; |
619 | } | |
620 | ||
621 | addr = buf; | |
622 | pastend = buf + buf_size; | |
623 | ||
624 | family = *addr++; | |
625 | type = *addr++; | |
626 | *flags = *addr++; | |
627 | mask_len = *addr++; | |
628 | ||
4416b1f6 DS |
629 | if (type) { |
630 | zlog_warn("%s: unknown source address encoding type=%d: %02x%02x%02x%02x%02x%02x%02x%02x", | |
631 | __PRETTY_FUNCTION__, | |
632 | type, | |
633 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); | |
634 | return -2; | |
635 | } | |
636 | ||
12e41d03 DL |
637 | switch (family) { |
638 | case PIM_MSG_ADDRESS_FAMILY_IPV4: | |
12e41d03 | 639 | if ((addr + sizeof(struct in_addr)) > pastend) { |
4416b1f6 | 640 | zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu", |
12e41d03 | 641 | __PRETTY_FUNCTION__, |
4416b1f6 | 642 | pastend - addr, sizeof(struct in_addr)); |
12e41d03 DL |
643 | return -3; |
644 | } | |
645 | ||
a7762e07 | 646 | memcpy(&sg->src, addr, sizeof(struct in_addr)); |
12e41d03 DL |
647 | |
648 | /* | |
649 | RFC 4601: 4.9.1 Encoded Source and Group Address Formats | |
650 | ||
651 | Encoded-Source Address | |
652 | ||
653 | The mask length MUST be equal to the mask length in bits for | |
654 | the given Address Family and Encoding Type (32 for IPv4 native | |
655 | and 128 for IPv6 native). A router SHOULD ignore any messages | |
656 | received with any other mask length. | |
657 | */ | |
a7762e07 | 658 | if (mask_len != 32) { |
4416b1f6 | 659 | zlog_warn("%s: IPv4 bad source address mask: %d", |
a7762e07 | 660 | __PRETTY_FUNCTION__, mask_len); |
12e41d03 DL |
661 | return -4; |
662 | } | |
663 | ||
664 | addr += sizeof(struct in_addr); | |
665 | ||
666 | break; | |
667 | default: | |
668 | { | |
4416b1f6 | 669 | zlog_warn("%s: unknown source address encoding family=%d: %02x%02x%02x%02x%02x%02x%02x%02x", |
12e41d03 | 670 | __PRETTY_FUNCTION__, |
4416b1f6 | 671 | family, |
12e41d03 DL |
672 | buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]); |
673 | return -5; | |
674 | } | |
675 | } | |
676 | ||
677 | return addr - buf; | |
678 | } | |
679 | ||
680 | #define FREE_ADDR_LIST(hello_option_addr_list) \ | |
681 | { \ | |
682 | if (hello_option_addr_list) { \ | |
683 | list_delete(hello_option_addr_list); \ | |
684 | hello_option_addr_list = 0; \ | |
685 | } \ | |
686 | } | |
687 | ||
688 | int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr, | |
689 | pim_hello_options *hello_options, | |
690 | struct list **hello_option_addr_list, | |
691 | uint16_t option_len, | |
692 | const uint8_t *tlv_curr) | |
693 | { | |
694 | const uint8_t *addr; | |
695 | const uint8_t *pastend; | |
696 | ||
697 | zassert(hello_option_addr_list); | |
698 | ||
699 | /* | |
700 | Scan addr list | |
701 | */ | |
702 | addr = tlv_curr; | |
703 | pastend = tlv_curr + option_len; | |
704 | while (addr < pastend) { | |
705 | struct prefix tmp; | |
706 | int addr_offset; | |
707 | ||
708 | /* | |
709 | Parse ucast addr | |
710 | */ | |
4416b1f6 | 711 | addr_offset = pim_parse_addr_ucast(&tmp, addr, pastend - addr); |
12e41d03 | 712 | if (addr_offset < 1) { |
eaa54bdb | 713 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
714 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
715 | zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s", | |
716 | __PRETTY_FUNCTION__, | |
717 | src_str, ifname); | |
718 | FREE_ADDR_LIST(*hello_option_addr_list); | |
719 | return -1; | |
720 | } | |
721 | addr += addr_offset; | |
722 | ||
723 | /* | |
724 | Debug | |
725 | */ | |
726 | if (PIM_DEBUG_PIM_TRACE) { | |
727 | switch (tmp.family) { | |
728 | case AF_INET: | |
729 | { | |
eaa54bdb DW |
730 | char addr_str[INET_ADDRSTRLEN]; |
731 | char src_str[INET_ADDRSTRLEN]; | |
12e41d03 DL |
732 | pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str)); |
733 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); | |
734 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s", | |
735 | __PRETTY_FUNCTION__, | |
736 | *hello_option_addr_list ? | |
737 | ((int) listcount(*hello_option_addr_list)) : -1, | |
738 | addr_str, src_str, ifname); | |
739 | } | |
740 | break; | |
0f4b1d2d DS |
741 | case AF_INET6: |
742 | break; | |
12e41d03 DL |
743 | default: |
744 | { | |
eaa54bdb | 745 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
746 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
747 | zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s", | |
748 | __PRETTY_FUNCTION__, | |
749 | *hello_option_addr_list ? | |
750 | ((int) listcount(*hello_option_addr_list)) : -1, | |
751 | src_str, ifname); | |
752 | } | |
753 | } | |
754 | } | |
755 | ||
756 | /* | |
757 | Exclude neighbor's primary address if incorrectly included in | |
758 | the secondary address list | |
759 | */ | |
760 | if (tmp.family == AF_INET) { | |
761 | if (tmp.u.prefix4.s_addr == src_addr.s_addr) { | |
eaa54bdb | 762 | char src_str[INET_ADDRSTRLEN]; |
12e41d03 DL |
763 | pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str)); |
764 | zlog_warn("%s: ignoring primary address in secondary list from %s on %s", | |
765 | __PRETTY_FUNCTION__, | |
766 | src_str, ifname); | |
767 | continue; | |
768 | } | |
769 | } | |
770 | ||
771 | /* | |
772 | Allocate list if needed | |
773 | */ | |
774 | if (!*hello_option_addr_list) { | |
775 | *hello_option_addr_list = list_new(); | |
776 | if (!*hello_option_addr_list) { | |
777 | zlog_err("%s %s: failure: hello_option_addr_list=list_new()", | |
778 | __FILE__, __PRETTY_FUNCTION__); | |
779 | return -2; | |
780 | } | |
781 | (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free; | |
782 | } | |
783 | ||
784 | /* | |
785 | Attach addr to list | |
786 | */ | |
787 | { | |
788 | struct prefix *p; | |
789 | p = prefix_new(); | |
790 | if (!p) { | |
791 | zlog_err("%s %s: failure: prefix_new()", | |
792 | __FILE__, __PRETTY_FUNCTION__); | |
793 | FREE_ADDR_LIST(*hello_option_addr_list); | |
794 | return -3; | |
795 | } | |
0f4b1d2d | 796 | prefix_copy(p, &tmp); |
12e41d03 DL |
797 | listnode_add(*hello_option_addr_list, p); |
798 | } | |
799 | ||
800 | } /* while (addr < pastend) */ | |
801 | ||
802 | /* | |
803 | Mark hello option | |
804 | */ | |
805 | PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST); | |
806 | ||
807 | return 0; | |
808 | } |