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