blob: ed4dbba2e5bd7a92a79fa96cbc0117794b376ea9 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
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"
27
28#include "pimd.h"
Everton Marques7c5f5012009-11-19 17:00:23 -020029#include "pim_int.h"
Everton Marques871dbcf2009-08-11 15:43:05 -030030#include "pim_tlv.h"
31#include "pim_str.h"
32#include "pim_msg.h"
33
David Lamparterf8cfeb22012-02-16 04:31:08 +000034uint8_t *pim_tlv_append_uint16(uint8_t *buf,
35 const uint8_t *buf_pastend,
36 uint16_t option_type,
37 uint16_t option_value)
Everton Marques871dbcf2009-08-11 15:43:05 -030038{
39 uint16_t option_len = 2;
40
Donald Sharp6d853c42015-10-21 16:13:51 -040041 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
42 return NULL;
Everton Marques871dbcf2009-08-11 15:43:05 -030043
44 *(uint16_t *) buf = htons(option_type);
45 buf += 2;
46 *(uint16_t *) buf = htons(option_len);
47 buf += 2;
48 *(uint16_t *) buf = htons(option_value);
49 buf += option_len;
50
51 return buf;
52}
53
David Lamparterf8cfeb22012-02-16 04:31:08 +000054uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
55 const uint8_t *buf_pastend,
56 uint16_t option_type,
57 uint16_t option_value1,
58 uint16_t option_value2)
Everton Marques871dbcf2009-08-11 15:43:05 -030059{
60 uint16_t option_len = 4;
61
Donald Sharp6d853c42015-10-21 16:13:51 -040062 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
63 return NULL;
Everton Marques871dbcf2009-08-11 15:43:05 -030064
65 *(uint16_t *) buf = htons(option_type);
66 buf += 2;
67 *(uint16_t *) buf = htons(option_len);
68 buf += 2;
69 *(uint16_t *) buf = htons(option_value1);
70 buf += 2;
71 *(uint16_t *) buf = htons(option_value2);
72 buf += 2;
73
74 return buf;
75}
76
David Lamparterf8cfeb22012-02-16 04:31:08 +000077uint8_t *pim_tlv_append_uint32(uint8_t *buf,
78 const uint8_t *buf_pastend,
79 uint16_t option_type,
80 uint32_t option_value)
Everton Marques871dbcf2009-08-11 15:43:05 -030081{
82 uint16_t option_len = 4;
83
Donald Sharp6d853c42015-10-21 16:13:51 -040084 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend)
85 return NULL;
Everton Marques871dbcf2009-08-11 15:43:05 -030086
87 *(uint16_t *) buf = htons(option_type);
88 buf += 2;
89 *(uint16_t *) buf = htons(option_len);
90 buf += 2;
Everton Marques7c5f5012009-11-19 17:00:23 -020091 pim_write_uint32(buf, option_value);
Everton Marques871dbcf2009-08-11 15:43:05 -030092 buf += option_len;
93
94 return buf;
95}
96
97#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
98
David Lamparterf8cfeb22012-02-16 04:31:08 +000099uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
100 const uint8_t *buf_pastend,
101 struct list *ifconnected)
Everton Marques871dbcf2009-08-11 15:43:05 -0300102{
103 struct listnode *node;
104 uint16_t option_len = 0;
105
Everton Marques7c5f5012009-11-19 17:00:23 -0200106 uint8_t *curr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300107
108 node = listhead(ifconnected);
109
110 /* Empty address list ? */
111 if (!node) {
112 return buf;
113 }
114
115 /* Skip first address (primary) */
116 node = listnextnode(node);
117
118 /* Scan secondary address list */
119 curr = buf + 4; /* skip T and L */
120 for (; node; node = listnextnode(node)) {
121 struct connected *ifc = listgetdata(node);
122 struct prefix *p = ifc->address;
123
124 if (p->family != AF_INET)
125 continue;
126
Donald Sharp6d853c42015-10-21 16:13:51 -0400127 if ((curr + ucast_ipv4_encoding_len) > buf_pastend)
Everton Marques871dbcf2009-08-11 15:43:05 -0300128 return 0;
Everton Marques871dbcf2009-08-11 15:43:05 -0300129
130 /* Write encoded unicast IPv4 address */
131 *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
132 ++curr;
133 *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
134 ++curr;
Klemen Sladic3defeb32014-02-07 16:23:44 +1300135 memcpy(curr, &p->u.prefix4, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300136 curr += sizeof(struct in_addr);
137
138 option_len += ucast_ipv4_encoding_len;
139 }
140
141 if (PIM_DEBUG_PIM_TRACE) {
Donald Sharp6d853c42015-10-21 16:13:51 -0400142 zlog_debug("%s: number of encoded secondary unicast IPv4 addresses: %zu",
143 __PRETTY_FUNCTION__,
144 option_len / ucast_ipv4_encoding_len);
Everton Marques871dbcf2009-08-11 15:43:05 -0300145 }
146
147 if (option_len < 1) {
148 /* Empty secondary unicast IPv4 address list */
149 return buf;
150 }
151
152 /*
153 * Write T and L
154 */
155 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
156 *(uint16_t *) (buf + 2) = htons(option_len);
157
158 return curr;
159}
160
161static int check_tlv_length(const char *label, const char *tlv_name,
162 const char *ifname, struct in_addr src_addr,
163 int correct_len, int option_len)
164{
165 if (option_len != correct_len) {
166 char src_str[100];
167 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
168 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
169 label, tlv_name,
170 option_len, correct_len,
171 src_str, ifname);
172 return -1;
173 }
174
175 return 0;
176}
177
178static void check_tlv_redefinition_uint16(const char *label, const char *tlv_name,
179 const char *ifname, struct in_addr src_addr,
180 pim_hello_options options,
181 pim_hello_options opt_mask,
182 uint16_t new, uint16_t old)
183{
184 if (PIM_OPTION_IS_SET(options, opt_mask)) {
185 char src_str[100];
186 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
187 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
188 label, tlv_name,
189 new, old,
190 src_str, ifname);
191 }
192}
193
194static void check_tlv_redefinition_uint32(const char *label, const char *tlv_name,
195 const char *ifname, struct in_addr src_addr,
196 pim_hello_options options,
197 pim_hello_options opt_mask,
198 uint32_t new, uint32_t old)
199{
200 if (PIM_OPTION_IS_SET(options, opt_mask)) {
201 char src_str[100];
202 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
203 zlog_warn("%s: PIM hello TLV redefined %s=%u old=%u from %s on interface %s",
204 label, tlv_name,
205 new, old,
206 src_str, ifname);
207 }
208}
209
210static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
211 const char *ifname, struct in_addr src_addr,
212 pim_hello_options options,
213 pim_hello_options opt_mask,
214 uint32_t new, uint32_t old)
215{
216 if (PIM_OPTION_IS_SET(options, opt_mask)) {
217 char src_str[100];
218 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
219 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
220 label, tlv_name,
221 new, old,
222 src_str, ifname);
223 }
224}
225
226int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
227 pim_hello_options *hello_options,
228 uint16_t *hello_option_holdtime,
229 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000230 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300231{
232 const char *label = "holdtime";
233
234 if (check_tlv_length(__PRETTY_FUNCTION__, label,
235 ifname, src_addr,
236 sizeof(uint16_t), option_len)) {
237 return -1;
238 }
239
240 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
241 ifname, src_addr,
242 *hello_options, PIM_OPTION_MASK_HOLDTIME,
243 PIM_TLV_GET_HOLDTIME(tlv_curr),
244 *hello_option_holdtime);
245
246 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
247
248 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
249
250 return 0;
251}
252
253int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
254 pim_hello_options *hello_options,
255 uint16_t *hello_option_propagation_delay,
256 uint16_t *hello_option_override_interval,
257 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000258 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300259{
260 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
261 ifname, src_addr,
262 sizeof(uint32_t), option_len)) {
263 return -1;
264 }
265
266 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
267 ifname, src_addr,
268 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
269 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
270 *hello_option_propagation_delay);
271
272 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
273
274 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
275 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
276 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
277 }
278 else {
279 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
280 }
281 ++tlv_curr;
282 ++tlv_curr;
283 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
284
285 return 0;
286}
287
288int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
289 pim_hello_options *hello_options,
290 uint32_t *hello_option_dr_priority,
291 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000292 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300293{
294 const char *label = "dr_priority";
295
296 if (check_tlv_length(__PRETTY_FUNCTION__, label,
297 ifname, src_addr,
298 sizeof(uint32_t), option_len)) {
299 return -1;
300 }
301
302 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
303 ifname, src_addr,
304 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
305 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
306 *hello_option_dr_priority);
307
308 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
309
310 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
Everton Marques7c5f5012009-11-19 17:00:23 -0200311
Everton Marques871dbcf2009-08-11 15:43:05 -0300312 return 0;
313}
314
315int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
316 pim_hello_options *hello_options,
317 uint32_t *hello_option_generation_id,
318 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000319 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300320{
321 const char *label = "generation_id";
322
323 if (check_tlv_length(__PRETTY_FUNCTION__, label,
324 ifname, src_addr,
325 sizeof(uint32_t), option_len)) {
326 return -1;
327 }
328
329 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
330 ifname, src_addr,
331 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
332 PIM_TLV_GET_GENERATION_ID(tlv_curr),
333 *hello_option_generation_id);
334
335 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
336
337 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
338
339 return 0;
340}
341
342int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr,
343 struct prefix *p,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000344 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300345 int buf_size)
346{
347 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000348 const uint8_t *addr;
349 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300350 int family;
351 int type;
352
353 if (buf_size < ucast_encoding_min_len) {
354 char src_str[100];
355 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
356 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s",
357 __PRETTY_FUNCTION__,
358 buf_size, ucast_encoding_min_len,
359 src_str, ifname);
360 return -1;
361 }
362
363 addr = buf;
364 pastend = buf + buf_size;
365
David Lamparterf8cfeb22012-02-16 04:31:08 +0000366 family = *addr++;
367 type = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300368
369 switch (family) {
370 case PIM_MSG_ADDRESS_FAMILY_IPV4:
371 if (type) {
372 char src_str[100];
373 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
374 zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s",
375 __PRETTY_FUNCTION__,
376 type, src_str, ifname);
377 return -2;
378 }
379
380 if ((addr + sizeof(struct in_addr)) > pastend) {
381 char src_str[100];
382 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100383 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300384 __PRETTY_FUNCTION__,
385 pastend - addr, sizeof(struct in_addr),
386 src_str, ifname);
387 return -3;
388 }
389
390 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300391 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
392
Everton Marques871dbcf2009-08-11 15:43:05 -0300393 addr += sizeof(struct in_addr);
394
395 break;
396 default:
397 {
398 char src_str[100];
399 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
400 zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
401 __PRETTY_FUNCTION__,
402 family, src_str, ifname);
403 return -4;
404 }
405 }
406
407 return addr - buf;
408}
409
410int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
411 struct prefix *p,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000412 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300413 int buf_size)
414{
415 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000416 const uint8_t *addr;
417 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300418 int family;
419 int type;
420 int mask_len;
421
422 if (buf_size < grp_encoding_min_len) {
423 char src_str[100];
424 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
425 zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
426 __PRETTY_FUNCTION__,
427 buf_size, grp_encoding_min_len,
428 src_str, ifname);
429 return -1;
430 }
431
432 addr = buf;
433 pastend = buf + buf_size;
434
David Lamparterf8cfeb22012-02-16 04:31:08 +0000435 family = *addr++;
436 type = *addr++;
Everton Marquesd4595862014-02-13 19:50:30 -0200437 //++addr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300438 ++addr; /* skip b_reserved_z fields */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000439 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300440
441 switch (family) {
442 case PIM_MSG_ADDRESS_FAMILY_IPV4:
443 if (type) {
444 char src_str[100];
445 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
446 zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
447 __PRETTY_FUNCTION__,
448 type, src_str, ifname);
449 return -2;
450 }
451
452 if ((addr + sizeof(struct in_addr)) > pastend) {
453 char src_str[100];
454 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100455 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300456 __PRETTY_FUNCTION__,
457 pastend - addr, sizeof(struct in_addr),
458 src_str, ifname);
459 return -3;
460 }
461
462 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300463 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300464 p->prefixlen = mask_len;
465
466 addr += sizeof(struct in_addr);
467
468 break;
469 default:
470 {
471 char src_str[100];
472 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
473 zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
474 __PRETTY_FUNCTION__,
475 family, src_str, ifname);
476 return -4;
477 }
478 }
479
480 return addr - buf;
481}
482
483int pim_parse_addr_source(const char *ifname,
484 struct in_addr src_addr,
485 struct prefix *p,
486 uint8_t *flags,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000487 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300488 int buf_size)
489{
490 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000491 const uint8_t *addr;
492 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300493 int family;
494 int type;
495 int mask_len;
496
497 if (buf_size < src_encoding_min_len) {
498 char src_str[100];
499 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
500 zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
501 __PRETTY_FUNCTION__,
502 buf_size, src_encoding_min_len,
503 src_str, ifname);
504 return -1;
505 }
506
507 addr = buf;
508 pastend = buf + buf_size;
509
David Lamparterf8cfeb22012-02-16 04:31:08 +0000510 family = *addr++;
511 type = *addr++;
512 *flags = *addr++;
513 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300514
515 switch (family) {
516 case PIM_MSG_ADDRESS_FAMILY_IPV4:
517 if (type) {
518 char src_str[100];
519 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
Everton Marquesd4595862014-02-13 19:50:30 -0200520 zlog_warn("%s: unknown source address encoding type=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
Everton Marques871dbcf2009-08-11 15:43:05 -0300521 __PRETTY_FUNCTION__,
Everton Marquesd4595862014-02-13 19:50:30 -0200522 type, src_str, ifname,
523 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
Everton Marques871dbcf2009-08-11 15:43:05 -0300524 return -2;
525 }
526
527 if ((addr + sizeof(struct in_addr)) > pastend) {
528 char src_str[100];
529 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100530 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300531 __PRETTY_FUNCTION__,
532 pastend - addr, sizeof(struct in_addr),
533 src_str, ifname);
534 return -3;
535 }
536
537 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300538 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300539 p->prefixlen = mask_len;
540
Everton Marquesd12beab2009-08-12 10:52:22 -0300541 /*
542 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
543
544 Encoded-Source Address
545
546 The mask length MUST be equal to the mask length in bits for
547 the given Address Family and Encoding Type (32 for IPv4 native
548 and 128 for IPv6 native). A router SHOULD ignore any messages
549 received with any other mask length.
550 */
551 if (p->prefixlen != 32) {
552 char src_str[100];
553 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
554 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
555 __PRETTY_FUNCTION__, src_str, p->prefixlen);
556 return -4;
557 }
558
Everton Marques871dbcf2009-08-11 15:43:05 -0300559 addr += sizeof(struct in_addr);
560
561 break;
562 default:
563 {
564 char src_str[100];
565 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
Everton Marquesd4595862014-02-13 19:50:30 -0200566 zlog_warn("%s: unknown source address encoding family=%d from %s on %s: %02x%02x%02x%02x%02x%02x%02x%02x",
Everton Marques871dbcf2009-08-11 15:43:05 -0300567 __PRETTY_FUNCTION__,
Everton Marquesd4595862014-02-13 19:50:30 -0200568 family, src_str, ifname,
569 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
Everton Marquesd12beab2009-08-12 10:52:22 -0300570 return -5;
Everton Marques871dbcf2009-08-11 15:43:05 -0300571 }
572 }
573
574 return addr - buf;
575}
576
577#define FREE_ADDR_LIST(hello_option_addr_list) \
578{ \
579 if (hello_option_addr_list) { \
580 list_delete(hello_option_addr_list); \
581 hello_option_addr_list = 0; \
582 } \
583}
584
585int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
586 pim_hello_options *hello_options,
587 struct list **hello_option_addr_list,
588 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000589 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300590{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000591 const uint8_t *addr;
592 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300593
594 zassert(hello_option_addr_list);
595
596 /*
597 Scan addr list
598 */
599 addr = tlv_curr;
600 pastend = tlv_curr + option_len;
601 while (addr < pastend) {
602 struct prefix tmp;
603 int addr_offset;
604
605 /*
606 Parse ucast addr
607 */
608 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
609 addr, pastend - addr);
610 if (addr_offset < 1) {
611 char src_str[100];
612 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
613 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
614 __PRETTY_FUNCTION__,
615 src_str, ifname);
616 FREE_ADDR_LIST(*hello_option_addr_list);
617 return -1;
618 }
619 addr += addr_offset;
620
621 /*
622 Debug
623 */
624 if (PIM_DEBUG_PIM_TRACE) {
625 switch (tmp.family) {
626 case AF_INET:
627 {
628 char addr_str[100];
629 char src_str[100];
630 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
631 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
632 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
633 __PRETTY_FUNCTION__,
634 *hello_option_addr_list ?
635 ((int) listcount(*hello_option_addr_list)) : -1,
636 addr_str, src_str, ifname);
637 }
638 break;
639 default:
640 {
641 char src_str[100];
642 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
643 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
644 __PRETTY_FUNCTION__,
645 *hello_option_addr_list ?
646 ((int) listcount(*hello_option_addr_list)) : -1,
647 src_str, ifname);
648 }
649 }
650 }
651
652 /*
653 Exclude neighbor's primary address if incorrectly included in
654 the secondary address list
655 */
656 if (tmp.family == AF_INET) {
657 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
658 char src_str[100];
659 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
660 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
661 __PRETTY_FUNCTION__,
662 src_str, ifname);
663 continue;
664 }
665 }
666
667 /*
668 Allocate list if needed
669 */
670 if (!*hello_option_addr_list) {
671 *hello_option_addr_list = list_new();
672 if (!*hello_option_addr_list) {
673 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
674 __FILE__, __PRETTY_FUNCTION__);
675 return -2;
676 }
677 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
678 }
679
680 /*
681 Attach addr to list
682 */
683 {
684 struct prefix *p;
685 p = prefix_new();
686 if (!p) {
687 zlog_err("%s %s: failure: prefix_new()",
688 __FILE__, __PRETTY_FUNCTION__);
689 FREE_ADDR_LIST(*hello_option_addr_list);
690 return -3;
691 }
692 p->family = tmp.family;
693 p->u.prefix4 = tmp.u.prefix4;
694 listnode_add(*hello_option_addr_list, p);
695 }
696
697 } /* while (addr < pastend) */
698
699 /*
700 Mark hello option
701 */
702 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
703
704 return 0;
705}