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