]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_packet.c
eigrpd: Convert eigrp_packet.c to not use VRF_DEFAULT
[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;
488
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
514
515 /* IP Header dump. */
516 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
517 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
518 eigrp_ip_header_dump(iph);
519
520 /* Note that sockopt_iphdrincl_swab_systoh was called in
521 * eigrp_recv_packet. */
522 if (ifp == NULL) {
523 struct connected *c;
524 /* Handle cases where the platform does not support retrieving
525 the ifindex,
526 and also platforms (such as Solaris 8) that claim to support
527 ifindex
528 retrieval but do not. */
529 c = if_lookup_address((void *)&iph->ip_src, AF_INET,
daa64bdf 530 eigrp->vrf_id);
d62a17ae 531
532 if (c == NULL)
533 return 0;
534
535 ifp = c->ifp;
536 }
537
538 /* associate packet with eigrp interface */
b748db67 539 ei = ifp->info;
d62a17ae 540
541 /* eigrp_verify_header() relies on a valid "ei" and thus can be called
542 only
543 after the checks below are passed. These checks in turn access the
544 fields of unverified "eigrph" structure for their own purposes and
545 must remain very accurate in doing this.
546 */
547 if (!ei)
548 return 0;
549
550 /* Self-originated packet should be discarded silently. */
551 if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
b245781a 552 || (IPV4_ADDR_SAME(&iph->ip_src, &ei->address.u.prefix4))) {
d62a17ae 553 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
554 zlog_debug(
555 "eigrp_read[%s]: Dropping self-originated packet",
556 inet_ntoa(iph->ip_src));
557 return 0;
558 }
559
560 /* Advance from IP header to EIGRP header (iph->ip_hl has been verified
561 by eigrp_recv_packet() to be correct). */
562
563 stream_forward_getp(ibuf, (iph->ip_hl * 4));
2d34fb80 564 eigrph = (struct eigrp_header *)stream_pnt(ibuf);
d62a17ae 565
566 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
567 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
568 eigrp_header_dump(eigrph);
569
570 // if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) -
571 // stream_get_getp(ibuf)))
572 // return -1;
573
d62a17ae 574 /* If incoming interface is passive one, ignore it. */
885c8244 575 if (eigrp_if_is_passive(ei)) {
d62a17ae 576 char buf[3][INET_ADDRSTRLEN];
577
578 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
579 zlog_debug(
580 "ignoring packet from router %s sent to %s, "
581 "received on a passive interface, %s",
582 inet_ntop(AF_INET, &eigrph->vrid, buf[0],
583 sizeof(buf[0])),
584 inet_ntop(AF_INET, &iph->ip_dst, buf[1],
585 sizeof(buf[1])),
b245781a 586 inet_ntop(AF_INET, &ei->address.u.prefix4,
d62a17ae 587 buf[2], sizeof(buf[2])));
588
589 if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) {
d62a17ae 590 eigrp_if_set_multicast(ei);
591 }
592 return 0;
593 }
594
595 /* else it must be a local eigrp interface, check it was received on
596 * correct link
597 */
598 else if (ei->ifp != ifp) {
599 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
600 zlog_warn("Packet from [%s] received on wrong link %s",
601 inet_ntoa(iph->ip_src), ifp->name);
602 return 0;
603 }
604
605 /* Verify more EIGRP header fields. */
606 ret = eigrp_verify_header(ibuf, ei, iph, eigrph);
607 if (ret < 0) {
608 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
609 zlog_debug(
610 "eigrp_read[%s]: Header check failed, dropping.",
611 inet_ntoa(iph->ip_src));
612 return ret;
613 }
614
615 /* calcualte the eigrp packet length, and move the pounter to the
616 start of the eigrp TLVs */
617 opcode = eigrph->opcode;
618
9c273c6d 619 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)) {
dbfd865b 620 char src[PREFIX_STRLEN], dst[PREFIX_STRLEN];
9c273c6d 621
21dfc9ed
DS
622 strlcpy(src, inet_ntoa(iph->ip_src), sizeof(src));
623 strlcpy(dst, inet_ntoa(iph->ip_dst), sizeof(dst));
996c9314
LB
624 zlog_debug(
625 "Received [%s][%d/%d] length [%u] via [%s] src [%s] dst [%s]",
626 lookup_msg(eigrp_packet_type_str, opcode, NULL),
627 ntohl(eigrph->sequence), ntohl(eigrph->ack), length,
628 IF_NAME(ei), src, dst);
9c273c6d 629 }
d62a17ae 630
631 /* Read rest of the packet and call each sort of packet routine. */
632 stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
633
634 /* New testing block of code for handling Acks */
635 if (ntohl(eigrph->ack) != 0) {
1a0770e3
DS
636 struct eigrp_packet *ep = NULL;
637
d62a17ae 638 nbr = eigrp_nbr_get(ei, eigrph, iph);
639
1a0770e3 640 // neighbor must be valid, eigrp_nbr_get creates if none existed
d62a17ae 641 assert(nbr);
642
f90f65a2 643 ep = eigrp_fifo_next(nbr->retrans_queue);
1a0770e3
DS
644 if ((ep) && (ntohl(eigrph->ack) == ep->sequence_number)) {
645 ep = eigrp_fifo_pop(nbr->retrans_queue);
646 eigrp_packet_free(ep);
647
648 if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
996c9314
LB
649 && (ntohl(eigrph->ack)
650 == nbr->init_sequence_number)) {
1a0770e3
DS
651 eigrp_nbr_state_set(nbr, EIGRP_NEIGHBOR_UP);
652 zlog_info("Neighbor(%s) adjacency became full",
653 inet_ntoa(nbr->src));
654 nbr->init_sequence_number = 0;
655 nbr->recv_sequence_number =
656 ntohl(eigrph->sequence);
657 eigrp_update_send_EOT(nbr);
996c9314 658 } else
1a0770e3 659 eigrp_send_packet_reliably(nbr);
d62a17ae 660 }
f90f65a2 661 ep = eigrp_fifo_next(nbr->multicast_queue);
d62a17ae 662 if (ep) {
663 if (ntohl(eigrph->ack) == ep->sequence_number) {
f90f65a2 664 ep = eigrp_fifo_pop(nbr->multicast_queue);
d62a17ae 665 eigrp_packet_free(ep);
666 if (nbr->multicast_queue->count > 0) {
667 eigrp_send_packet_reliably(nbr);
668 }
669 }
670 }
671 }
672
673
674 switch (opcode) {
675 case EIGRP_OPC_HELLO:
676 eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length);
677 break;
678 case EIGRP_OPC_PROBE:
679 // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei,
680 // length);
681 break;
682 case EIGRP_OPC_QUERY:
683 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
684 break;
685 case EIGRP_OPC_REPLY:
686 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
687 break;
688 case EIGRP_OPC_REQUEST:
689 // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei,
690 // length);
691 break;
692 case EIGRP_OPC_SIAQUERY:
693 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
694 break;
695 case EIGRP_OPC_SIAREPLY:
696 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
697 break;
698 case EIGRP_OPC_UPDATE:
699 eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length);
700 break;
701 default:
702 zlog_warn(
703 "interface %s: EIGRP packet header type %d unsupported",
704 IF_NAME(ei), opcode);
705 break;
706 }
707
708 return 0;
7f57883e
DS
709}
710
e78ebbd5
DS
711static struct stream *eigrp_recv_packet(struct eigrp *eigrp,
712 int fd, struct interface **ifp,
d62a17ae 713 struct stream *ibuf)
7f57883e 714{
d62a17ae 715 int ret;
716 struct ip *iph;
d7c0a89a 717 uint16_t ip_len;
d62a17ae 718 unsigned int ifindex = 0;
719 struct iovec iov;
720 /* Header and data both require alignment. */
721 char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
722 struct msghdr msgh;
723
724 memset(&msgh, 0, sizeof(struct msghdr));
725 msgh.msg_iov = &iov;
726 msgh.msg_iovlen = 1;
727 msgh.msg_control = (caddr_t)buff;
728 msgh.msg_controllen = sizeof(buff);
729
730 ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1));
731 if (ret < 0) {
732 zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
733 return NULL;
734 }
885c8244 735 if ((unsigned int)ret < sizeof(*iph)) /* ret must be > 0 now */
d62a17ae 736 {
737 zlog_warn(
738 "eigrp_recv_packet: discarding runt packet of length %d "
739 "(ip header size is %u)",
885c8244 740 ret, (unsigned int)sizeof(*iph));
d62a17ae 741 return NULL;
742 }
743
744 /* Note that there should not be alignment problems with this assignment
745 because this is at the beginning of the stream data buffer. */
746 iph = (struct ip *)STREAM_DATA(ibuf);
747 sockopt_iphdrincl_swab_systoh(iph);
748
749 ip_len = iph->ip_len;
750
751#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
752 /*
753 * Kernel network code touches incoming IP header parameters,
754 * before protocol specific processing.
755 *
756 * 1) Convert byteorder to host representation.
757 * --> ip_len, ip_id, ip_off
758 *
759 * 2) Adjust ip_len to strip IP header size!
760 * --> If user process receives entire IP packet via RAW
761 * socket, it must consider adding IP header size to
762 * the "ip_len" field of "ip" structure.
763 *
764 * For more details, see <netinet/ip_input.c>.
765 */
766 ip_len = ip_len + (iph->ip_hl << 2);
7f57883e
DS
767#endif
768
d62a17ae 769#if defined(__DragonFly__)
770 /*
771 * in DragonFly's raw socket, ip_len/ip_off are read
772 * in network byte order.
773 * As OpenBSD < 200311 adjust ip_len to strip IP header size!
774 */
775 ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
7f57883e
DS
776#endif
777
d62a17ae 778 ifindex = getsockopt_ifindex(AF_INET, &msgh);
7f57883e 779
e78ebbd5 780 *ifp = if_lookup_by_index(ifindex, eigrp->vrf_id);
7f57883e 781
d62a17ae 782 if (ret != ip_len) {
783 zlog_warn(
784 "eigrp_recv_packet read length mismatch: ip_len is %d, "
785 "but recvmsg returned %d",
786 ip_len, ret);
787 return NULL;
788 }
7f57883e 789
d62a17ae 790 return ibuf;
7f57883e
DS
791}
792
d62a17ae 793struct eigrp_fifo *eigrp_fifo_new(void)
7f57883e 794{
d62a17ae 795 struct eigrp_fifo *new;
7f57883e 796
d62a17ae 797 new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
798 return new;
7f57883e
DS
799}
800
801/* Free eigrp packet fifo. */
d62a17ae 802void eigrp_fifo_free(struct eigrp_fifo *fifo)
7f57883e 803{
d62a17ae 804 struct eigrp_packet *ep;
805 struct eigrp_packet *next;
806
807 for (ep = fifo->head; ep; ep = next) {
808 next = ep->next;
809 eigrp_packet_free(ep);
810 }
811 fifo->head = fifo->tail = NULL;
812 fifo->count = 0;
813
814 XFREE(MTYPE_EIGRP_FIFO, fifo);
7f57883e
DS
815}
816
817/* Free eigrp fifo entries without destroying fifo itself*/
d62a17ae 818void eigrp_fifo_reset(struct eigrp_fifo *fifo)
7f57883e 819{
d62a17ae 820 struct eigrp_packet *ep;
821 struct eigrp_packet *next;
822
823 for (ep = fifo->head; ep; ep = next) {
824 next = ep->next;
825 eigrp_packet_free(ep);
826 }
827 fifo->head = fifo->tail = NULL;
828 fifo->count = 0;
7f57883e
DS
829}
830
907b4303 831struct eigrp_packet *eigrp_packet_new(size_t size, struct eigrp_neighbor *nbr)
7f57883e 832{
d62a17ae 833 struct eigrp_packet *new;
7f57883e 834
d62a17ae 835 new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
836 new->s = stream_new(size);
837 new->retrans_counter = 0;
907b4303 838 new->nbr = nbr;
7f57883e 839
d62a17ae 840 return new;
7f57883e
DS
841}
842
d62a17ae 843void eigrp_send_packet_reliably(struct eigrp_neighbor *nbr)
7f57883e 844{
d62a17ae 845 struct eigrp_packet *ep;
846
f90f65a2 847 ep = eigrp_fifo_next(nbr->retrans_queue);
d62a17ae 848
849 if (ep) {
850 struct eigrp_packet *duplicate;
851 duplicate = eigrp_packet_duplicate(ep, nbr);
852 /* Add packet to the top of the interface output queue*/
f90f65a2 853 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 854
855 /*Start retransmission timer*/
856 thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
857 EIGRP_PACKET_RETRANS_TIME,
858 &ep->t_retrans_timer);
859
860 /*Increment sequence number counter*/
861 nbr->ei->eigrp->sequence_number++;
862
863 /* Hook thread to write packet. */
864 if (nbr->ei->on_write_q == 0) {
865 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
866 nbr->ei->on_write_q = 1;
867 }
868 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
869 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
870 }
7f57883e
DS
871}
872
873/* Calculate EIGRP checksum */
d62a17ae 874void eigrp_packet_checksum(struct eigrp_interface *ei, struct stream *s,
d7c0a89a 875 uint16_t length)
7f57883e 876{
d62a17ae 877 struct eigrp_header *eigrph;
7f57883e 878
d62a17ae 879 eigrph = (struct eigrp_header *)STREAM_DATA(s);
7f57883e 880
d62a17ae 881 /* Calculate checksum. */
882 eigrph->checksum = in_cksum(eigrph, length);
7f57883e
DS
883}
884
885/* Make EIGRP header. */
996c9314 886void eigrp_packet_header_init(int type, struct eigrp *eigrp, struct stream *s,
d7c0a89a 887 uint32_t flags, uint32_t sequence, uint32_t ack)
7f57883e 888{
d62a17ae 889 struct eigrp_header *eigrph;
7f57883e 890
7ecf0a4d 891 stream_reset(s);
d62a17ae 892 eigrph = (struct eigrp_header *)STREAM_DATA(s);
7f57883e 893
d7c0a89a
QY
894 eigrph->version = (uint8_t)EIGRP_HEADER_VERSION;
895 eigrph->opcode = (uint8_t)type;
d62a17ae 896 eigrph->checksum = 0;
7f57883e 897
cf2f4dae
DS
898 eigrph->vrid = htons(eigrp->vrid);
899 eigrph->ASNumber = htons(eigrp->AS);
d62a17ae 900 eigrph->ack = htonl(ack);
901 eigrph->sequence = htonl(sequence);
902 // if(flags == EIGRP_INIT_FLAG)
903 // eigrph->sequence = htonl(3);
904 eigrph->flags = htonl(flags);
7f57883e 905
0f6c16fb 906 if (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
d62a17ae 907 zlog_debug("Packet Header Init Seq [%u] Ack [%u]",
908 htonl(eigrph->sequence), htonl(eigrph->ack));
7f57883e 909
d62a17ae 910 stream_forward_endp(s, EIGRP_HEADER_LEN);
7f57883e
DS
911}
912
913/* Add new packet to head of fifo. */
f90f65a2 914void eigrp_fifo_push(struct eigrp_fifo *fifo, struct eigrp_packet *ep)
7f57883e 915{
d62a17ae 916 ep->next = fifo->head;
917 ep->previous = NULL;
7f57883e 918
d62a17ae 919 if (fifo->tail == NULL)
920 fifo->tail = ep;
7f57883e 921
d62a17ae 922 if (fifo->count != 0)
923 fifo->head->previous = ep;
7f57883e 924
d62a17ae 925 fifo->head = ep;
7f57883e 926
d62a17ae 927 fifo->count++;
7f57883e
DS
928}
929
7f57883e 930/* Return last fifo entry. */
f90f65a2 931struct eigrp_packet *eigrp_fifo_next(struct eigrp_fifo *fifo)
7f57883e 932{
d62a17ae 933 return fifo->tail;
7f57883e
DS
934}
935
d62a17ae 936void eigrp_packet_delete(struct eigrp_interface *ei)
7f57883e 937{
d62a17ae 938 struct eigrp_packet *ep;
7f57883e 939
d62a17ae 940 ep = eigrp_fifo_pop(ei->obuf);
7f57883e 941
d62a17ae 942 if (ep)
943 eigrp_packet_free(ep);
7f57883e
DS
944}
945
d62a17ae 946void eigrp_packet_free(struct eigrp_packet *ep)
7f57883e 947{
d62a17ae 948 if (ep->s)
949 stream_free(ep->s);
7f57883e 950
d62a17ae 951 THREAD_OFF(ep->t_retrans_timer);
7f57883e 952
d62a17ae 953 XFREE(MTYPE_EIGRP_PACKET, ep);
7f57883e
DS
954}
955
956/* EIGRP Header verification. */
d62a17ae 957static int eigrp_verify_header(struct stream *ibuf, struct eigrp_interface *ei,
958 struct ip *iph, struct eigrp_header *eigrph)
7f57883e 959{
d62a17ae 960 /* Check network mask, Silently discarded. */
961 if (!eigrp_check_network_mask(ei, iph->ip_src)) {
962 zlog_warn(
963 "interface %s: eigrp_read network address is not same [%s]",
964 IF_NAME(ei), inet_ntoa(iph->ip_src));
965 return -1;
966 }
967 //
968 // /* Check authentication. The function handles logging actions, where
969 // required. */
970 // if (! eigrp_check_auth(ei, eigrph))
971 // return -1;
972
973 return 0;
7f57883e
DS
974}
975
976/* Unbound socket will accept any Raw IP packets if proto is matched.
f9e5c9ca
DS
977 To prevent it, compare src IP address and i/f address with masking
978 i/f network mask. */
d62a17ae 979static int eigrp_check_network_mask(struct eigrp_interface *ei,
980 struct in_addr ip_src)
7f57883e 981{
d62a17ae 982 struct in_addr mask, me, him;
7f57883e 983
d62a17ae 984 if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
985 return 1;
7f57883e 986
b245781a 987 masklen2ip(ei->address.prefixlen, &mask);
7f57883e 988
b245781a 989 me.s_addr = ei->address.u.prefix4.s_addr & mask.s_addr;
d62a17ae 990 him.s_addr = ip_src.s_addr & mask.s_addr;
7f57883e 991
d62a17ae 992 if (IPV4_ADDR_SAME(&me, &him))
993 return 1;
7f57883e 994
d62a17ae 995 return 0;
7f57883e
DS
996}
997
d62a17ae 998int eigrp_unack_packet_retrans(struct thread *thread)
7f57883e 999{
d62a17ae 1000 struct eigrp_neighbor *nbr;
1001 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
1002
1003 struct eigrp_packet *ep;
f90f65a2 1004 ep = eigrp_fifo_next(nbr->retrans_queue);
d62a17ae 1005
1006 if (ep) {
1007 struct eigrp_packet *duplicate;
1008 duplicate = eigrp_packet_duplicate(ep, nbr);
1009
1010 /* Add packet to the top of the interface output queue*/
f90f65a2 1011 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 1012
1013 ep->retrans_counter++;
1014 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1015 return eigrp_retrans_count_exceeded(ep, nbr);
1016
1017 /*Start retransmission timer*/
1018 ep->t_retrans_timer = NULL;
1019 thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
1020 EIGRP_PACKET_RETRANS_TIME,
1021 &ep->t_retrans_timer);
1022
1023 /* Hook thread to write packet. */
1024 if (nbr->ei->on_write_q == 0) {
1025 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1026 nbr->ei->on_write_q = 1;
1027 }
1028 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1029 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1030 }
1031
1032 return 0;
7f57883e
DS
1033}
1034
d62a17ae 1035int eigrp_unack_multicast_packet_retrans(struct thread *thread)
7f57883e 1036{
d62a17ae 1037 struct eigrp_neighbor *nbr;
1038 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
1039
1040 struct eigrp_packet *ep;
f90f65a2 1041 ep = eigrp_fifo_next(nbr->multicast_queue);
d62a17ae 1042
1043 if (ep) {
1044 struct eigrp_packet *duplicate;
1045 duplicate = eigrp_packet_duplicate(ep, nbr);
1046 /* Add packet to the top of the interface output queue*/
f90f65a2 1047 eigrp_fifo_push(nbr->ei->obuf, duplicate);
d62a17ae 1048
1049 ep->retrans_counter++;
1050 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1051 return eigrp_retrans_count_exceeded(ep, nbr);
1052
1053 /*Start retransmission timer*/
1054 ep->t_retrans_timer = NULL;
1055 thread_add_timer(master, eigrp_unack_multicast_packet_retrans,
1056 nbr, EIGRP_PACKET_RETRANS_TIME,
1057 &ep->t_retrans_timer);
1058
1059 /* Hook thread to write packet. */
1060 if (nbr->ei->on_write_q == 0) {
1061 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1062 nbr->ei->on_write_q = 1;
1063 }
1064 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1065 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1066 }
1067
1068 return 0;
7f57883e
DS
1069}
1070
1071/* Get packet from tail of fifo. */
f90f65a2 1072struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo)
7f57883e 1073{
1a0770e3 1074 struct eigrp_packet *ep = NULL;
7f57883e 1075
d62a17ae 1076 ep = fifo->tail;
7f57883e 1077
d62a17ae 1078 if (ep) {
1079 fifo->tail = ep->previous;
7f57883e 1080
d62a17ae 1081 if (fifo->tail == NULL)
1082 fifo->head = NULL;
1083 else
1084 fifo->tail->next = NULL;
7f57883e 1085
d62a17ae 1086 fifo->count--;
1087 }
7f57883e 1088
d62a17ae 1089 return ep;
7f57883e
DS
1090}
1091
d62a17ae 1092struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
1093 struct eigrp_neighbor *nbr)
7f57883e 1094{
d62a17ae 1095 struct eigrp_packet *new;
7f57883e 1096
9378632f 1097 new = eigrp_packet_new(EIGRP_PACKET_MTU(nbr->ei->ifp->mtu), nbr);
d62a17ae 1098 new->length = old->length;
1099 new->retrans_counter = old->retrans_counter;
1100 new->dst = old->dst;
1101 new->sequence_number = old->sequence_number;
1102 stream_copy(new->s, old->s);
7f57883e 1103
d62a17ae 1104 return new;
7f57883e
DS
1105}
1106
4d762f26 1107static struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new(void)
5ca6df78
DS
1108{
1109 struct TLV_IPv4_Internal_type *new;
1110
1111 new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,
1112 sizeof(struct TLV_IPv4_Internal_type));
1113
1114 return new;
1115}
1116
d62a17ae 1117struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
7f57883e 1118{
d62a17ae 1119 struct TLV_IPv4_Internal_type *tlv;
e296eae4 1120 uint32_t destination_tmp;
d62a17ae 1121
1122 tlv = eigrp_IPv4_InternalTLV_new();
1123
1124 tlv->type = stream_getw(s);
1125 tlv->length = stream_getw(s);
1126 tlv->forward.s_addr = stream_getl(s);
1127 tlv->metric.delay = stream_getl(s);
b1968f83 1128 tlv->metric.bandwidth = stream_getl(s);
d62a17ae 1129 tlv->metric.mtu[0] = stream_getc(s);
1130 tlv->metric.mtu[1] = stream_getc(s);
1131 tlv->metric.mtu[2] = stream_getc(s);
1132 tlv->metric.hop_count = stream_getc(s);
1133 tlv->metric.reliability = stream_getc(s);
1134 tlv->metric.load = stream_getc(s);
1135 tlv->metric.tag = stream_getc(s);
1136 tlv->metric.flags = stream_getc(s);
1137
1138 tlv->prefix_length = stream_getc(s);
1139
e296eae4
PD
1140 destination_tmp = stream_getc(s) << 24;
1141 if (tlv->prefix_length > 8)
1142 destination_tmp |= stream_getc(s) << 16;
1143 if (tlv->prefix_length > 16)
1144 destination_tmp |= stream_getc(s) << 8;
1145 if (tlv->prefix_length > 24)
1146 destination_tmp |= stream_getc(s);
1147
1148 tlv->destination.s_addr = htonl(destination_tmp);
1149
d62a17ae 1150 return tlv;
7f57883e
DS
1151}
1152
d7c0a89a
QY
1153uint16_t eigrp_add_internalTLV_to_stream(struct stream *s,
1154 struct eigrp_prefix_entry *pe)
7f57883e 1155{
d7c0a89a 1156 uint16_t length;
d62a17ae 1157
1158 stream_putw(s, EIGRP_TLV_IPv4_INT);
03161b73
DS
1159 switch (pe->destination->prefixlen) {
1160 case 0:
1161 case 1:
1162 case 2:
1163 case 3:
1164 case 4:
1165 case 5:
1166 case 6:
1167 case 7:
1168 case 8:
1169 length = EIGRP_TLV_IPV4_SIZE_GRT_0_BIT;
1170 stream_putw(s, length);
1171 break;
1172 case 9:
1173 case 10:
1174 case 11:
1175 case 12:
1176 case 13:
1177 case 14:
1178 case 15:
1179 case 16:
1180 length = EIGRP_TLV_IPV4_SIZE_GRT_8_BIT;
1181 stream_putw(s, length);
1182 break;
1183 case 17:
1184 case 18:
1185 case 19:
1186 case 20:
1187 case 21:
1188 case 22:
1189 case 23:
1190 case 24:
1191 length = EIGRP_TLV_IPV4_SIZE_GRT_16_BIT;
1192 stream_putw(s, length);
1193 break;
1194 case 25:
1195 case 26:
1196 case 27:
1197 case 28:
1198 case 29:
1199 case 30:
1200 case 31:
1201 case 32:
1202 length = EIGRP_TLV_IPV4_SIZE_GRT_24_BIT;
1203 stream_putw(s, length);
1204 break;
1205 default:
1c50c1c0
QY
1206 flog_err(EC_LIB_DEVELOPMENT, "%s: Unexpected prefix length: %d",
1207 __PRETTY_FUNCTION__, pe->destination->prefixlen);
03161b73 1208 return 0;
d62a17ae 1209 }
d62a17ae 1210 stream_putl(s, 0x00000000);
1211
1212 /*Metric*/
1213 stream_putl(s, pe->reported_metric.delay);
b1968f83 1214 stream_putl(s, pe->reported_metric.bandwidth);
d62a17ae 1215 stream_putc(s, pe->reported_metric.mtu[2]);
1216 stream_putc(s, pe->reported_metric.mtu[1]);
1217 stream_putc(s, pe->reported_metric.mtu[0]);
1218 stream_putc(s, pe->reported_metric.hop_count);
1219 stream_putc(s, pe->reported_metric.reliability);
1220 stream_putc(s, pe->reported_metric.load);
1221 stream_putc(s, pe->reported_metric.tag);
1222 stream_putc(s, pe->reported_metric.flags);
1223
02b45998 1224 stream_putc(s, pe->destination->prefixlen);
d62a17ae 1225
e296eae4 1226 stream_putc(s, (ntohl(pe->destination->u.prefix4.s_addr) >> 24) & 0xFF);
02b45998 1227 if (pe->destination->prefixlen > 8)
e296eae4 1228 stream_putc(s, (ntohl(pe->destination->u.prefix4.s_addr) >> 16) & 0xFF);
02b45998 1229 if (pe->destination->prefixlen > 16)
e296eae4 1230 stream_putc(s, (ntohl(pe->destination->u.prefix4.s_addr) >> 8) & 0xFF);
02b45998 1231 if (pe->destination->prefixlen > 24)
e296eae4 1232 stream_putc(s, ntohl(pe->destination->u.prefix4.s_addr) & 0xFF);
d62a17ae 1233
1234 return length;
7f57883e
DS
1235}
1236
d7c0a89a
QY
1237uint16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
1238 struct eigrp_interface *ei)
7f57883e 1239{
d62a17ae 1240 struct key *key;
1241 struct keychain *keychain;
1242 struct TLV_MD5_Authentication_Type *authTLV;
1243
1244 authTLV = eigrp_authTLV_MD5_new();
1245
1246 authTLV->type = htons(EIGRP_TLV_AUTH);
1247 authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
1248 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
1249 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
1250 authTLV->key_sequence = 0;
1251 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1252
b748db67 1253 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 1254 if (keychain)
1255 key = key_lookup_for_send(keychain);
1256 else {
b748db67
DS
1257 free(ei->params.auth_keychain);
1258 ei->params.auth_keychain = NULL;
d62a17ae 1259 eigrp_authTLV_MD5_free(authTLV);
1260 return 0;
1261 }
1262
1263 if (key) {
1264 authTLV->key_id = htonl(key->index);
1265 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
1266 stream_put(s, authTLV,
1267 sizeof(struct TLV_MD5_Authentication_Type));
1268 eigrp_authTLV_MD5_free(authTLV);
1269 return EIGRP_AUTH_MD5_TLV_SIZE;
1270 }
1271
1272 eigrp_authTLV_MD5_free(authTLV);
1273
1274 return 0;
7f57883e
DS
1275}
1276
d7c0a89a
QY
1277uint16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
1278 struct eigrp_interface *ei)
7f57883e 1279{
d62a17ae 1280 struct key *key;
1281 struct keychain *keychain;
1282 struct TLV_SHA256_Authentication_Type *authTLV;
1283
1284 authTLV = eigrp_authTLV_SHA256_new();
1285
1286 authTLV->type = htons(EIGRP_TLV_AUTH);
1287 authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
1288 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
1289 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
1290 authTLV->key_sequence = 0;
1291 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1292
b748db67 1293 keychain = keychain_lookup(ei->params.auth_keychain);
d62a17ae 1294 if (keychain)
1295 key = key_lookup_for_send(keychain);
1296 else {
b748db67
DS
1297 free(ei->params.auth_keychain);
1298 ei->params.auth_keychain = NULL;
d62a17ae 1299 eigrp_authTLV_SHA256_free(authTLV);
1300 return 0;
1301 }
1302
1303 if (key) {
1304 authTLV->key_id = 0;
1305 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_SHA256_LEN);
1306 stream_put(s, authTLV,
1307 sizeof(struct TLV_SHA256_Authentication_Type));
1308 eigrp_authTLV_SHA256_free(authTLV);
1309 return EIGRP_AUTH_SHA256_TLV_SIZE;
1310 }
1311
1312 eigrp_authTLV_SHA256_free(authTLV);
1313
1314 return 0;
7f57883e
DS
1315}
1316
4d762f26 1317struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new(void)
7f57883e 1318{
d62a17ae 1319 struct TLV_MD5_Authentication_Type *new;
7f57883e 1320
d62a17ae 1321 new = XCALLOC(MTYPE_EIGRP_AUTH_TLV,
1322 sizeof(struct TLV_MD5_Authentication_Type));
7f57883e 1323
d62a17ae 1324 return new;
7f57883e
DS
1325}
1326
d62a17ae 1327void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV)
7f57883e 1328{
d62a17ae 1329 XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
7f57883e
DS
1330}
1331
4d762f26 1332struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new(void)
7f57883e 1333{
d62a17ae 1334 struct TLV_SHA256_Authentication_Type *new;
7f57883e 1335
d62a17ae 1336 new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV,
1337 sizeof(struct TLV_SHA256_Authentication_Type));
7f57883e 1338
d62a17ae 1339 return new;
7f57883e
DS
1340}
1341
d62a17ae 1342void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV)
7f57883e 1343{
d62a17ae 1344 XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
7f57883e
DS
1345}
1346
d62a17ae 1347void eigrp_IPv4_InternalTLV_free(
1348 struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
7f57883e 1349{
d62a17ae 1350 XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
7f57883e
DS
1351}
1352
4d762f26 1353struct TLV_Sequence_Type *eigrp_SequenceTLV_new(void)
7f57883e 1354{
d62a17ae 1355 struct TLV_Sequence_Type *new;
7f57883e 1356
d62a17ae 1357 new = XCALLOC(MTYPE_EIGRP_SEQ_TLV, sizeof(struct TLV_Sequence_Type));
7f57883e 1358
d62a17ae 1359 return new;
7f57883e 1360}