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