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