blob: 95ee5ab0ece177548a8ed9f2d64a857346857753 [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 Marquesd4595862014-02-13 19:50:30 -0200453 //++addr;
Everton Marques871dbcf2009-08-11 15:43:05 -0300454 ++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));
Everton Marquesd4595862014-02-13 19:50:30 -0200536 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 -0300537 __PRETTY_FUNCTION__,
Everton Marquesd4595862014-02-13 19:50:30 -0200538 type, src_str, ifname,
539 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
Everton Marques871dbcf2009-08-11 15:43:05 -0300540 return -2;
541 }
542
543 if ((addr + sizeof(struct in_addr)) > pastend) {
544 char src_str[100];
545 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
David Lamparter5c697982012-02-16 04:47:56 +0100546 zlog_warn("%s: IPv4 source address overflow: left=%zd needed=%zu from %s on %s",
Everton Marques871dbcf2009-08-11 15:43:05 -0300547 __PRETTY_FUNCTION__,
548 pastend - addr, sizeof(struct in_addr),
549 src_str, ifname);
550 return -3;
551 }
552
553 p->family = AF_INET; /* notice: AF_INET != PIM_MSG_ADDRESS_FAMILY_IPV4 */
Klemen Sladic3defeb32014-02-07 16:23:44 +1300554 memcpy(&p->u.prefix4, addr, sizeof(struct in_addr));
Everton Marques871dbcf2009-08-11 15:43:05 -0300555 p->prefixlen = mask_len;
556
Everton Marquesd12beab2009-08-12 10:52:22 -0300557 /*
558 RFC 4601: 4.9.1 Encoded Source and Group Address Formats
559
560 Encoded-Source Address
561
562 The mask length MUST be equal to the mask length in bits for
563 the given Address Family and Encoding Type (32 for IPv4 native
564 and 128 for IPv6 native). A router SHOULD ignore any messages
565 received with any other mask length.
566 */
567 if (p->prefixlen != 32) {
568 char src_str[100];
569 pim_inet4_dump("<src?>", p->u.prefix4, src_str, sizeof(src_str));
570 zlog_warn("%s: IPv4 bad source address mask: %s/%d",
571 __PRETTY_FUNCTION__, src_str, p->prefixlen);
572 return -4;
573 }
574
Everton Marques871dbcf2009-08-11 15:43:05 -0300575 addr += sizeof(struct in_addr);
576
577 break;
578 default:
579 {
580 char src_str[100];
581 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
Everton Marquesd4595862014-02-13 19:50:30 -0200582 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 -0300583 __PRETTY_FUNCTION__,
Everton Marquesd4595862014-02-13 19:50:30 -0200584 family, src_str, ifname,
585 buf[0], buf[1], buf[2], buf[3], buf[4], buf[5], buf[6], buf[7]);
Everton Marquesd12beab2009-08-12 10:52:22 -0300586 return -5;
Everton Marques871dbcf2009-08-11 15:43:05 -0300587 }
588 }
589
590 return addr - buf;
591}
592
593#define FREE_ADDR_LIST(hello_option_addr_list) \
594{ \
595 if (hello_option_addr_list) { \
596 list_delete(hello_option_addr_list); \
597 hello_option_addr_list = 0; \
598 } \
599}
600
601int pim_tlv_parse_addr_list(const char *ifname, struct in_addr src_addr,
602 pim_hello_options *hello_options,
603 struct list **hello_option_addr_list,
604 uint16_t option_len,
David Lamparterf8cfeb22012-02-16 04:31:08 +0000605 const uint8_t *tlv_curr)
Everton Marques871dbcf2009-08-11 15:43:05 -0300606{
David Lamparterf8cfeb22012-02-16 04:31:08 +0000607 const uint8_t *addr;
608 const uint8_t *pastend;
Everton Marques871dbcf2009-08-11 15:43:05 -0300609
610 zassert(hello_option_addr_list);
611
612 /*
613 Scan addr list
614 */
615 addr = tlv_curr;
616 pastend = tlv_curr + option_len;
617 while (addr < pastend) {
618 struct prefix tmp;
619 int addr_offset;
620
621 /*
622 Parse ucast addr
623 */
624 addr_offset = pim_parse_addr_ucast(ifname, src_addr, &tmp,
625 addr, pastend - addr);
626 if (addr_offset < 1) {
627 char src_str[100];
628 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
629 zlog_warn("%s: pim_parse_addr_ucast() failure: from %s on %s",
630 __PRETTY_FUNCTION__,
631 src_str, ifname);
632 FREE_ADDR_LIST(*hello_option_addr_list);
633 return -1;
634 }
635 addr += addr_offset;
636
637 /*
638 Debug
639 */
640 if (PIM_DEBUG_PIM_TRACE) {
641 switch (tmp.family) {
642 case AF_INET:
643 {
644 char addr_str[100];
645 char src_str[100];
646 pim_inet4_dump("<addr?>", tmp.u.prefix4, addr_str, sizeof(addr_str));
647 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
648 zlog_debug("%s: PIM hello TLV option: list_old_size=%d IPv4 address %s from %s on %s",
649 __PRETTY_FUNCTION__,
650 *hello_option_addr_list ?
651 ((int) listcount(*hello_option_addr_list)) : -1,
652 addr_str, src_str, ifname);
653 }
654 break;
655 default:
656 {
657 char src_str[100];
658 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
659 zlog_debug("%s: PIM hello TLV option: list_old_size=%d UNKNOWN address family from %s on %s",
660 __PRETTY_FUNCTION__,
661 *hello_option_addr_list ?
662 ((int) listcount(*hello_option_addr_list)) : -1,
663 src_str, ifname);
664 }
665 }
666 }
667
668 /*
669 Exclude neighbor's primary address if incorrectly included in
670 the secondary address list
671 */
672 if (tmp.family == AF_INET) {
673 if (tmp.u.prefix4.s_addr == src_addr.s_addr) {
674 char src_str[100];
675 pim_inet4_dump("<src?>", src_addr, src_str, sizeof(src_str));
676 zlog_warn("%s: ignoring primary address in secondary list from %s on %s",
677 __PRETTY_FUNCTION__,
678 src_str, ifname);
679 continue;
680 }
681 }
682
683 /*
684 Allocate list if needed
685 */
686 if (!*hello_option_addr_list) {
687 *hello_option_addr_list = list_new();
688 if (!*hello_option_addr_list) {
689 zlog_err("%s %s: failure: hello_option_addr_list=list_new()",
690 __FILE__, __PRETTY_FUNCTION__);
691 return -2;
692 }
693 (*hello_option_addr_list)->del = (void (*)(void *)) prefix_free;
694 }
695
696 /*
697 Attach addr to list
698 */
699 {
700 struct prefix *p;
701 p = prefix_new();
702 if (!p) {
703 zlog_err("%s %s: failure: prefix_new()",
704 __FILE__, __PRETTY_FUNCTION__);
705 FREE_ADDR_LIST(*hello_option_addr_list);
706 return -3;
707 }
708 p->family = tmp.family;
709 p->u.prefix4 = tmp.u.prefix4;
710 listnode_add(*hello_option_addr_list, p);
711 }
712
713 } /* while (addr < pastend) */
714
715 /*
716 Mark hello option
717 */
718 PIM_OPTION_SET(*hello_options, PIM_OPTION_MASK_ADDRESS_LIST);
719
720 return 0;
721}