]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_packet.c
*: silence '-Wchar-subscripts' warnings on NetBSD
[mirror_frr.git] / eigrpd / eigrp_packet.c
CommitLineData
7f57883e
DS
1/*
2 * EIGRP General Sending and Receiving of EIGRP Packets.
3 * Copyright (C) 2013-2014
4 * Authors:
5 * Donnie Savage
6 * Jan Janovic
7 * Matej Perina
8 * Peter Orsag
9 * Peter Paluch
10 *
11 * This file is part of GNU Zebra.
12 *
13 * GNU Zebra is free software; you can redistribute it and/or modify it
14 * under the terms of the GNU General Public License as published by the
15 * Free Software Foundation; either version 2, or (at your option) any
16 * later version.
17 *
18 * GNU Zebra is distributed in the hope that it will be useful, but
19 * WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
21 * General Public License for more details.
22 *
896014f4
DL
23 * You should have received a copy of the GNU General Public License along
24 * with this program; see the file COPYING; if not, write to the Free Software
25 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
7f57883e
DS
26 */
27
28#include <zebra.h>
29
30#include "thread.h"
31#include "memory.h"
32#include "linklist.h"
33#include "vty.h"
34#include "keychain.h"
35#include "prefix.h"
36#include "if.h"
37#include "table.h"
38#include "sockunion.h"
39#include "stream.h"
40#include "log.h"
41#include "sockopt.h"
42#include "checksum.h"
43#include "md5.h"
44#include "sha256.h"
45
46#include "eigrpd/eigrp_structs.h"
47#include "eigrpd/eigrpd.h"
48#include "eigrpd/eigrp_interface.h"
49#include "eigrpd/eigrp_neighbor.h"
50#include "eigrpd/eigrp_packet.h"
51#include "eigrpd/eigrp_zebra.h"
52#include "eigrpd/eigrp_vty.h"
53#include "eigrpd/eigrp_dump.h"
54#include "eigrpd/eigrp_network.h"
55#include "eigrpd/eigrp_topology.h"
56#include "eigrpd/eigrp_fsm.h"
57#include "eigrpd/eigrp_memory.h"
58
59/* Packet Type String. */
d62a17ae 60const struct message eigrp_packet_type_str[] = {
61 {EIGRP_OPC_UPDATE, "Update"},
62 {EIGRP_OPC_REQUEST, "Request"},
63 {EIGRP_OPC_QUERY, "Query"},
64 {EIGRP_OPC_REPLY, "Reply"},
65 {EIGRP_OPC_HELLO, "Hello"},
66 {EIGRP_OPC_IPXSAP, "IPX-SAP"},
67 {EIGRP_OPC_PROBE, "Probe"},
68 {EIGRP_OPC_ACK, "Ack"},
69 {EIGRP_OPC_SIAQUERY, "SIAQuery"},
70 {EIGRP_OPC_SIAREPLY, "SIAReply"},
71 {0}};
f9e5c9ca 72
7f57883e
DS
73
74static unsigned char zeropad[16] = {0};
75
76/* Forward function reference*/
d62a17ae 77static struct stream *eigrp_recv_packet(int, struct interface **,
78 struct stream *);
79static int eigrp_verify_header(struct stream *, struct eigrp_interface *,
80 struct ip *, struct eigrp_header *);
81static int eigrp_check_network_mask(struct eigrp_interface *, struct in_addr);
82
83static int eigrp_retrans_count_exceeded(struct eigrp_packet *ep,
84 struct eigrp_neighbor *nbr)
7f57883e 85{
d62a17ae 86 return 1;
7f57883e
DS
87}
88
d62a17ae 89int eigrp_make_md5_digest(struct eigrp_interface *ei, struct stream *s,
90 u_char flags)
7f57883e 91{
d62a17ae 92 struct key *key = NULL;
93 struct keychain *keychain;
94
95 unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
96 MD5_CTX ctx;
97 u_char *ibuf;
98 size_t backup_get, backup_end;
99 struct TLV_MD5_Authentication_Type *auth_TLV;
100
101 ibuf = s->data;
102 backup_end = s->endp;
103 backup_get = s->getp;
104
105 auth_TLV = eigrp_authTLV_MD5_new();
106
107 stream_set_getp(s, EIGRP_HEADER_LEN);
108 stream_get(auth_TLV, s, EIGRP_AUTH_MD5_TLV_SIZE);
109 stream_set_getp(s, backup_get);
110
b748db67 111 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 112 if (keychain)
113 key = key_lookup_for_send(keychain);
114 else {
115 eigrp_authTLV_MD5_free(auth_TLV);
116 return EIGRP_AUTH_TYPE_NONE;
117 }
118
119 memset(&ctx, 0, sizeof(ctx));
120 MD5Init(&ctx);
121
122 /* Generate a digest. Each situation needs different handling */
123 if (flags & EIGRP_AUTH_BASIC_HELLO_FLAG) {
124 MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
125 MD5Update(&ctx, key->string, strlen(key->string));
126 if (strlen(key->string) < 16)
127 MD5Update(&ctx, zeropad, 16 - strlen(key->string));
128 } else if (flags & EIGRP_AUTH_UPDATE_INIT_FLAG) {
129 MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
130 } else if (flags & EIGRP_AUTH_UPDATE_FLAG) {
131 MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
132 MD5Update(&ctx, key->string, strlen(key->string));
133 if (strlen(key->string) < 16)
134 MD5Update(&ctx, zeropad, 16 - strlen(key->string));
135 if (backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) {
136 MD5Update(&ctx,
9d303b37
DL
137 ibuf + (EIGRP_HEADER_LEN
138 + EIGRP_AUTH_MD5_TLV_SIZE),
d62a17ae 139 backup_end - 20
140 - (EIGRP_HEADER_LEN
141 + EIGRP_AUTH_MD5_TLV_SIZE));
142 }
143 }
144
145 MD5Final(digest, &ctx);
146
147 /* Append md5 digest to the end of the stream. */
148 memcpy(auth_TLV->digest, digest, EIGRP_AUTH_TYPE_MD5_LEN);
149
150 stream_set_endp(s, EIGRP_HEADER_LEN);
151 stream_put(s, auth_TLV, EIGRP_AUTH_MD5_TLV_SIZE);
152 stream_set_endp(s, backup_end);
153
154 eigrp_authTLV_MD5_free(auth_TLV);
155 return EIGRP_AUTH_TYPE_MD5_LEN;
7f57883e
DS
156}
157
d62a17ae 158int eigrp_check_md5_digest(struct stream *s,
159 struct TLV_MD5_Authentication_Type *authTLV,
160 struct eigrp_neighbor *nbr, u_char flags)
7f57883e 161{
d62a17ae 162 MD5_CTX ctx;
163 unsigned char digest[EIGRP_AUTH_TYPE_MD5_LEN];
5da38785 164 unsigned char orig[EIGRP_AUTH_TYPE_MD5_LEN];
d62a17ae 165 struct key *key = NULL;
166 struct keychain *keychain;
167 u_char *ibuf;
168 size_t backup_end;
169 struct TLV_MD5_Authentication_Type *auth_TLV;
170 struct eigrp_header *eigrph;
171
6c86ed54 172 if (ntohl(nbr->crypt_seqnum) > ntohl(authTLV->key_sequence)) {
d62a17ae 173 zlog_warn(
174 "interface %s: eigrp_check_md5 bad sequence %d (expect %d)",
175 IF_NAME(nbr->ei), ntohl(authTLV->key_sequence),
176 ntohl(nbr->crypt_seqnum));
177 return 0;
178 }
179
180 eigrph = (struct eigrp_header *)s->data;
181 eigrph->checksum = 0;
182
183 auth_TLV = (struct TLV_MD5_Authentication_Type *)(s->data
184 + EIGRP_HEADER_LEN);
5da38785
DS
185 memcpy(orig, auth_TLV->digest, EIGRP_AUTH_TYPE_MD5_LEN);
186 memset(digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
187 memset(auth_TLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
d62a17ae 188
189 ibuf = s->data;
190 backup_end = s->endp;
191
b748db67 192 keychain = keychain_lookup(nbr->ei->params.auth_keychain);
d62a17ae 193 if (keychain)
194 key = key_lookup_for_send(keychain);
195
dbfd865b
DS
196 if (!key) {
197 zlog_warn("Interface %s: Expected key value not found in config",
198 nbr->ei->ifp->name);
199 return 0;
200 }
201
d62a17ae 202 memset(&ctx, 0, sizeof(ctx));
203 MD5Init(&ctx);
204
205 /* Generate a digest. Each situation needs different handling */
206 if (flags & EIGRP_AUTH_BASIC_HELLO_FLAG) {
207 MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
208 MD5Update(&ctx, key->string, strlen(key->string));
209 if (strlen(key->string) < 16)
210 MD5Update(&ctx, zeropad, 16 - strlen(key->string));
211 } else if (flags & EIGRP_AUTH_UPDATE_INIT_FLAG) {
212 MD5Update(&ctx, ibuf, EIGRP_MD5_UPDATE_INIT_COMPUTE);
213 } else if (flags & EIGRP_AUTH_UPDATE_FLAG) {
214 MD5Update(&ctx, ibuf, EIGRP_MD5_BASIC_COMPUTE);
215 MD5Update(&ctx, key->string, strlen(key->string));
216 if (strlen(key->string) < 16)
217 MD5Update(&ctx, zeropad, 16 - strlen(key->string));
218 if (backup_end > (EIGRP_HEADER_LEN + EIGRP_AUTH_MD5_TLV_SIZE)) {
219 MD5Update(&ctx,
9d303b37
DL
220 ibuf + (EIGRP_HEADER_LEN
221 + EIGRP_AUTH_MD5_TLV_SIZE),
d62a17ae 222 backup_end - 20
223 - (EIGRP_HEADER_LEN
224 + EIGRP_AUTH_MD5_TLV_SIZE));
225 }
226 }
227
228 MD5Final(digest, &ctx);
229
230 /* compare the two */
5da38785 231 if (memcmp(orig, digest, EIGRP_AUTH_TYPE_MD5_LEN) != 0) {
d62a17ae 232 zlog_warn("interface %s: eigrp_check_md5 checksum mismatch",
233 IF_NAME(nbr->ei));
234 return 0;
235 }
236
237 /* save neighbor's crypt_seqnum */
dbfd865b 238 nbr->crypt_seqnum = authTLV->key_sequence;
d62a17ae 239
240 return 1;
7f57883e
DS
241}
242
d62a17ae 243int eigrp_make_sha256_digest(struct eigrp_interface *ei, struct stream *s,
244 u_char flags)
7f57883e 245{
d62a17ae 246 struct key *key = NULL;
247 struct keychain *keychain;
dbfd865b 248 char source_ip[PREFIX_STRLEN];
7f57883e 249
d62a17ae 250 unsigned char digest[EIGRP_AUTH_TYPE_SHA256_LEN];
251 unsigned char buffer[1 + PLAINTEXT_LENGTH + 45 + 1] = {0};
dbfd865b 252
d62a17ae 253 HMAC_SHA256_CTX ctx;
254 void *ibuf;
255 size_t backup_get, backup_end;
256 struct TLV_SHA256_Authentication_Type *auth_TLV;
7f57883e 257
d62a17ae 258 ibuf = s->data;
259 backup_end = s->endp;
260 backup_get = s->getp;
7f57883e 261
d62a17ae 262 auth_TLV = eigrp_authTLV_SHA256_new();
7f57883e 263
d62a17ae 264 stream_set_getp(s, EIGRP_HEADER_LEN);
265 stream_get(auth_TLV, s, EIGRP_AUTH_SHA256_TLV_SIZE);
266 stream_set_getp(s, backup_get);
7f57883e 267
b748db67 268 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 269 if (keychain)
270 key = key_lookup_for_send(keychain);
7f57883e 271
dbfd865b
DS
272 if (!key) {
273 zlog_warn("Interface %s: Expected key value not found in config",
274 ei->ifp->name);
21dfc9ed 275 eigrp_authTLV_SHA256_free(auth_TLV);
dbfd865b
DS
276 return 0;
277 }
7f57883e 278
dbfd865b 279 inet_ntop(AF_INET, &ei->address->u.prefix4, source_ip, PREFIX_STRLEN);
7f57883e 280
d62a17ae 281 memset(&ctx, 0, sizeof(ctx));
282 buffer[0] = '\n';
283 memcpy(buffer + 1, key, strlen(key->string));
284 memcpy(buffer + 1 + strlen(key->string), source_ip, strlen(source_ip));
285 HMAC__SHA256_Init(&ctx, buffer,
286 1 + strlen(key->string) + strlen(source_ip));
287 HMAC__SHA256_Update(&ctx, ibuf, strlen(ibuf));
288 HMAC__SHA256_Final(digest, &ctx);
7f57883e
DS
289
290
d62a17ae 291 /* Put hmac-sha256 digest to it's place */
292 memcpy(auth_TLV->digest, digest, EIGRP_AUTH_TYPE_SHA256_LEN);
7f57883e 293
d62a17ae 294 stream_set_endp(s, EIGRP_HEADER_LEN);
295 stream_put(s, auth_TLV, EIGRP_AUTH_SHA256_TLV_SIZE);
296 stream_set_endp(s, backup_end);
7f57883e 297
d62a17ae 298 eigrp_authTLV_SHA256_free(auth_TLV);
7f57883e 299
d62a17ae 300 return EIGRP_AUTH_TYPE_SHA256_LEN;
7f57883e
DS
301}
302
d62a17ae 303int eigrp_check_sha256_digest(struct stream *s,
304 struct TLV_SHA256_Authentication_Type *authTLV,
305 struct eigrp_neighbor *nbr, u_char flags)
7f57883e 306{
d62a17ae 307 return 1;
7f57883e 308}
f9e5c9ca 309
d62a17ae 310int eigrp_write(struct thread *thread)
7f57883e 311{
d62a17ae 312 struct eigrp *eigrp = THREAD_ARG(thread);
313 struct eigrp_header *eigrph;
314 struct eigrp_interface *ei;
315 struct eigrp_packet *ep;
316 struct sockaddr_in sa_dst;
317 struct ip iph;
318 struct msghdr msg;
319 struct iovec iov[2];
9c273c6d 320 u_int32_t seqno, ack;
d62a17ae 321
322 int ret;
323 int flags = 0;
324 struct listnode *node;
7f57883e 325#ifdef WANT_EIGRP_WRITE_FRAGMENT
d62a17ae 326 static u_int16_t ipid = 0;
9d303b37
DL
327#endif /* WANT_EIGRP_WRITE_FRAGMENT */
328 /* $FRR indent$ */
329/* clang-format off */
7f57883e
DS
330#define EIGRP_WRITE_IPHL_SHIFT 2
331
d62a17ae 332 eigrp->t_write = NULL;
7f57883e 333
d62a17ae 334 node = listhead(eigrp->oi_write_q);
335 assert(node);
336 ei = listgetdata(node);
337 assert(ei);
7f57883e
DS
338
339#ifdef WANT_EIGRP_WRITE_FRAGMENT
d62a17ae 340 /* seed ipid static with low order bits of time */
341 if (ipid == 0)
342 ipid = (time(NULL) & 0xffff);
7f57883e
DS
343#endif /* WANT_EIGRP_WRITE_FRAGMENT */
344
d62a17ae 345 /* Get one packet from queue. */
f90f65a2 346 ep = eigrp_fifo_next(ei->obuf);
d4395853
DS
347 if (!ep) {
348 zlog_err("%s: Interface %s no packet on queue?",
349 __PRETTY_FUNCTION__, ei->ifp->name);
350 goto out;
351 }
352 if (ep->length < EIGRP_HEADER_LEN) {
353 zlog_err("%s: Packet just has a header?",
354 __PRETTY_FUNCTION__);
355 eigrp_header_dump((struct eigrp_header *)ep->s->data);
356 eigrp_packet_delete(ei);
357 goto out;
358 }
7f57883e 359
d62a17ae 360 if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
361 eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
7f57883e 362
d62a17ae 363 memset(&iph, 0, sizeof(struct ip));
364 memset(&sa_dst, 0, sizeof(sa_dst));
7f57883e 365
9c273c6d
DS
366 /*
367 * We build and schedule packets to go out
368 * in the future. In the mean time we may
369 * process some update packets from the
370 * neighbor, thus making it necessary
371 * to update the ack we are using for
372 * this outgoing packet.
373 */
374 eigrph = (struct eigrp_header *)STREAM_DATA(ep->s);
9c273c6d
DS
375 seqno = ntohl(eigrph->sequence);
376 ack = ntohl(eigrph->ack);
377 if (ep->nbr && (ack != ep->nbr->recv_sequence_number)) {
378 eigrph->ack = htonl(ep->nbr->recv_sequence_number);
379 ack = ep->nbr->recv_sequence_number;
380 eigrph->checksum = 0;
381 eigrp_packet_checksum(ei, ep->s, ep->length);
382 }
383
d62a17ae 384 sa_dst.sin_family = AF_INET;
7f57883e 385#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
d62a17ae 386 sa_dst.sin_len = sizeof(sa_dst);
7f57883e 387#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
d62a17ae 388 sa_dst.sin_addr = ep->dst;
389 sa_dst.sin_port = htons(0);
390
391 /* Set DONTROUTE flag if dst is unicast. */
392 if (!IN_MULTICAST(htonl(ep->dst.s_addr)))
393 flags = MSG_DONTROUTE;
394
395 iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT;
396 /* it'd be very strange for header to not be 4byte-word aligned but.. */
397 if (sizeof(struct ip)
398 > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT))
399 iph.ip_hl++; /* we presume sizeof struct ip cant overflow
400 ip_hl.. */
401
402 iph.ip_v = IPVERSION;
403 iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
404 iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length;
405
406#if defined(__DragonFly__)
407 /*
408 * DragonFly's raw socket expects ip_len/ip_off in network byte order.
409 */
410 iph.ip_len = htons(iph.ip_len);
7f57883e
DS
411#endif
412
d62a17ae 413 iph.ip_off = 0;
414 iph.ip_ttl = EIGRP_IP_TTL;
415 iph.ip_p = IPPROTO_EIGRPIGP;
416 iph.ip_sum = 0;
417 iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
418 iph.ip_dst.s_addr = ep->dst.s_addr;
419
420 memset(&msg, 0, sizeof(msg));
421 msg.msg_name = (caddr_t)&sa_dst;
422 msg.msg_namelen = sizeof(sa_dst);
423 msg.msg_iov = iov;
424 msg.msg_iovlen = 2;
425
426 iov[0].iov_base = (char *)&iph;
427 iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT;
2d34fb80 428 iov[1].iov_base = stream_pnt(ep->s);
d62a17ae 429 iov[1].iov_len = ep->length;
430
431 /* send final fragment (could be first) */
432 sockopt_iphdrincl_swab_htosys(&iph);
433 ret = sendmsg(eigrp->fd, &msg, flags);
434 sockopt_iphdrincl_swab_systoh(&iph);
435
436 if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) {
437 eigrph = (struct eigrp_header *)STREAM_DATA(ep->s);
9c273c6d 438 zlog_debug("Sending [%s][%d/%d] to [%s] via [%s] ret [%d].",
443e99e7 439 lookup_msg(eigrp_packet_type_str, eigrph->opcode, NULL),
9c273c6d 440 seqno, ack,
d62a17ae 441 inet_ntoa(ep->dst), IF_NAME(ei), ret);
442 }
443
444 if (ret < 0)
445 zlog_warn(
446 "*** sendmsg in eigrp_write failed to %s, "
447 "id %d, off %d, len %d, interface %s, mtu %u: %s",
448 inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off,
449 iph.ip_len, ei->ifp->name, ei->ifp->mtu,
450 safe_strerror(errno));
451
d62a17ae 452 /* Now delete packet from queue. */
453 eigrp_packet_delete(ei);
454
d4395853 455out:
f90f65a2 456 if (eigrp_fifo_next(ei->obuf) == NULL) {
d62a17ae 457 ei->on_write_q = 0;
458 list_delete_node(eigrp->oi_write_q, node);
459 }
460
461 /* If packets still remain in queue, call write thread. */
462 if (!list_isempty(eigrp->oi_write_q)) {
463 eigrp->t_write = NULL;
464 thread_add_write(master, eigrp_write, eigrp, eigrp->fd,
465 &eigrp->t_write);
466 }
467
468 return 0;
7f57883e
DS
469}
470
471/* Starting point of packet process function. */
d62a17ae 472int eigrp_read(struct thread *thread)
7f57883e 473{
d62a17ae 474 int ret;
475 struct stream *ibuf;
476 struct eigrp *eigrp;
477 struct eigrp_interface *ei;
478 struct ip *iph;
479 struct eigrp_header *eigrph;
480 struct interface *ifp;
481 struct eigrp_neighbor *nbr;
482
483 u_int16_t opcode = 0;
484 u_int16_t length = 0;
485
486 /* first of all get interface pointer. */
487 eigrp = THREAD_ARG(thread);
488
489 /* prepare for next packet. */
490 eigrp->t_read = NULL;
491 thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
492
493 stream_reset(eigrp->ibuf);
494 if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf))) {
495 /* This raw packet is known to be at least as big as its IP
496 * header. */
497 return -1;
498 }
499
500 /* Note that there should not be alignment problems with this assignment
501 because this is at the beginning of the stream data buffer. */
502 iph = (struct ip *)STREAM_DATA(ibuf);
503
504 // Substract IPv4 header size from EIGRP Packet itself
505 if (iph->ip_v == 4)
506 length = (iph->ip_len) - 20U;
507
508
509 /* IP Header dump. */
510 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
511 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
512 eigrp_ip_header_dump(iph);
513
514 /* Note that sockopt_iphdrincl_swab_systoh was called in
515 * eigrp_recv_packet. */
516 if (ifp == NULL) {
517 struct connected *c;
518 /* Handle cases where the platform does not support retrieving
519 the ifindex,
520 and also platforms (such as Solaris 8) that claim to support
521 ifindex
522 retrieval but do not. */
523 c = if_lookup_address((void *)&iph->ip_src, AF_INET,
524 VRF_DEFAULT);
525
526 if (c == NULL)
527 return 0;
528
529 ifp = c->ifp;
530 }
531
532 /* associate packet with eigrp interface */
b748db67 533 ei = ifp->info;
d62a17ae 534
535 /* eigrp_verify_header() relies on a valid "ei" and thus can be called
536 only
537 after the checks below are passed. These checks in turn access the
538 fields of unverified "eigrph" structure for their own purposes and
539 must remain very accurate in doing this.
540 */
541 if (!ei)
542 return 0;
543
544 /* Self-originated packet should be discarded silently. */
545 if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
19aad877 546 || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address->u.prefix4))) {
d62a17ae 547 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
548 zlog_debug(
549 "eigrp_read[%s]: Dropping self-originated packet",
550 inet_ntoa(iph->ip_src));
551 return 0;
552 }
553
554 /* Advance from IP header to EIGRP header (iph->ip_hl has been verified
555 by eigrp_recv_packet() to be correct). */
556
557 stream_forward_getp(ibuf, (iph->ip_hl * 4));
2d34fb80 558 eigrph = (struct eigrp_header *)stream_pnt(ibuf);
d62a17ae 559
560 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
561 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
562 eigrp_header_dump(eigrph);
563
564 // if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) -
565 // stream_get_getp(ibuf)))
566 // return -1;
567
d62a17ae 568 /* If incoming interface is passive one, ignore it. */
b748db67 569 if (ei && eigrp_if_is_passive(ei)) {
d62a17ae 570 char buf[3][INET_ADDRSTRLEN];
571
572 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
573 zlog_debug(
574 "ignoring packet from router %s sent to %s, "
575 "received on a passive interface, %s",
576 inet_ntop(AF_INET, &eigrph->vrid, buf[0],
577 sizeof(buf[0])),
578 inet_ntop(AF_INET, &iph->ip_dst, buf[1],
579 sizeof(buf[1])),
580 inet_ntop(AF_INET, &ei->address->u.prefix4,
581 buf[2], sizeof(buf[2])));
582
583 if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) {
d62a17ae 584 eigrp_if_set_multicast(ei);
585 }
586 return 0;
587 }
588
589 /* else it must be a local eigrp interface, check it was received on
590 * correct link
591 */
592 else if (ei->ifp != ifp) {
593 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
594 zlog_warn("Packet from [%s] received on wrong link %s",
595 inet_ntoa(iph->ip_src), ifp->name);
596 return 0;
597 }
598
599 /* Verify more EIGRP header fields. */
600 ret = eigrp_verify_header(ibuf, ei, iph, eigrph);
601 if (ret < 0) {
602 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
603 zlog_debug(
604 "eigrp_read[%s]: Header check failed, dropping.",
605 inet_ntoa(iph->ip_src));
606 return ret;
607 }
608
609 /* calcualte the eigrp packet length, and move the pounter to the
610 start of the eigrp TLVs */
611 opcode = eigrph->opcode;
612
9c273c6d 613 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) {
dbfd865b 614 char src[PREFIX_STRLEN], dst[PREFIX_STRLEN];
9c273c6d 615
21dfc9ed
DS
616 strlcpy(src, inet_ntoa(iph->ip_src), sizeof(src));
617 strlcpy(dst, inet_ntoa(iph->ip_dst), sizeof(dst));
9c273c6d
DS
618 zlog_debug("Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]",
619 lookup_msg(eigrp_packet_type_str, opcode, NULL),
620 ntohl(eigrph->sequence), ntohl(eigrph->ack), length,
621 IF_NAME(ei), src, dst);
622 }
d62a17ae 623
624 /* Read rest of the packet and call each sort of packet routine. */
625 stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
626
627 /* New testing block of code for handling Acks */
628 if (ntohl(eigrph->ack) != 0) {
1a0770e3
DS
629 struct eigrp_packet *ep = NULL;
630
d62a17ae 631 nbr = eigrp_nbr_get(ei, eigrph, iph);
632
1a0770e3 633 // neighbor must be valid, eigrp_nbr_get creates if none existed
d62a17ae 634 assert(nbr);
635
f90f65a2 636 ep = eigrp_fifo_next(nbr->retrans_queue);
1a0770e3
DS
637 if ((ep) && (ntohl(eigrph->ack) == ep->sequence_number)) {
638 ep = eigrp_fifo_pop(nbr->retrans_queue);
639 eigrp_packet_free(ep);
640
641 if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
642 && (ntohl(eigrph->ack) == nbr->init_sequence_number)) {
643 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP);
644 zlog_info("Neighbor(%s) adjacency became full",
645 inet_ntoa(nbr->src));
646 nbr->init_sequence_number = 0;
647 nbr->recv_sequence_number =
648 ntohl(eigrph->sequence);
649 eigrp_update_send_EOT(nbr);
d62a17ae 650 }
1a0770e3
DS
651 else
652 eigrp_send_packet_reliably(nbr);
d62a17ae 653 }
f90f65a2 654 ep = eigrp_fifo_next(nbr->multicast_queue);
d62a17ae 655 if (ep) {
656 if (ntohl(eigrph->ack) == ep->sequence_number) {
f90f65a2 657 ep = eigrp_fifo_pop(nbr->multicast_queue);
d62a17ae 658 eigrp_packet_free(ep);
659 if (nbr->multicast_queue->count > 0) {
660 eigrp_send_packet_reliably(nbr);
661 }
662 }
663 }
664 }
665
666
667 switch (opcode) {
668 case EIGRP_OPC_HELLO:
669 eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length);
670 break;
671 case EIGRP_OPC_PROBE:
672 // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei,
673 // length);
674 break;
675 case EIGRP_OPC_QUERY:
676 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
677 break;
678 case EIGRP_OPC_REPLY:
679 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
680 break;
681 case EIGRP_OPC_REQUEST:
682 // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei,
683 // length);
684 break;
685 case EIGRP_OPC_SIAQUERY:
686 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
687 break;
688 case EIGRP_OPC_SIAREPLY:
689 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
690 break;
691 case EIGRP_OPC_UPDATE:
692 eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length);
693 break;
694 default:
695 zlog_warn(
696 "interface %s: EIGRP packet header type %d unsupported",
697 IF_NAME(ei), opcode);
698 break;
699 }
700
701 return 0;
7f57883e
DS
702}
703
d62a17ae 704static struct stream *eigrp_recv_packet(int fd, struct interface **ifp,
705 struct stream *ibuf)
7f57883e 706{
d62a17ae 707 int ret;
708 struct ip *iph;
709 u_int16_t ip_len;
710 unsigned int ifindex = 0;
711 struct iovec iov;
712 /* Header and data both require alignment. */
713 char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
714 struct msghdr msgh;
715
716 memset(&msgh, 0, sizeof(struct msghdr));
717 msgh.msg_iov = &iov;
718 msgh.msg_iovlen = 1;
719 msgh.msg_control = (caddr_t)buff;
720 msgh.msg_controllen = sizeof(buff);
721
722 ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1));
723 if (ret < 0) {
724 zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
725 return NULL;
726 }
727 if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
728 {
729 zlog_warn(
730 "eigrp_recv_packet: discarding runt packet of length %d "
731 "(ip header size is %u)",
732 ret, (u_int)sizeof(iph));
733 return NULL;
734 }
735
736 /* Note that there should not be alignment problems with this assignment
737 because this is at the beginning of the stream data buffer. */
738 iph = (struct ip *)STREAM_DATA(ibuf);
739 sockopt_iphdrincl_swab_systoh(iph);
740
741 ip_len = iph->ip_len;
742
743#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
744 /*
745 * Kernel network code touches incoming IP header parameters,
746 * before protocol specific processing.
747 *
748 * 1) Convert byteorder to host representation.
749 * --> ip_len, ip_id, ip_off
750 *
751 * 2) Adjust ip_len to strip IP header size!
752 * --> If user process receives entire IP packet via RAW
753 * socket, it must consider adding IP header size to
754 * the "ip_len" field of "ip" structure.
755 *
756 * For more details, see <netinet/ip_input.c>.
757 */
758 ip_len = ip_len + (iph->ip_hl << 2);
7f57883e
DS
759#endif
760
d62a17ae 761#if defined(__DragonFly__)
762 /*
763 * in DragonFly's raw socket, ip_len/ip_off are read
764 * in network byte order.
765 * As OpenBSD < 200311 adjust ip_len to strip IP header size!
766 */
767 ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
7f57883e
DS
768#endif
769
d62a17ae 770 ifindex = getsockopt_ifindex(AF_INET, &msgh);
7f57883e 771
d62a17ae 772 *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
7f57883e 773
d62a17ae 774 if (ret != ip_len) {
775 zlog_warn(
776 "eigrp_recv_packet read length mismatch: ip_len is %d, "
777 "but recvmsg returned %d",
778 ip_len, ret);
779 return NULL;
780 }
7f57883e 781
d62a17ae 782 return ibuf;
7f57883e
DS
783}
784
d62a17ae 785struct eigrp_fifo *eigrp_fifo_new(void)
7f57883e 786{
d62a17ae 787 struct eigrp_fifo *new;
7f57883e 788
d62a17ae 789 new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
790 return new;
7f57883e
DS
791}
792
793/* Free eigrp packet fifo. */
d62a17ae 794void eigrp_fifo_free(struct eigrp_fifo *fifo)
7f57883e 795{
d62a17ae 796 struct eigrp_packet *ep;
797 struct eigrp_packet *next;
798
799 for (ep = fifo->head; ep; ep = next) {
800 next = ep->next;
801 eigrp_packet_free(ep);
802 }
803 fifo->head = fifo->tail = NULL;
804 fifo->count = 0;
805
806 XFREE(MTYPE_EIGRP_FIFO, fifo);
7f57883e
DS
807}
808
809/* Free eigrp fifo entries without destroying fifo itself*/
d62a17ae 810void eigrp_fifo_reset(struct eigrp_fifo *fifo)
7f57883e 811{
d62a17ae 812 struct eigrp_packet *ep;
813 struct eigrp_packet *next;
814
815 for (ep = fifo->head; ep; ep = next) {
816 next = ep->next;
817 eigrp_packet_free(ep);
818 }
819 fifo->head = fifo->tail = NULL;
820 fifo->count = 0;
7f57883e
DS
821}
822
907b4303 823struct eigrp_packet *eigrp_packet_new(size_t size, struct eigrp_neighbor *nbr)
7f57883e 824{
d62a17ae 825 struct eigrp_packet *new;
7f57883e 826
d62a17ae 827 new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
828 new->s = stream_new(size);
829 new->retrans_counter = 0;
907b4303 830 new->nbr = nbr;
7f57883e 831
d62a17ae 832 return new;
7f57883e
DS
833}
834
d62a17ae 835void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr)
7f57883e 836{
d62a17ae 837 struct eigrp_packet *ep;
838
f90f65a2 839 ep = eigrp_fifo_next(nbr->retrans_queue);
d62a17ae 840
841 if (ep) {
842 struct eigrp_packet *duplicate;
843 duplicate = eigrp_packet_duplicate(ep, nbr);
844 /* Add packet to the top of the interface output queue*/
f90f65a2 845 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 846
847 /*Start retransmission timer*/
848 thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
849 EIGRP_PACKET_RETRANS_TIME,
850 &ep->t_retrans_timer);
851
852 /*Increment sequence number counter*/
853 nbr->ei->eigrp->sequence_number++;
854
855 /* Hook thread to write packet. */
856 if (nbr->ei->on_write_q == 0) {
857 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
858 nbr->ei->on_write_q = 1;
859 }
860 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
861 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
862 }
7f57883e
DS
863}
864
865/* Calculate EIGRP checksum */
d62a17ae 866void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
867 u_int16_t length)
7f57883e 868{
d62a17ae 869 struct eigrp_header *eigrph;
7f57883e 870
d62a17ae 871 eigrph = (struct eigrp_header *)STREAM_DATA(s);
7f57883e 872
d62a17ae 873 /* Calculate checksum. */
874 eigrph->checksum = in_cksum(eigrph, length);
7f57883e
DS
875}
876
877/* Make EIGRP header. */
cf2f4dae 878void eigrp_packet_header_init(int type, struct eigrp *eigrp,
d62a17ae 879 struct stream *s, u_int32_t flags,
880 u_int32_t sequence, u_int32_t ack)
7f57883e 881{
d62a17ae 882 struct eigrp_header *eigrph;
7f57883e 883
7ecf0a4d 884 stream_reset(s);
d62a17ae 885 eigrph = (struct eigrp_header *)STREAM_DATA(s);
7f57883e 886
d62a17ae 887 eigrph->version = (u_char)EIGRP_HEADER_VERSION;
888 eigrph->opcode = (u_char)type;
889 eigrph->checksum = 0;
7f57883e 890
cf2f4dae
DS
891 eigrph->vrid = htons(eigrp->vrid);
892 eigrph->ASNumber = htons(eigrp->AS);
d62a17ae 893 eigrph->ack = htonl(ack);
894 eigrph->sequence = htonl(sequence);
895 // if(flags == EIGRP_INIT_FLAG)
896 // eigrph->sequence = htonl(3);
897 eigrph->flags = htonl(flags);
7f57883e 898
0f6c16fb 899 if (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
d62a17ae 900 zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
901 htonl(eigrph->sequence), htonl(eigrph->ack));
7f57883e 902
d62a17ae 903 stream_forward_endp(s, EIGRP_HEADER_LEN);
7f57883e
DS
904}
905
906/* Add new packet to head of fifo. */
f90f65a2 907void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep)
7f57883e 908{
d62a17ae 909 ep->next = fifo->head;
910 ep->previous = NULL;
7f57883e 911
d62a17ae 912 if (fifo->tail == NULL)
913 fifo->tail = ep;
7f57883e 914
d62a17ae 915 if (fifo->count != 0)
916 fifo->head->previous = ep;
7f57883e 917
d62a17ae 918 fifo->head = ep;
7f57883e 919
d62a17ae 920 fifo->count++;
7f57883e
DS
921}
922
7f57883e 923/* Return last fifo entry. */
f90f65a2 924struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo)
7f57883e 925{
d62a17ae 926 return fifo->tail;
7f57883e
DS
927}
928
d62a17ae 929void eigrp_packet_delete(struct eigrp_interface *ei)
7f57883e 930{
d62a17ae 931 struct eigrp_packet *ep;
7f57883e 932
d62a17ae 933 ep = eigrp_fifo_pop(ei->obuf);
7f57883e 934
d62a17ae 935 if (ep)
936 eigrp_packet_free(ep);
7f57883e
DS
937}
938
d62a17ae 939void eigrp_packet_free(struct eigrp_packet *ep)
7f57883e 940{
d62a17ae 941 if (ep->s)
942 stream_free(ep->s);
7f57883e 943
d62a17ae 944 THREAD_OFF(ep->t_retrans_timer);
7f57883e 945
d62a17ae 946 XFREE(MTYPE_EIGRP_PACKET, ep);
7f57883e 947
d62a17ae 948 ep = NULL;
7f57883e
DS
949}
950
951/* EIGRP Header verification. */
d62a17ae 952static int eigrp_verify_header(struct stream *ibuf, struct eigrp_interface *ei,
953 struct ip *iph, struct eigrp_header *eigrph)
7f57883e 954{
d62a17ae 955 /* Check network mask, Silently discarded. */
956 if (!eigrp_check_network_mask(ei, iph->ip_src)) {
957 zlog_warn(
958 "interface %s: eigrp_read network address is not same [%s]",
959 IF_NAME(ei), inet_ntoa(iph->ip_src));
960 return -1;
961 }
962 //
963 // /* Check authentication. The function handles logging actions, where
964 // required. */
965 // if (! eigrp_check_auth(ei, eigrph))
966 // return -1;
967
968 return 0;
7f57883e
DS
969}
970
971/* Unbound socket will accept any Raw IP packets if proto is matched.
f9e5c9ca
DS
972 To prevent it, compare src IP address and i/f address with masking
973 i/f network mask. */
d62a17ae 974static int eigrp_check_network_mask(struct eigrp_interface *ei,
975 struct in_addr ip_src)
7f57883e 976{
d62a17ae 977 struct in_addr mask, me, him;
7f57883e 978
d62a17ae 979 if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
980 return 1;
7f57883e 981
d62a17ae 982 masklen2ip(ei->address->prefixlen, &mask);
7f57883e 983
d62a17ae 984 me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
985 him.s_addr = ip_src.s_addr & mask.s_addr;
7f57883e 986
d62a17ae 987 if (IPV4_ADDR_SAME(&me, &him))
988 return 1;
7f57883e 989
d62a17ae 990 return 0;
7f57883e
DS
991}
992
d62a17ae 993int eigrp_unack_packet_retrans(struct thread *thread)
7f57883e 994{
d62a17ae 995 struct eigrp_neighbor *nbr;
996 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
997
998 struct eigrp_packet *ep;
f90f65a2 999 ep = eigrp_fifo_next(nbr->retrans_queue);
d62a17ae 1000
1001 if (ep) {
1002 struct eigrp_packet *duplicate;
1003 duplicate = eigrp_packet_duplicate(ep, nbr);
1004
1005 /* Add packet to the top of the interface output queue*/
f90f65a2 1006 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 1007
1008 ep->retrans_counter++;
1009 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1010 return eigrp_retrans_count_exceeded(ep, nbr);
1011
1012 /*Start retransmission timer*/
1013 ep->t_retrans_timer = NULL;
1014 thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
1015 EIGRP_PACKET_RETRANS_TIME,
1016 &ep->t_retrans_timer);
1017
1018 /* Hook thread to write packet. */
1019 if (nbr->ei->on_write_q == 0) {
1020 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1021 nbr->ei->on_write_q = 1;
1022 }
1023 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1024 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1025 }
1026
1027 return 0;
7f57883e
DS
1028}
1029
d62a17ae 1030int eigrp_unack_multicast_packet_retrans(struct thread *thread)
7f57883e 1031{
d62a17ae 1032 struct eigrp_neighbor *nbr;
1033 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
1034
1035 struct eigrp_packet *ep;
f90f65a2 1036 ep = eigrp_fifo_next(nbr->multicast_queue);
d62a17ae 1037
1038 if (ep) {
1039 struct eigrp_packet *duplicate;
1040 duplicate = eigrp_packet_duplicate(ep, nbr);
1041 /* Add packet to the top of the interface output queue*/
f90f65a2 1042 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 1043
1044 ep->retrans_counter++;
1045 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1046 return eigrp_retrans_count_exceeded(ep, nbr);
1047
1048 /*Start retransmission timer*/
1049 ep->t_retrans_timer = NULL;
1050 thread_add_timer(master, eigrp_unack_multicast_packet_retrans,
1051 nbr, EIGRP_PACKET_RETRANS_TIME,
1052 &ep->t_retrans_timer);
1053
1054 /* Hook thread to write packet. */
1055 if (nbr->ei->on_write_q == 0) {
1056 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1057 nbr->ei->on_write_q = 1;
1058 }
1059 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1060 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1061 }
1062
1063 return 0;
7f57883e
DS
1064}
1065
1066/* Get packet from tail of fifo. */
f90f65a2 1067struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo)
7f57883e 1068{
1a0770e3 1069 struct eigrp_packet *ep = NULL;
7f57883e 1070
d62a17ae 1071 ep = fifo->tail;
7f57883e 1072
d62a17ae 1073 if (ep) {
1074 fifo->tail = ep->previous;
7f57883e 1075
d62a17ae 1076 if (fifo->tail == NULL)
1077 fifo->head = NULL;
1078 else
1079 fifo->tail->next = NULL;
7f57883e 1080
d62a17ae 1081 fifo->count--;
1082 }
7f57883e 1083
d62a17ae 1084 return ep;
7f57883e
DS
1085}
1086
d62a17ae 1087struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
1088 struct eigrp_neighbor *nbr)
7f57883e 1089{
d62a17ae 1090 struct eigrp_packet *new;
7f57883e 1091
907b4303 1092 new = eigrp_packet_new(nbr->ei->ifp->mtu, nbr);
d62a17ae 1093 new->length = old->length;
1094 new->retrans_counter = old->retrans_counter;
1095 new->dst = old->dst;
1096 new->sequence_number = old->sequence_number;
1097 stream_copy(new->s, old->s);
7f57883e 1098
d62a17ae 1099 return new;
7f57883e
DS
1100}
1101
5ca6df78
DS
1102static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new()
1103{
1104 struct TLV_IPv4_Internal_type *new;
1105
1106 new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,
1107 sizeof(struct TLV_IPv4_Internal_type));
1108
1109 return new;
1110}
1111
d62a17ae 1112struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
7f57883e 1113{
d62a17ae 1114 struct TLV_IPv4_Internal_type *tlv;
1115
1116 tlv = eigrp_IPv4_InternalTLV_new();
1117
1118 tlv->type = stream_getw(s);
1119 tlv->length = stream_getw(s);
1120 tlv->forward.s_addr = stream_getl(s);
1121 tlv->metric.delay = stream_getl(s);
b1968f83 1122 tlv->metric.bandwidth = stream_getl(s);
d62a17ae 1123 tlv->metric.mtu[0] = stream_getc(s);
1124 tlv->metric.mtu[1] = stream_getc(s);
1125 tlv->metric.mtu[2] = stream_getc(s);
1126 tlv->metric.hop_count = stream_getc(s);
1127 tlv->metric.reliability = stream_getc(s);
1128 tlv->metric.load = stream_getc(s);
1129 tlv->metric.tag = stream_getc(s);
1130 tlv->metric.flags = stream_getc(s);
1131
1132 tlv->prefix_length = stream_getc(s);
1133
1134 if (tlv->prefix_length <= 8) {
1135 tlv->destination_part[0] = stream_getc(s);
1136 tlv->destination.s_addr = (tlv->destination_part[0]);
1137 } else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16) {
1138 tlv->destination_part[0] = stream_getc(s);
1139 tlv->destination_part[1] = stream_getc(s);
1140 tlv->destination.s_addr = ((tlv->destination_part[1] << 8)
1141 + tlv->destination_part[0]);
1142 } else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24) {
1143 tlv->destination_part[0] = stream_getc(s);
1144 tlv->destination_part[1] = stream_getc(s);
1145 tlv->destination_part[2] = stream_getc(s);
1146 tlv->destination.s_addr = ((tlv->destination_part[2] << 16)
1147 + (tlv->destination_part[1] << 8)
1148 + tlv->destination_part[0]);
1149 } else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32) {
1150 tlv->destination_part[0] = stream_getc(s);
1151 tlv->destination_part[1] = stream_getc(s);
1152 tlv->destination_part[2] = stream_getc(s);
1153 tlv->destination_part[3] = stream_getc(s);
1154 tlv->destination.s_addr = ((tlv->destination_part[3] << 24)
1155 + (tlv->destination_part[2] << 16)
1156 + (tlv->destination_part[1] << 8)
1157 + tlv->destination_part[0]);
1158 }
1159 return tlv;
7f57883e
DS
1160}
1161
d62a17ae 1162u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s,
1163 struct eigrp_prefix_entry *pe)
7f57883e 1164{
d62a17ae 1165 u_int16_t length;
1166
1167 stream_putw(s, EIGRP_TLV_IPv4_INT);
03161b73
DS
1168 switch (pe->destination->prefixlen) {
1169 case 0:
1170 case 1:
1171 case 2:
1172 case 3:
1173 case 4:
1174 case 5:
1175 case 6:
1176 case 7:
1177 case 8:
1178 length = EIGRP_TLV_IPV4_SIZE_GRT_0_BIT;
1179 stream_putw(s, length);
1180 break;
1181 case 9:
1182 case 10:
1183 case 11:
1184 case 12:
1185 case 13:
1186 case 14:
1187 case 15:
1188 case 16:
1189 length = EIGRP_TLV_IPV4_SIZE_GRT_8_BIT;
1190 stream_putw(s, length);
1191 break;
1192 case 17:
1193 case 18:
1194 case 19:
1195 case 20:
1196 case 21:
1197 case 22:
1198 case 23:
1199 case 24:
1200 length = EIGRP_TLV_IPV4_SIZE_GRT_16_BIT;
1201 stream_putw(s, length);
1202 break;
1203 case 25:
1204 case 26:
1205 case 27:
1206 case 28:
1207 case 29:
1208 case 30:
1209 case 31:
1210 case 32:
1211 length = EIGRP_TLV_IPV4_SIZE_GRT_24_BIT;
1212 stream_putw(s, length);
1213 break;
1214 default:
1215 zlog_err("%s: Unexpected prefix length: %d",
1216 __PRETTY_FUNCTION__, pe->destination->prefixlen);
1217 return 0;
d62a17ae 1218 }
d62a17ae 1219 stream_putl(s, 0x00000000);
1220
1221 /*Metric*/
1222 stream_putl(s, pe->reported_metric.delay);
b1968f83 1223 stream_putl(s, pe->reported_metric.bandwidth);
d62a17ae 1224 stream_putc(s, pe->reported_metric.mtu[2]);
1225 stream_putc(s, pe->reported_metric.mtu[1]);
1226 stream_putc(s, pe->reported_metric.mtu[0]);
1227 stream_putc(s, pe->reported_metric.hop_count);
1228 stream_putc(s, pe->reported_metric.reliability);
1229 stream_putc(s, pe->reported_metric.load);
1230 stream_putc(s, pe->reported_metric.tag);
1231 stream_putc(s, pe->reported_metric.flags);
1232
02b45998 1233 stream_putc(s, pe->destination->prefixlen);
d62a17ae 1234
02b45998
DS
1235 stream_putc(s, pe->destination->u.prefix4.s_addr & 0xFF);
1236 if (pe->destination->prefixlen > 8)
d62a17ae 1237 stream_putc(s,
02b45998
DS
1238 (pe->destination->u.prefix4.s_addr >> 8) & 0xFF);
1239 if (pe->destination->prefixlen > 16)
d62a17ae 1240 stream_putc(s,
02b45998
DS
1241 (pe->destination->u.prefix4.s_addr >> 16) & 0xFF);
1242 if (pe->destination->prefixlen > 24)
d62a17ae 1243 stream_putc(s,
02b45998 1244 (pe->destination->u.prefix4.s_addr >> 24) & 0xFF);
d62a17ae 1245
1246 return length;
7f57883e
DS
1247}
1248
d62a17ae 1249u_int16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
1250 struct eigrp_interface *ei)
7f57883e 1251{
d62a17ae 1252 struct key *key;
1253 struct keychain *keychain;
1254 struct TLV_MD5_Authentication_Type *authTLV;
1255
1256 authTLV = eigrp_authTLV_MD5_new();
1257
1258 authTLV->type = htons(EIGRP_TLV_AUTH);
1259 authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
1260 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
1261 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
1262 authTLV->key_sequence = 0;
1263 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1264
b748db67 1265 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 1266 if (keychain)
1267 key = key_lookup_for_send(keychain);
1268 else {
b748db67
DS
1269 free(ei->params.auth_keychain);
1270 ei->params.auth_keychain = NULL;
d62a17ae 1271 eigrp_authTLV_MD5_free(authTLV);
1272 return 0;
1273 }
1274
1275 if (key) {
1276 authTLV->key_id = htonl(key->index);
1277 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
1278 stream_put(s, authTLV,
1279 sizeof(struct TLV_MD5_Authentication_Type));
1280 eigrp_authTLV_MD5_free(authTLV);
1281 return EIGRP_AUTH_MD5_TLV_SIZE;
1282 }
1283
1284 eigrp_authTLV_MD5_free(authTLV);
1285
1286 return 0;
7f57883e
DS
1287}
1288
d62a17ae 1289u_int16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
1290 struct eigrp_interface *ei)
7f57883e 1291{
d62a17ae 1292 struct key *key;
1293 struct keychain *keychain;
1294 struct TLV_SHA256_Authentication_Type *authTLV;
1295
1296 authTLV = eigrp_authTLV_SHA256_new();
1297
1298 authTLV->type = htons(EIGRP_TLV_AUTH);
1299 authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
1300 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
1301 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
1302 authTLV->key_sequence = 0;
1303 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1304
b748db67 1305 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 1306 if (keychain)
1307 key = key_lookup_for_send(keychain);
1308 else {
b748db67
DS
1309 free(ei->params.auth_keychain);
1310 ei->params.auth_keychain = NULL;
d62a17ae 1311 eigrp_authTLV_SHA256_free(authTLV);
1312 return 0;
1313 }
1314
1315 if (key) {
1316 authTLV->key_id = 0;
1317 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_SHA256_LEN);
1318 stream_put(s, authTLV,
1319 sizeof(struct TLV_SHA256_Authentication_Type));
1320 eigrp_authTLV_SHA256_free(authTLV);
1321 return EIGRP_AUTH_SHA256_TLV_SIZE;
1322 }
1323
1324 eigrp_authTLV_SHA256_free(authTLV);
1325
1326 return 0;
7f57883e
DS
1327}
1328
d62a17ae 1329struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new()
7f57883e 1330{
d62a17ae 1331 struct TLV_MD5_Authentication_Type *new;
7f57883e 1332
d62a17ae 1333 new = XCALLOC(MTYPE_EIGRP_AUTH_TLV,
1334 sizeof(struct TLV_MD5_Authentication_Type));
7f57883e 1335
d62a17ae 1336 return new;
7f57883e
DS
1337}
1338
d62a17ae 1339void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV)
7f57883e 1340{
d62a17ae 1341 XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
7f57883e
DS
1342}
1343
d62a17ae 1344struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new()
7f57883e 1345{
d62a17ae 1346 struct TLV_SHA256_Authentication_Type *new;
7f57883e 1347
d62a17ae 1348 new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV,
1349 sizeof(struct TLV_SHA256_Authentication_Type));
7f57883e 1350
d62a17ae 1351 return new;
7f57883e
DS
1352}
1353
d62a17ae 1354void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV)
7f57883e 1355{
d62a17ae 1356 XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
7f57883e
DS
1357}
1358
d62a17ae 1359void eigrp_IPv4_InternalTLV_free(
1360 struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
7f57883e 1361{
d62a17ae 1362 XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
7f57883e
DS
1363}
1364
d62a17ae 1365struct TLV_Sequence_Type *eigrp_SequenceTLV_new()
7f57883e 1366{
d62a17ae 1367 struct TLV_Sequence_Type *new;
7f57883e 1368
d62a17ae 1369 new = XCALLOC(MTYPE_EIGRP_SEQ_TLV, sizeof(struct TLV_Sequence_Type));
7f57883e 1370
d62a17ae 1371 return new;
7f57883e 1372}