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