blob: 4ce9a3d220ebe26ce72ba944bb8ec69088273913 [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;
151 *(struct in_addr *) curr = p->u.prefix4;
152 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 */
407 p->u.prefix4 = *(const struct in_addr *) addr;
408 addr += sizeof(struct in_addr);
409
410 break;
411 default:
412 {
413 char src_str[100];
414 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
415 zlog_warn("%s: unknown unicast address encoding family=%d from %s on %s",
416 __PRETTY_FUNCTION__,
417 family, src_str, ifname);
418 return -4;
419 }
420 }
421
422 return addr - buf;
423}
424
425int pim_parse_addr_group(const char *ifname, struct in_addr src_addr,
426 struct prefix *p,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000427 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300428 int buf_size)
429{
430 const int grp_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000431 const uint8_t *addr;
432 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300433 int family;
434 int type;
435 int mask_len;
436
437 if (buf_size < grp_encoding_min_len) {
438 char src_str[100];
439 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
440 zlog_warn("%s: group address encoding overflow: left=%d needed=%d from %s on %s",
441 __PRETTY_FUNCTION__,
442 buf_size, grp_encoding_min_len,
443 src_str, ifname);
444 return -1;
445 }
446
447 addr = buf;
448 pastend = buf + buf_size;
449
David Lamparterf8cfeb22012-02-16 04:31:08 +0000450 family = *addr++;
451 type = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300452 ++addr;
453 ++addr; /* skip b_reserved_z fields */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000454 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300455
456 switch (family) {
457 case PIM_MSG_ADDRESS_FAMILY_IPV4:
458 if (type) {
459 char src_str[100];
460 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
461 zlog_warn("%s: unknown group address encoding type=%d from %s on %s",
462 __PRETTY_FUNCTION__,
463 type, src_str, ifname);
464 return -2;
465 }
466
467 if ((addr + sizeof(struct in_addr)) > pastend) {
468 char src_str[100];
469 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100470 zlog_warn("%s: IPv4 group address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300471 __PRETTY_FUNCTION__,
472 pastend - addr, sizeof(struct in_addr),
473 src_str, ifname);
474 return -3;
475 }
476
477 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
478 p->u.prefix4 = *(const struct in_addr *) addr;
479 p->prefixlen = mask_len;
480
481 addr += sizeof(struct in_addr);
482
483 break;
484 default:
485 {
486 char src_str[100];
487 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
488 zlog_warn("%s: unknown group address encoding family=%d from %s on %s",
489 __PRETTY_FUNCTION__,
490 family, src_str, ifname);
491 return -4;
492 }
493 }
494
495 return addr - buf;
496}
497
498int pim_parse_addr_source(const char *ifname,
499 struct in_addr src_addr,
500 struct prefix *p,
501 uint8_t *flags,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000502 const uint8_t *buf,
Everton Marques871dbcf2009-08-11 15:43:05 -0300503 int buf_size)
504{
505 const int src_encoding_min_len = 4; /* 1 family + 1 type + 1 reserved + 1 addr */
David Lamparterf8cfeb22012-02-16 04:31:08 +0000506 const uint8_t *addr;
507 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300508 int family;
509 int type;
510 int mask_len;
511
512 if (buf_size < src_encoding_min_len) {
513 char src_str[100];
514 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
515 zlog_warn("%s: source address encoding overflow: left=%d needed=%d from %s on %s",
516 __PRETTY_FUNCTION__,
517 buf_size, src_encoding_min_len,
518 src_str, ifname);
519 return -1;
520 }
521
522 addr = buf;
523 pastend = buf + buf_size;
524
David Lamparterf8cfeb22012-02-16 04:31:08 +0000525 family = *addr++;
526 type = *addr++;
527 *flags = *addr++;
528 mask_len = *addr++;
Everton Marques871dbcf2009-08-11 15:43:05 -0300529
530 switch (family) {
531 case PIM_MSG_ADDRESS_FAMILY_IPV4:
532 if (type) {
533 char src_str[100];
534 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
535 zlog_warn("%s: unknown source address encoding type=%d from %s on %s",
536 __PRETTY_FUNCTION__,
537 type, src_str, ifname);
538 return -2;
539 }
540
541 if ((addr + sizeof(struct in_addr)) > pastend) {
542 char src_str[100];
543 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100544 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300545 __PRETTY_FUNCTION__,
546 pastend - addr, sizeof(struct in_addr),
547 src_str, ifname);
548 return -3;
549 }
550
551 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
552 p->u.prefix4 = *(const struct in_addr *) addr;
553 p->prefixlen = mask_len;
554
Everton Marquesd12beab2009-08-12 10:52:22 -0300555 /*
556 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
557
558 Encoded-Source Address
559
560 The mask length MUST be equal to the mask length in bits for
561 the given Address Family and Encoding Type (32 for IPv4 native
562 and 128 for IPv6 native). A router SHOULD ignore any messages
563 received with any other mask length.
564 */
565 if (p->prefixlen != 32) {
566 char src_str[100];
567 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
568 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
569 __PRETTY_FUNCTION__, src_str, p->prefixlen);
570 return -4;
571 }
572
Everton Marques871dbcf2009-08-11 15:43:05 -0300573 addr += sizeof(struct in_addr);
574
575 break;
576 default:
577 {
578 char src_str[100];
579 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
580 zlog_warn("%s: unknown source address encoding family=%d from %s on %s",
581 __PRETTY_FUNCTION__,
582 family, src_str, ifname);
Everton Marquesd12beab2009-08-12 10:52:22 -0300583 return -5;
Everton Marques871dbcf2009-08-11 15:43:05 -0300584 }
585 }
586
587 return addr - buf;
588}
589
590#define FREE_ADDR_LIST(hello_option_addr_list) \
591{ \
592 if (hello_option_addr_list) { \
593 list_delete(hello_option_addr_list); \
594 hello_option_addr_list = 0; \
595 } \
596}
597
598int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
599 pim_hello_options *hello_options,
600 struct list **hello_option_addr_list,
601 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000602 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300603{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000604 const uint8_t *addr;
605 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300606
607 zassert(hello_option_addr_list);
608
609 /*
610 Scan addr list
611 */
612 addr = tlv_curr;
613 pastend = tlv_curr + option_len;
614 while (addr < pastend) {
615 struct prefix tmp;
616 int addr_offset;
617
618 /*
619 Parse ucast addr
620 */
621 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
622 addr, pastend - addr);
623 if (addr_offset < 1) {
624 char src_str[100];
625 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
626 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
627 __PRETTY_FUNCTION__,
628 src_str, ifname);
629 FREE_ADDR_LIST(*hello_option_addr_list);
630 return -1;
631 }
632 addr += addr_offset;
633
634 /*
635 Debug
636 */
637 if (PIM_DEBUG_PIM_TRACE) {
638 switch (tmp.family) {
639 case AF_INET:
640 {
641 char addr_str[100];
642 char src_str[100];
643 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
644 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
645 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
646 __PRETTY_FUNCTION__,
647 *hello_option_addr_list ?
648 ((int) listcount(*hello_option_addr_list)) : -1,
649 addr_str, src_str, ifname);
650 }
651 break;
652 default:
653 {
654 char src_str[100];
655 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
656 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
657 __PRETTY_FUNCTION__,
658 *hello_option_addr_list ?
659 ((int) listcount(*hello_option_addr_list)) : -1,
660 src_str, ifname);
661 }
662 }
663 }
664
665 /*
666 Exclude neighbor's primary address if incorrectly included in
667 the secondary address list
668 */
669 if (tmp.family == AF_INET) {
670 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
671 char src_str[100];
672 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
673 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
674 __PRETTY_FUNCTION__,
675 src_str, ifname);
676 continue;
677 }
678 }
679
680 /*
681 Allocate list if needed
682 */
683 if (!*hello_option_addr_list) {
684 *hello_option_addr_list = list_new();
685 if (!*hello_option_addr_list) {
686 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
687 __FILE__, __PRETTY_FUNCTION__);
688 return -2;
689 }
690 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
691 }
692
693 /*
694 Attach addr to list
695 */
696 {
697 struct prefix *p;
698 p = prefix_new();
699 if (!p) {
700 zlog_err("%s %s: failure: prefix_new()",
701 __FILE__, __PRETTY_FUNCTION__);
702 FREE_ADDR_LIST(*hello_option_addr_list);
703 return -3;
704 }
705 p->family = tmp.family;
706 p->u.prefix4 = tmp.u.prefix4;
707 listnode_add(*hello_option_addr_list, p);
708 }
709
710 } /* while (addr < pastend) */
711
712 /*
713 Mark hello option
714 */
715 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
716
717 return 0;
718}