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