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