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