]> git.proxmox.com Git - mirror_frr.git/blob - eigrpd/eigrp_hello.c
Merge pull request #12805 from karlquan/kquan_self_orig
[mirror_frr.git] / eigrpd / eigrp_hello.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * EIGRP Sending and Receiving EIGRP Hello Packets.
4 * Copyright (C) 2013-2016
5 * Authors:
6 * Donnie Savage
7 * Jan Janovic
8 * Matej Perina
9 * Peter Orsag
10 * Peter Paluch
11 * Frantisek Gazo
12 * Tomas Hvorkovy
13 * Martin Kontsek
14 * Lukas Koribsky
15 */
16
17 #include <zebra.h>
18
19 #include "thread.h"
20 #include "memory.h"
21 #include "linklist.h"
22 #include "prefix.h"
23 #include "if.h"
24 #include "table.h"
25 #include "sockunion.h"
26 #include "stream.h"
27 #include "log.h"
28 #include "sockopt.h"
29 #include "checksum.h"
30 #include "vty.h"
31 #include "md5.h"
32
33 #include "eigrpd/eigrp_structs.h"
34 #include "eigrpd/eigrpd.h"
35 #include "eigrpd/eigrp_interface.h"
36 #include "eigrpd/eigrp_neighbor.h"
37 #include "eigrpd/eigrp_packet.h"
38 #include "eigrpd/eigrp_zebra.h"
39 #include "eigrpd/eigrp_vty.h"
40 #include "eigrpd/eigrp_dump.h"
41 #include "eigrpd/eigrp_macros.h"
42 #include "eigrpd/eigrp_errors.h"
43
44 /* Packet Type String. */
45 static const struct message eigrp_general_tlv_type_str[] = {
46 {EIGRP_TLV_PARAMETER, "PARAMETER"},
47 {EIGRP_TLV_AUTH, "AUTH"},
48 {EIGRP_TLV_SEQ, "SEQ"},
49 {EIGRP_TLV_SW_VERSION, "SW_VERSION"},
50 {EIGRP_TLV_NEXT_MCAST_SEQ, "NEXT_MCAST_SEQ"},
51 {EIGRP_TLV_PEER_TERMINATION, "PEER_TERMINATION"},
52 {EIGRP_TLV_PEER_MTRLIST, "PEER_MTRLIST"},
53 {EIGRP_TLV_PEER_TIDLIST, "PEER_TIDLIST"},
54 {0}};
55
56
57 /*
58 * @fn eigrp_hello_timer
59 *
60 * @param[in] thread current execution thread timer is associated with
61 *
62 * @return void
63 *
64 * @par
65 * Called once per "hello" time interval, default 5 seconds
66 * Sends hello packet via multicast for all interfaces eigrp
67 * is configured for
68 */
69 void eigrp_hello_timer(struct thread *thread)
70 {
71 struct eigrp_interface *ei;
72
73 ei = THREAD_ARG(thread);
74
75 if (IS_DEBUG_EIGRP(0, TIMERS))
76 zlog_debug("Start Hello Timer (%s) Expire [%u]", IF_NAME(ei),
77 ei->params.v_hello);
78
79 /* Sending hello packet. */
80 eigrp_hello_send(ei, EIGRP_HELLO_NORMAL, NULL);
81
82 /* Hello timer set. */
83 thread_add_timer(master, eigrp_hello_timer, ei, ei->params.v_hello,
84 &ei->t_hello);
85 }
86
87 /**
88 * @fn eigrp_hello_parameter_decode
89 *
90 * @param[in] nbr neighbor the ACK should be sent to
91 * @param[in] param pointer packet TLV is stored to
92 *
93 * @return uint16_t number of bytes added to packet stream
94 *
95 * @par
96 * Encode Parameter TLV, used to convey metric weights and the hold time.
97 *
98 * @usage
99 * Note the addition of K6 for the new extended metrics, and does not apply to
100 * older TLV packet formats.
101 */
102 static struct eigrp_neighbor *
103 eigrp_hello_parameter_decode(struct eigrp_neighbor *nbr,
104 struct eigrp_tlv_hdr_type *tlv)
105 {
106 struct eigrp *eigrp = nbr->ei->eigrp;
107 struct TLV_Parameter_Type *param = (struct TLV_Parameter_Type *)tlv;
108
109 /* First validate TLV length */
110 if (tlv->length < sizeof(struct TLV_Parameter_Type))
111 return NULL;
112
113 /* copy over the values passed in by the neighbor */
114 nbr->K1 = param->K1;
115 nbr->K2 = param->K2;
116 nbr->K3 = param->K3;
117 nbr->K4 = param->K4;
118 nbr->K5 = param->K5;
119 nbr->K6 = param->K6;
120 nbr->v_holddown = ntohs(param->hold_time);
121
122 /*
123 * Check K1-K5 have the correct values to be able to become neighbors
124 * K6 does not have to match
125 */
126 if ((eigrp->k_values[0] == nbr->K1) && (eigrp->k_values[1] == nbr->K2)
127 && (eigrp->k_values[2] == nbr->K3)
128 && (eigrp->k_values[3] == nbr->K4)
129 && (eigrp->k_values[4] == nbr->K5)) {
130
131 if (eigrp_nbr_state_get(nbr) == EIGRP_NEIGHBOR_DOWN) {
132 zlog_info(
133 "Neighbor %pI4 (%s) is pending: new adjacency",
134 &nbr->src,
135 ifindex2ifname(nbr->ei->ifp->ifindex,
136 eigrp->vrf_id));
137
138 /* Expedited hello sent */
139 eigrp_hello_send(nbr->ei, EIGRP_HELLO_NORMAL, NULL);
140
141 // if(ntohl(nbr->ei->address->u.prefix4.s_addr) >
142 // ntohl(nbr->src.s_addr))
143 eigrp_update_send_init(nbr);
144
145 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_PENDING);
146 }
147 } else {
148 if (eigrp_nbr_state_get(nbr) != EIGRP_NEIGHBOR_DOWN) {
149 if ((param->K1 & param->K2 & param->K3 & param->K4
150 & param->K5)
151 == 255) {
152 zlog_info(
153 "Neighbor %pI4 (%s) is down: Interface PEER-TERMINATION received",
154 &nbr->src,
155 ifindex2ifname(nbr->ei->ifp->ifindex,
156 eigrp->vrf_id));
157 eigrp_nbr_delete(nbr);
158 return NULL;
159 } else {
160 zlog_info(
161 "Neighbor %pI4 (%s) going down: Kvalue mismatch",
162 &nbr->src,
163 ifindex2ifname(nbr->ei->ifp->ifindex,
164 eigrp->vrf_id));
165 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_DOWN);
166 }
167 }
168 }
169
170 return nbr;
171 }
172
173 static uint8_t
174 eigrp_hello_authentication_decode(struct stream *s,
175 struct eigrp_tlv_hdr_type *tlv_header,
176 struct eigrp_neighbor *nbr)
177 {
178 struct TLV_MD5_Authentication_Type *md5;
179
180 md5 = (struct TLV_MD5_Authentication_Type *)tlv_header;
181
182 if (md5->auth_type == EIGRP_AUTH_TYPE_MD5) {
183 /* Validate tlv length */
184 if (md5->length < sizeof(struct TLV_MD5_Authentication_Type))
185 return 0;
186
187 return eigrp_check_md5_digest(s, md5, nbr,
188 EIGRP_AUTH_BASIC_HELLO_FLAG);
189 } else if (md5->auth_type == EIGRP_AUTH_TYPE_SHA256) {
190 /* Validate tlv length */
191 if (md5->length < sizeof(struct TLV_SHA256_Authentication_Type))
192 return 0;
193
194 return eigrp_check_sha256_digest(
195 s, (struct TLV_SHA256_Authentication_Type *)tlv_header,
196 nbr, EIGRP_AUTH_BASIC_HELLO_FLAG);
197 }
198
199 return 0;
200 }
201
202 /**
203 * @fn eigrp_sw_version_decode
204 *
205 * @param[in] nbr neighbor the ACK shoudl be sent to
206 * @param[in] param pointer to TLV software version information
207 *
208 * @return void
209 *
210 * @par
211 * Read the software version in the specified location.
212 * This consists of two bytes of OS version, and two bytes of EIGRP
213 * revision number.
214 */
215 static void eigrp_sw_version_decode(struct eigrp_neighbor *nbr,
216 struct eigrp_tlv_hdr_type *tlv)
217 {
218 struct TLV_Software_Type *version = (struct TLV_Software_Type *)tlv;
219
220 /* Validate TLV length */
221 if (tlv->length < sizeof(struct TLV_Software_Type))
222 return;
223
224 nbr->os_rel_major = version->vender_major;
225 nbr->os_rel_minor = version->vender_minor;
226 nbr->tlv_rel_major = version->eigrp_major;
227 nbr->tlv_rel_minor = version->eigrp_minor;
228 return;
229 }
230
231 /**
232 * @fn eigrp_peer_termination_decode
233 *
234 * @param[in] nbr neighbor the ACK shoudl be sent to
235 * @param[in] tlv pointer to TLV software version information
236 *
237 * @return void
238 *
239 * @par
240 * Read the address in the TLV and match to out address. If
241 * a match is found, move the sending neighbor to the down state. If
242 * out address is not in the TLV, then ignore the peer termination
243 */
244 static void eigrp_peer_termination_decode(struct eigrp_neighbor *nbr,
245 struct eigrp_tlv_hdr_type *tlv)
246 {
247 struct eigrp *eigrp = nbr->ei->eigrp;
248 struct TLV_Peer_Termination_type *param =
249 (struct TLV_Peer_Termination_type *)tlv;
250
251 /* Validate TLV length */
252 if (tlv->length < sizeof(struct TLV_Peer_Termination_type))
253 return;
254
255 uint32_t my_ip = nbr->ei->address.u.prefix4.s_addr;
256 uint32_t received_ip = param->neighbor_ip;
257
258 if (my_ip == received_ip) {
259 zlog_info(
260 "Neighbor %pI4 (%s) is down: Peer Termination received",
261 &nbr->src,
262 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id));
263 /* set neighbor to DOWN */
264 nbr->state = EIGRP_NEIGHBOR_DOWN;
265 /* delete neighbor */
266 eigrp_nbr_delete(nbr);
267 }
268 }
269
270 /**
271 * @fn eigrp_peer_termination_encode
272 *
273 * @param[in,out] s packet stream TLV is stored to
274 * @param[in] nbr_addr pointer to neighbor address for Peer
275 * Termination TLV
276 *
277 * @return uint16_t number of bytes added to packet stream
278 *
279 * @par
280 * Function used to encode Peer Termination TLV to Hello packet.
281 */
282 static uint16_t eigrp_peer_termination_encode(struct stream *s,
283 struct in_addr *nbr_addr)
284 {
285 uint16_t length = EIGRP_TLV_PEER_TERMINATION_LEN;
286
287 /* fill in type and length */
288 stream_putw(s, EIGRP_TLV_PEER_TERMINATION);
289 stream_putw(s, length);
290
291 /* fill in unknown field 0x04 */
292 stream_putc(s, 0x04);
293
294 /* finally neighbor IP address */
295 stream_put_ipv4(s, nbr_addr->s_addr);
296
297 return (length);
298 }
299
300 /*
301 * @fn eigrp_hello_receive
302 *
303 * @param[in] eigrp eigrp routing process
304 * @param[in] iph pointer to ip header
305 * @param[in] eigrph pointer to eigrp header
306 * @param[in] s input ip stream
307 * @param[in] ei eigrp interface packet arrived on
308 * @param[in] size size of eigrp packet
309 *
310 * @return void
311 *
312 * @par
313 * This is the main worker function for processing hello packets. It
314 * will validate the peer associated with the src ip address of the ip
315 * header, and then decode each of the general TLVs which the packet
316 * may contain.
317 *
318 * @usage
319 * Not all TLVs are current decoder. This is a work in progress..
320 */
321 void eigrp_hello_receive(struct eigrp *eigrp, struct ip *iph,
322 struct eigrp_header *eigrph, struct stream *s,
323 struct eigrp_interface *ei, int size)
324 {
325 struct eigrp_tlv_hdr_type *tlv_header;
326 struct eigrp_neighbor *nbr;
327 uint16_t type;
328 uint16_t length;
329
330 /* get neighbor struct */
331 nbr = eigrp_nbr_get(ei, eigrph, iph);
332
333 /* neighbor must be valid, eigrp_nbr_get creates if none existed */
334 assert(nbr);
335
336 if (IS_DEBUG_EIGRP_PACKET(eigrph->opcode - 1, RECV))
337 zlog_debug("Processing Hello size[%u] int(%s) nbr(%pI4)", size,
338 ifindex2ifname(nbr->ei->ifp->ifindex, eigrp->vrf_id),
339 &nbr->src);
340
341 size -= EIGRP_HEADER_LEN;
342 if (size < 0)
343 return;
344
345 tlv_header = (struct eigrp_tlv_hdr_type *)eigrph->tlv;
346
347 do {
348 type = ntohs(tlv_header->type);
349 length = ntohs(tlv_header->length);
350
351 /* Validate length against packet size */
352 if (length > size)
353 return;
354
355 if ((length > 0) && (length <= size)) {
356 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
357 zlog_debug(
358 " General TLV(%s)",
359 lookup_msg(eigrp_general_tlv_type_str,
360 type, NULL));
361
362 // determine what General TLV is being processed
363 switch (type) {
364 case EIGRP_TLV_PARAMETER:
365 nbr = eigrp_hello_parameter_decode(nbr,
366 tlv_header);
367 if (!nbr)
368 return;
369 break;
370 case EIGRP_TLV_AUTH: {
371 if (eigrp_hello_authentication_decode(
372 s, tlv_header, nbr)
373 == 0)
374 return;
375 else
376 break;
377 break;
378 }
379 case EIGRP_TLV_SEQ:
380 break;
381 case EIGRP_TLV_SW_VERSION:
382 eigrp_sw_version_decode(nbr, tlv_header);
383 break;
384 case EIGRP_TLV_NEXT_MCAST_SEQ:
385 break;
386 case EIGRP_TLV_PEER_TERMINATION:
387 eigrp_peer_termination_decode(nbr, tlv_header);
388 return;
389 break;
390 case EIGRP_TLV_PEER_MTRLIST:
391 case EIGRP_TLV_PEER_TIDLIST:
392 break;
393 default:
394 break;
395 }
396 }
397
398 tlv_header = (struct eigrp_tlv_hdr_type *)(((char *)tlv_header)
399 + length);
400 size -= length;
401
402 } while (size > 0);
403
404
405 /*If received packet is hello with Parameter TLV*/
406 if (ntohl(eigrph->ack) == 0) {
407 /* increment statistics. */
408 ei->hello_in++;
409 if (nbr)
410 eigrp_nbr_state_update(nbr);
411 }
412
413 if (IS_DEBUG_EIGRP_PACKET(0, RECV))
414 zlog_debug("Hello Packet received from %pI4", &nbr->src);
415 }
416
417 uint32_t FRR_MAJOR;
418 uint32_t FRR_MINOR;
419
420 void eigrp_sw_version_initialize(void)
421 {
422 char ver_string[] = VERSION;
423 char *dash = strstr(ver_string, "-");
424 int ret;
425
426 if (dash)
427 dash[0] = '\0';
428
429 ret = sscanf(ver_string, "%" SCNu32 ".%" SCNu32, &FRR_MAJOR,
430 &FRR_MINOR);
431 if (ret != 2)
432 flog_err(EC_EIGRP_PACKET,
433 "Did not Properly parse %s, please fix VERSION string",
434 VERSION);
435 }
436
437 /**
438 * @fn eigrp_sw_version_encode
439 *
440 * @param[in,out] s packet stream TLV is stored to
441 *
442 * @return uint16_t number of bytes added to packet stream
443 *
444 * @par
445 * Store the software version in the specified location.
446 * This consists of two bytes of OS version, and two bytes of EIGRP
447 * revision number.
448 */
449 static uint16_t eigrp_sw_version_encode(struct stream *s)
450 {
451 uint16_t length = EIGRP_TLV_SW_VERSION_LEN;
452
453 // setup the tlv fields
454 stream_putw(s, EIGRP_TLV_SW_VERSION);
455 stream_putw(s, length);
456
457 stream_putc(s, FRR_MAJOR); //!< major os version
458 stream_putc(s, FRR_MINOR); //!< minor os version
459
460 /* and the core eigrp version */
461 stream_putc(s, EIGRP_MAJOR_VERSION);
462 stream_putc(s, EIGRP_MINOR_VERSION);
463
464 return (length);
465 }
466
467 /**
468 * @fn eigrp_tidlist_encode
469 *
470 * @param[in,out] s packet stream TLV is stored to
471 *
472 * @return void
473 *
474 * @par
475 * If doing mutli-topology, then store the supported TID list.
476 * This is currently a place holder function
477 */
478 static uint16_t eigrp_tidlist_encode(struct stream *s)
479 {
480 // uint16_t length = EIGRP_TLV_SW_VERSION_LEN;
481 return 0;
482 }
483
484 /**
485 * @fn eigrp_sequence_encode
486 *
487 * @param[in,out] s packet stream TLV is stored to
488 *
489 * @return uint16_t number of bytes added to packet stream
490 *
491 * @par
492 * Part of conditional receive process
493 *
494 */
495 static uint16_t eigrp_sequence_encode(struct eigrp *eigrp, struct stream *s)
496 {
497 uint16_t length = EIGRP_TLV_SEQ_BASE_LEN;
498 struct eigrp_interface *ei;
499 struct listnode *node, *node2, *nnode2;
500 struct eigrp_neighbor *nbr;
501 size_t backup_end, size_end;
502 int found;
503
504 // add in the parameters TLV
505 backup_end = stream_get_endp(s);
506 stream_putw(s, EIGRP_TLV_SEQ);
507 size_end = s->endp;
508 stream_putw(s, 0x0000);
509 stream_putc(s, IPV4_MAX_BYTELEN);
510
511 found = 0;
512 for (ALL_LIST_ELEMENTS_RO(eigrp->eiflist, node, ei)) {
513 for (ALL_LIST_ELEMENTS(ei->nbrs, node2, nnode2, nbr)) {
514 if (nbr->multicast_queue->count > 0) {
515 length += (uint16_t)stream_put_ipv4(
516 s, nbr->src.s_addr);
517 found = 1;
518 }
519 }
520 }
521
522 if (found == 0) {
523 stream_set_endp(s, backup_end);
524 return 0;
525 }
526
527 backup_end = stream_get_endp(s);
528 stream_set_endp(s, size_end);
529 stream_putw(s, length);
530 stream_set_endp(s, backup_end);
531
532 return length;
533 }
534
535 /**
536 * @fn eigrp_sequence_encode
537 *
538 * @param[in,out] s packet stream TLV is stored to
539 *
540 * @return uint16_t number of bytes added to packet stream
541 *
542 * @par
543 * Part of conditional receive process
544 *
545 */
546 static uint16_t eigrp_next_sequence_encode(struct eigrp *eigrp,
547 struct stream *s)
548 {
549 uint16_t length = EIGRP_NEXT_SEQUENCE_TLV_SIZE;
550
551 // add in the parameters TLV
552 stream_putw(s, EIGRP_TLV_NEXT_MCAST_SEQ);
553 stream_putw(s, EIGRP_NEXT_SEQUENCE_TLV_SIZE);
554 stream_putl(s, eigrp->sequence_number + 1);
555
556 return length;
557 }
558
559 /**
560 * @fn eigrp_hello_parameter_encode
561 *
562 * @param[in] ei pointer to interface hello packet came in on
563 * @param[in,out] s packet stream TLV is stored to
564 *
565 * @return uint16_t number of bytes added to packet stream
566 *
567 * @par
568 * Encode Parameter TLV, used to convey metric weights and the hold time.
569 *
570 * @usage
571 * Note the addition of K6 for the new extended metrics, and does not apply to
572 * older TLV packet formats.
573 */
574 static uint16_t eigrp_hello_parameter_encode(struct eigrp_interface *ei,
575 struct stream *s, uint8_t flags)
576 {
577 // add in the parameters TLV
578 stream_putw(s, EIGRP_TLV_PARAMETER);
579 stream_putw(s, EIGRP_TLV_PARAMETER_LEN);
580
581 // if graceful shutdown is needed to be announced, send all 255 in K
582 // values
583 if (flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) {
584 stream_putc(s, 0xff); /* K1 */
585 stream_putc(s, 0xff); /* K2 */
586 stream_putc(s, 0xff); /* K3 */
587 stream_putc(s, 0xff); /* K4 */
588 stream_putc(s, 0xff); /* K5 */
589 stream_putc(s, 0xff); /* K6 */
590 } else // set k values
591 {
592 stream_putc(s, ei->eigrp->k_values[0]); /* K1 */
593 stream_putc(s, ei->eigrp->k_values[1]); /* K2 */
594 stream_putc(s, ei->eigrp->k_values[2]); /* K3 */
595 stream_putc(s, ei->eigrp->k_values[3]); /* K4 */
596 stream_putc(s, ei->eigrp->k_values[4]); /* K5 */
597 stream_putc(s, ei->eigrp->k_values[5]); /* K6 */
598 }
599
600 // and set hold time value..
601 stream_putw(s, ei->params.v_wait);
602
603 return EIGRP_TLV_PARAMETER_LEN;
604 }
605
606 /**
607 * @fn eigrp_hello_encode
608 *
609 * @param[in] ei pointer to interface hello packet came in on
610 * @param[in] s packet stream TLV is stored to
611 * @param[in] ack if non-zero, neigbors sequence packet to ack
612 * @param[in] flags type of hello packet
613 * @param[in] nbr_addr pointer to neighbor address for Peer
614 * Termination TLV
615 *
616 * @return eigrp_packet pointer initialize hello packet
617 *
618 * @par
619 * Allocate an EIGRP hello packet, and add in the the approperate TLVs
620 *
621 */
622 static struct eigrp_packet *eigrp_hello_encode(struct eigrp_interface *ei,
623 in_addr_t addr, uint32_t ack,
624 uint8_t flags,
625 struct in_addr *nbr_addr)
626 {
627 struct eigrp_packet *ep;
628 uint16_t length = EIGRP_HEADER_LEN;
629
630 // allocate a new packet to be sent
631 ep = eigrp_packet_new(EIGRP_PACKET_MTU(ei->ifp->mtu), NULL);
632
633 if (ep) {
634 // encode common header feilds
635 eigrp_packet_header_init(EIGRP_OPC_HELLO, ei->eigrp, ep->s, 0,
636 0, ack);
637
638 // encode Authentication TLV
639 if ((ei->params.auth_type == EIGRP_AUTH_TYPE_MD5)
640 && (ei->params.auth_keychain != NULL)) {
641 length += eigrp_add_authTLV_MD5_to_stream(ep->s, ei);
642 } else if ((ei->params.auth_type == EIGRP_AUTH_TYPE_SHA256)
643 && (ei->params.auth_keychain != NULL)) {
644 length += eigrp_add_authTLV_SHA256_to_stream(ep->s, ei);
645 }
646
647 /* encode appropriate parameters to Hello packet */
648 if (flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN)
649 length += eigrp_hello_parameter_encode(
650 ei, ep->s, EIGRP_HELLO_GRACEFUL_SHUTDOWN);
651 else
652 length += eigrp_hello_parameter_encode(
653 ei, ep->s, EIGRP_HELLO_NORMAL);
654
655 // figure out the version of code we're running
656 length += eigrp_sw_version_encode(ep->s);
657
658 if (flags & EIGRP_HELLO_ADD_SEQUENCE) {
659 length += eigrp_sequence_encode(ei->eigrp, ep->s);
660 length += eigrp_next_sequence_encode(ei->eigrp, ep->s);
661 }
662
663 // add in the TID list if doing multi-topology
664 length += eigrp_tidlist_encode(ep->s);
665
666 /* encode Peer Termination TLV if needed */
667 if (flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN_NBR)
668 length +=
669 eigrp_peer_termination_encode(ep->s, nbr_addr);
670
671 // Set packet length
672 ep->length = length;
673
674 // set soruce address for the hello packet
675 ep->dst.s_addr = addr;
676
677 if ((ei->params.auth_type == EIGRP_AUTH_TYPE_MD5)
678 && (ei->params.auth_keychain != NULL)) {
679 eigrp_make_md5_digest(ei, ep->s,
680 EIGRP_AUTH_BASIC_HELLO_FLAG);
681 } else if ((ei->params.auth_type == EIGRP_AUTH_TYPE_SHA256)
682 && (ei->params.auth_keychain != NULL)) {
683 eigrp_make_sha256_digest(ei, ep->s,
684 EIGRP_AUTH_BASIC_HELLO_FLAG);
685 }
686
687 // EIGRP Checksum
688 eigrp_packet_checksum(ei, ep->s, length);
689 }
690
691 return (ep);
692 }
693
694 /**
695 * @fn eigrp_hello_send
696 *
697 * @param[in] nbr neighbor the ACK should be sent to
698 *
699 * @return void
700 *
701 * @par
702 * Send (unicast) a hello packet with the destination address
703 * associated with the neighbor. The eigrp header ACK feild will be
704 * updated to the neighbor's sequence number to acknolodge any
705 * outstanding packets
706 */
707 void eigrp_hello_send_ack(struct eigrp_neighbor *nbr)
708 {
709 struct eigrp_packet *ep;
710
711 /* if packet succesfully created, add it to the interface queue */
712 ep = eigrp_hello_encode(nbr->ei, nbr->src.s_addr,
713 nbr->recv_sequence_number, EIGRP_HELLO_NORMAL,
714 NULL);
715
716 if (ep) {
717 if (IS_DEBUG_EIGRP_PACKET(0, SEND))
718 zlog_debug("Queueing [Hello] Ack Seq [%u] nbr [%pI4]",
719 nbr->recv_sequence_number, &nbr->src);
720
721 /* Add packet to the top of the interface output queue*/
722 eigrp_fifo_push(nbr->ei->obuf, ep);
723
724 /* Hook thread to write packet. */
725 if (nbr->ei->on_write_q == 0) {
726 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
727 nbr->ei->on_write_q = 1;
728 }
729 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
730 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
731 }
732 }
733
734 /**
735 * @fn eigrp_hello_send
736 *
737 * @param[in] ei pointer to interface hello should be sent
738 * @param[in] flags type of hello packet
739 * @param[in] nbr_addr pointer to neighbor address for Peer
740 * Termination TLV
741 *
742 * @return void
743 *
744 * @par
745 * Build and enqueue a generic (multicast) periodic hello packet for
746 * sending. If no packets are currently queues, the packet will be
747 * sent immadiatly
748 */
749 void eigrp_hello_send(struct eigrp_interface *ei, uint8_t flags,
750 struct in_addr *nbr_addr)
751 {
752 struct eigrp_packet *ep = NULL;
753
754 if (IS_DEBUG_EIGRP_PACKET(0, SEND))
755 zlog_debug("Queueing [Hello] Interface(%s)", IF_NAME(ei));
756
757 /* if packet was succesfully created, then add it to the interface queue
758 */
759 ep = eigrp_hello_encode(ei, htonl(EIGRP_MULTICAST_ADDRESS), 0, flags,
760 nbr_addr);
761
762 if (ep) {
763 // Add packet to the top of the interface output queue
764 eigrp_fifo_push(ei->obuf, ep);
765
766 /* Hook thread to write packet. */
767 if (ei->on_write_q == 0) {
768 listnode_add(ei->eigrp->oi_write_q, ei);
769 ei->on_write_q = 1;
770 }
771
772 if (ei->eigrp->t_write == NULL) {
773 if (flags & EIGRP_HELLO_GRACEFUL_SHUTDOWN) {
774 thread_execute(master, eigrp_write, ei->eigrp,
775 ei->eigrp->fd);
776 } else {
777 thread_add_write(master, eigrp_write, ei->eigrp,
778 ei->eigrp->fd,
779 &ei->eigrp->t_write);
780 }
781 }
782 }
783 }