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