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