blob: 962c2b87c029421e2d3a4b3cfb0289512f3f1181 [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
41 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
David Lamparter5c697982012-02-16 04:47:56 +010042 zlog_warn("%s: buffer overflow: left=%zd needed=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -030043 __PRETTY_FUNCTION__,
44 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
45 return 0;
46 }
47
48 *(uint16_t *) buf = htons(option_type);
49 buf += 2;
50 *(uint16_t *) buf = htons(option_len);
51 buf += 2;
52 *(uint16_t *) buf = htons(option_value);
53 buf += option_len;
54
55 return buf;
56}
57
David Lamparterf8cfeb22012-02-16 04:31:08 +000058uint8_t *pim_tlv_append_2uint16(uint8_t *buf,
59 const uint8_t *buf_pastend,
60 uint16_t option_type,
61 uint16_t option_value1,
62 uint16_t option_value2)
Everton Marques871dbcf2009-08-11 15:43:05 -030063{
64 uint16_t option_len = 4;
65
66 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
David Lamparter5c697982012-02-16 04:47:56 +010067 zlog_warn("%s: buffer overflow: left=%zd needed=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -030068 __PRETTY_FUNCTION__,
69 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
70 return 0;
71 }
72
73 *(uint16_t *) buf = htons(option_type);
74 buf += 2;
75 *(uint16_t *) buf = htons(option_len);
76 buf += 2;
77 *(uint16_t *) buf = htons(option_value1);
78 buf += 2;
79 *(uint16_t *) buf = htons(option_value2);
80 buf += 2;
81
82 return buf;
83}
84
David Lamparterf8cfeb22012-02-16 04:31:08 +000085uint8_t *pim_tlv_append_uint32(uint8_t *buf,
86 const uint8_t *buf_pastend,
87 uint16_t option_type,
88 uint32_t option_value)
Everton Marques871dbcf2009-08-11 15:43:05 -030089{
90 uint16_t option_len = 4;
91
92 if ((buf + PIM_TLV_OPTION_SIZE(option_len)) > buf_pastend) {
David Lamparter5c697982012-02-16 04:47:56 +010093 zlog_warn("%s: buffer overflow: left=%zd needed=%d",
Everton Marques871dbcf2009-08-11 15:43:05 -030094 __PRETTY_FUNCTION__,
95 buf_pastend - buf, PIM_TLV_OPTION_SIZE(option_len));
96 return 0;
97 }
98
99 *(uint16_t *) buf = htons(option_type);
100 buf += 2;
101 *(uint16_t *) buf = htons(option_len);
102 buf += 2;
Everton Marques7c5f5012009-11-19 17:00:23 -0200103 pim_write_uint32(buf, option_value);
Everton Marques871dbcf2009-08-11 15:43:05 -0300104 buf += option_len;
105
106 return buf;
107}
108
109#define ucast_ipv4_encoding_len (2 + sizeof(struct in_addr))
110
David Lamparterf8cfeb22012-02-16 04:31:08 +0000111uint8_t *pim_tlv_append_addrlist_ucast(uint8_t *buf,
112 const uint8_t *buf_pastend,
113 struct list *ifconnected)
Everton Marques871dbcf2009-08-11 15:43:05 -0300114{
115 struct listnode *node;
116 uint16_t option_len = 0;
117
Everton Marques7c5f5012009-11-19 17:00:23 -0200118 uint8_t *curr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300119
120 node = listhead(ifconnected);
121
122 /* Empty address list ? */
123 if (!node) {
124 return buf;
125 }
126
127 /* Skip first address (primary) */
128 node = listnextnode(node);
129
130 /* Scan secondary address list */
131 curr = buf + 4; /* skip T and L */
132 for (; node; node = listnextnode(node)) {
133 struct connected *ifc = listgetdata(node);
134 struct prefix *p = ifc->address;
135
136 if (p->family != AF_INET)
137 continue;
138
139 if ((curr + ucast_ipv4_encoding_len) > buf_pastend) {
David Lamparter5c697982012-02-16 04:47:56 +0100140 zlog_warn("%s: buffer overflow: left=%zd needed=%zu",
Everton Marques871dbcf2009-08-11 15:43:05 -0300141 __PRETTY_FUNCTION__,
142 buf_pastend - curr, ucast_ipv4_encoding_len);
143 return 0;
144 }
145
146 /* Write encoded unicast IPv4 address */
147 *(uint8_t *) curr = PIM_MSG_ADDRESS_FAMILY_IPV4; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
148 ++curr;
149 *(uint8_t *) curr = 0; /* ucast IPv4 native encoding type (RFC 4601: 4.9.1) */
150 ++curr;
Klemen Sladic3defeb32014-02-07 16:23:44 +1300151 memcpy(curr, &p->u.prefix4, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300152 curr += sizeof(struct in_addr);
153
154 option_len += ucast_ipv4_encoding_len;
155 }
156
157 if (PIM_DEBUG_PIM_TRACE) {
David Lamparter5c697982012-02-16 04:47:56 +0100158 zlog_warn("%s: number of encoded secondary unicast IPv4 addresses: %zu",
Everton Marques871dbcf2009-08-11 15:43:05 -0300159 __PRETTY_FUNCTION__,
160 option_len / ucast_ipv4_encoding_len);
161 }
162
163 if (option_len < 1) {
164 /* Empty secondary unicast IPv4 address list */
165 return buf;
166 }
167
168 /*
169 * Write T and L
170 */
171 *(uint16_t *) buf = htons(PIM_MSG_OPTION_TYPE_ADDRESS_LIST);
172 *(uint16_t *) (buf + 2) = htons(option_len);
173
174 return curr;
175}
176
177static int check_tlv_length(const char *label, const char *tlv_name,
178 const char *ifname, struct in_addr src_addr,
179 int correct_len, int option_len)
180{
181 if (option_len != correct_len) {
182 char src_str[100];
183 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
184 zlog_warn("%s: PIM hello %s TLV with incorrect value size=%d correct=%d from %s on interface %s",
185 label, tlv_name,
186 option_len, correct_len,
187 src_str, ifname);
188 return -1;
189 }
190
191 return 0;
192}
193
194static void check_tlv_redefinition_uint16(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 uint16_t new, uint16_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(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=%u old=%u from %s on interface %s",
220 label, tlv_name,
221 new, old,
222 src_str, ifname);
223 }
224}
225
226static void check_tlv_redefinition_uint32_hex(const char *label, const char *tlv_name,
227 const char *ifname, struct in_addr src_addr,
228 pim_hello_options options,
229 pim_hello_options opt_mask,
230 uint32_t new, uint32_t old)
231{
232 if (PIM_OPTION_IS_SET(options, opt_mask)) {
233 char src_str[100];
234 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
235 zlog_warn("%s: PIM hello TLV redefined %s=%08x old=%08x from %s on interface %s",
236 label, tlv_name,
237 new, old,
238 src_str, ifname);
239 }
240}
241
242int pim_tlv_parse_holdtime(const char *ifname, struct in_addr src_addr,
243 pim_hello_options *hello_options,
244 uint16_t *hello_option_holdtime,
245 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000246 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300247{
248 const char *label = "holdtime";
249
250 if (check_tlv_length(__PRETTY_FUNCTION__, label,
251 ifname, src_addr,
252 sizeof(uint16_t), option_len)) {
253 return -1;
254 }
255
256 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, label,
257 ifname, src_addr,
258 *hello_options, PIM_OPTION_MASK_HOLDTIME,
259 PIM_TLV_GET_HOLDTIME(tlv_curr),
260 *hello_option_holdtime);
261
262 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_HOLDTIME);
263
264 *hello_option_holdtime = PIM_TLV_GET_HOLDTIME(tlv_curr);
265
266 return 0;
267}
268
269int pim_tlv_parse_lan_prune_delay(const char *ifname, struct in_addr src_addr,
270 pim_hello_options *hello_options,
271 uint16_t *hello_option_propagation_delay,
272 uint16_t *hello_option_override_interval,
273 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000274 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300275{
276 if (check_tlv_length(__PRETTY_FUNCTION__, "lan_prune_delay",
277 ifname, src_addr,
278 sizeof(uint32_t), option_len)) {
279 return -1;
280 }
281
282 check_tlv_redefinition_uint16(__PRETTY_FUNCTION__, "propagation_delay",
283 ifname, src_addr,
284 *hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY,
285 PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr),
286 *hello_option_propagation_delay);
287
288 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
289
290 *hello_option_propagation_delay = PIM_TLV_GET_PROPAGATION_DELAY(tlv_curr);
291 if (PIM_TLV_GET_CAN_DISABLE_JOIN_SUPPRESSION(tlv_curr)) {
292 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
293 }
294 else {
295 PIM_OPTION_UNSET(*hello_options, PIM_OPTION_MASK_CAN_DISABLE_JOIN_SUPPRESSION);
296 }
297 ++tlv_curr;
298 ++tlv_curr;
299 *hello_option_override_interval = PIM_TLV_GET_OVERRIDE_INTERVAL(tlv_curr);
300
301 return 0;
302}
303
304int pim_tlv_parse_dr_priority(const char *ifname, struct in_addr src_addr,
305 pim_hello_options *hello_options,
306 uint32_t *hello_option_dr_priority,
307 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000308 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300309{
310 const char *label = "dr_priority";
311
312 if (check_tlv_length(__PRETTY_FUNCTION__, label,
313 ifname, src_addr,
314 sizeof(uint32_t), option_len)) {
315 return -1;
316 }
317
318 check_tlv_redefinition_uint32(__PRETTY_FUNCTION__, label,
319 ifname, src_addr,
320 *hello_options, PIM_OPTION_MASK_DR_PRIORITY,
321 PIM_TLV_GET_DR_PRIORITY(tlv_curr),
322 *hello_option_dr_priority);
323
324 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_DR_PRIORITY);
325
326 *hello_option_dr_priority = PIM_TLV_GET_DR_PRIORITY(tlv_curr);
Everton Marques7c5f5012009-11-19 17:00:23 -0200327
Everton Marques871dbcf2009-08-11 15:43:05 -0300328 return 0;
329}
330
331int pim_tlv_parse_generation_id(const char *ifname, struct in_addr src_addr,
332 pim_hello_options *hello_options,
333 uint32_t *hello_option_generation_id,
334 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000335 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300336{
337 const char *label = "generation_id";
338
339 if (check_tlv_length(__PRETTY_FUNCTION__, label,
340 ifname, src_addr,
341 sizeof(uint32_t), option_len)) {
342 return -1;
343 }
344
345 check_tlv_redefinition_uint32_hex(__PRETTY_FUNCTION__, label,
346 ifname, src_addr,
347 *hello_options, PIM_OPTION_MASK_GENERATION_ID,
348 PIM_TLV_GET_GENERATION_ID(tlv_curr),
349 *hello_option_generation_id);
350
351 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_GENERATION_ID);
352
353 *hello_option_generation_id = PIM_TLV_GET_GENERATION_ID(tlv_curr);
354
355 return 0;
356}
357
358int pim_parse_addr_ucast(const char *ifname, struct in_addr src_addr,
359 struct prefix *p,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000360 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300361 int buf_size)
362{
363 const int ucast_encoding_min_len = 3; /* 1 family + 1 type + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000364 const uint8_t *addr;
365 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300366 int family;
367 int type;
368
369 if (buf_size < ucast_encoding_min_len) {
370 char src_str[100];
371 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
372 zlog_warn("%s: unicast address encoding overflow: left=%d needed=%d from %s on %s",
373 __PRETTY_FUNCTION__,
374 buf_size, ucast_encoding_min_len,
375 src_str, ifname);
376 return -1;
377 }
378
379 addr = buf;
380 pastend = buf + buf_size;
381
David Lamparterf8cfeb22012-02-16 04:31:08 +0000382 family = *addr++;
383 type = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300384
385 switch (family) {
386 case PIM_MSG_ADDRESS_FAMILY_IPV4:
387 if (type) {
388 char src_str[100];
389 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
390 zlog_warn("%s: unknown unicast address encoding type=%d from %s on %s",
391 __PRETTY_FUNCTION__,
392 type, src_str, ifname);
393 return -2;
394 }
395
396 if ((addr + sizeof(struct in_addr)) > pastend) {
397 char src_str[100];
398 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100399 zlog_warn("%s: IPv4 unicast address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300400 __PRETTY_FUNCTION__,
401 pastend - addr, sizeof(struct in_addr),
402 src_str, ifname);
403 return -3;
404 }
405
406 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300407 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
408
Everton Marques871dbcf2009-08-11 15:43:05 -0300409 addr += sizeof(struct in_addr);
410
411 break;
412 default:
413 {
414 char src_str[100];
415 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
416 zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
417 __PRETTY_FUNCTION__,
418 family, src_str, ifname);
419 return -4;
420 }
421 }
422
423 return addr - buf;
424}
425
426int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
427 struct prefix *p,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000428 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300429 int buf_size)
430{
431 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000432 const uint8_t *addr;
433 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300434 int family;
435 int type;
436 int mask_len;
437
438 if (buf_size < grp_encoding_min_len) {
439 char src_str[100];
440 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
441 zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
442 __PRETTY_FUNCTION__,
443 buf_size, grp_encoding_min_len,
444 src_str, ifname);
445 return -1;
446 }
447
448 addr = buf;
449 pastend = buf + buf_size;
450
David Lamparterf8cfeb22012-02-16 04:31:08 +0000451 family = *addr++;
452 type = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300453 ++addr;
454 ++addr; /* skip b_reserved_z fields */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000455 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300456
457 switch (family) {
458 case PIM_MSG_ADDRESS_FAMILY_IPV4:
459 if (type) {
460 char src_str[100];
461 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
462 zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
463 __PRETTY_FUNCTION__,
464 type, src_str, ifname);
465 return -2;
466 }
467
468 if ((addr + sizeof(struct in_addr)) > pastend) {
469 char src_str[100];
470 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100471 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300472 __PRETTY_FUNCTION__,
473 pastend - addr, sizeof(struct in_addr),
474 src_str, ifname);
475 return -3;
476 }
477
478 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300479 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300480 p->prefixlen = mask_len;
481
482 addr += sizeof(struct in_addr);
483
484 break;
485 default:
486 {
487 char src_str[100];
488 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
489 zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
490 __PRETTY_FUNCTION__,
491 family, src_str, ifname);
492 return -4;
493 }
494 }
495
496 return addr - buf;
497}
498
499int pim_parse_addr_source(const char *ifname,
500 struct in_addr src_addr,
501 struct prefix *p,
502 uint8_t *flags,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000503 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300504 int buf_size)
505{
506 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000507 const uint8_t *addr;
508 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300509 int family;
510 int type;
511 int mask_len;
512
513 if (buf_size < src_encoding_min_len) {
514 char src_str[100];
515 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
516 zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
517 __PRETTY_FUNCTION__,
518 buf_size, src_encoding_min_len,
519 src_str, ifname);
520 return -1;
521 }
522
523 addr = buf;
524 pastend = buf + buf_size;
525
David Lamparterf8cfeb22012-02-16 04:31:08 +0000526 family = *addr++;
527 type = *addr++;
528 *flags = *addr++;
529 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300530
531 switch (family) {
532 case PIM_MSG_ADDRESS_FAMILY_IPV4:
533 if (type) {
534 char src_str[100];
535 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
536 zlog_warn("%s: unknown source address encoding type=%d from %s on %s",
537 __PRETTY_FUNCTION__,
538 type, src_str, ifname);
539 return -2;
540 }
541
542 if ((addr + sizeof(struct in_addr)) > pastend) {
543 char src_str[100];
544 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100545 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300546 __PRETTY_FUNCTION__,
547 pastend - addr, sizeof(struct in_addr),
548 src_str, ifname);
549 return -3;
550 }
551
552 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300553 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300554 p->prefixlen = mask_len;
555
Everton Marquesd12beab2009-08-12 10:52:22 -0300556 /*
557 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
558
559 Encoded-Source Address
560
561 The mask length MUST be equal to the mask length in bits for
562 the given Address Family and Encoding Type (32 for IPv4 native
563 and 128 for IPv6 native). A router SHOULD ignore any messages
564 received with any other mask length.
565 */
566 if (p->prefixlen != 32) {
567 char src_str[100];
568 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
569 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
570 __PRETTY_FUNCTION__, src_str, p->prefixlen);
571 return -4;
572 }
573
Everton Marques871dbcf2009-08-11 15:43:05 -0300574 addr += sizeof(struct in_addr);
575
576 break;
577 default:
578 {
579 char src_str[100];
580 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
581 zlog_warn("%s: unknown source address encoding family=%d from %s on %s",
582 __PRETTY_FUNCTION__,
583 family, src_str, ifname);
Everton Marquesd12beab2009-08-12 10:52:22 -0300584 return -5;
Everton Marques871dbcf2009-08-11 15:43:05 -0300585 }
586 }
587
588 return addr - buf;
589}
590
591#define FREE_ADDR_LIST(hello_option_addr_list) \
592{ \
593 if (hello_option_addr_list) { \
594 list_delete(hello_option_addr_list); \
595 hello_option_addr_list = 0; \
596 } \
597}
598
599int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
600 pim_hello_options *hello_options,
601 struct list **hello_option_addr_list,
602 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000603 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300604{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000605 const uint8_t *addr;
606 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300607
608 zassert(hello_option_addr_list);
609
610 /*
611 Scan addr list
612 */
613 addr = tlv_curr;
614 pastend = tlv_curr + option_len;
615 while (addr < pastend) {
616 struct prefix tmp;
617 int addr_offset;
618
619 /*
620 Parse ucast addr
621 */
622 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
623 addr, pastend - addr);
624 if (addr_offset < 1) {
625 char src_str[100];
626 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
627 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
628 __PRETTY_FUNCTION__,
629 src_str, ifname);
630 FREE_ADDR_LIST(*hello_option_addr_list);
631 return -1;
632 }
633 addr += addr_offset;
634
635 /*
636 Debug
637 */
638 if (PIM_DEBUG_PIM_TRACE) {
639 switch (tmp.family) {
640 case AF_INET:
641 {
642 char addr_str[100];
643 char src_str[100];
644 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
645 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
646 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
647 __PRETTY_FUNCTION__,
648 *hello_option_addr_list ?
649 ((int) listcount(*hello_option_addr_list)) : -1,
650 addr_str, src_str, ifname);
651 }
652 break;
653 default:
654 {
655 char src_str[100];
656 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
657 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
658 __PRETTY_FUNCTION__,
659 *hello_option_addr_list ?
660 ((int) listcount(*hello_option_addr_list)) : -1,
661 src_str, ifname);
662 }
663 }
664 }
665
666 /*
667 Exclude neighbor's primary address if incorrectly included in
668 the secondary address list
669 */
670 if (tmp.family == AF_INET) {
671 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
672 char src_str[100];
673 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
674 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
675 __PRETTY_FUNCTION__,
676 src_str, ifname);
677 continue;
678 }
679 }
680
681 /*
682 Allocate list if needed
683 */
684 if (!*hello_option_addr_list) {
685 *hello_option_addr_list = list_new();
686 if (!*hello_option_addr_list) {
687 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
688 __FILE__, __PRETTY_FUNCTION__);
689 return -2;
690 }
691 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
692 }
693
694 /*
695 Attach addr to list
696 */
697 {
698 struct prefix *p;
699 p = prefix_new();
700 if (!p) {
701 zlog_err("%s %s: failure: prefix_new()",
702 __FILE__, __PRETTY_FUNCTION__);
703 FREE_ADDR_LIST(*hello_option_addr_list);
704 return -3;
705 }
706 p->family = tmp.family;
707 p->u.prefix4 = tmp.u.prefix4;
708 listnode_add(*hello_option_addr_list, p);
709 }
710
711 } /* while (addr < pastend) */
712
713 /*
714 Mark hello option
715 */
716 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
717
718 return 0;
719}