]> git.proxmox.com Git - mirror_frr.git/blame - eigrpd/eigrp_packet.c
eigrpd: Fix a md5 digest issue
[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
7f57883e
DS
302/*
303 * eigrp_packet_dump
304 *
305 * This routing dumps the contents of the IP packet either received or
306 * built by EIGRP.
307 */
d62a17ae 308static void eigrp_packet_dump(struct stream *s)
7f57883e 309{
d62a17ae 310 // not yet...
311 return;
7f57883e
DS
312}
313
d62a17ae 314int eigrp_write(struct thread *thread)
7f57883e 315{
d62a17ae 316 struct eigrp *eigrp = THREAD_ARG(thread);
317 struct eigrp_header *eigrph;
318 struct eigrp_interface *ei;
319 struct eigrp_packet *ep;
320 struct sockaddr_in sa_dst;
321 struct ip iph;
322 struct msghdr msg;
323 struct iovec iov[2];
324 u_int16_t opcode = 0;
325
326 int ret;
327 int flags = 0;
328 struct listnode *node;
7f57883e 329#ifdef WANT_EIGRP_WRITE_FRAGMENT
d62a17ae 330 static u_int16_t ipid = 0;
9d303b37
DL
331#endif /* WANT_EIGRP_WRITE_FRAGMENT */
332 /* $FRR indent$ */
333/* clang-format off */
7f57883e
DS
334#define EIGRP_WRITE_IPHL_SHIFT 2
335
d62a17ae 336 eigrp->t_write = NULL;
7f57883e 337
d62a17ae 338 node = listhead(eigrp->oi_write_q);
339 assert(node);
340 ei = listgetdata(node);
341 assert(ei);
7f57883e
DS
342
343#ifdef WANT_EIGRP_WRITE_FRAGMENT
d62a17ae 344 /* seed ipid static with low order bits of time */
345 if (ipid == 0)
346 ipid = (time(NULL) & 0xffff);
7f57883e
DS
347#endif /* WANT_EIGRP_WRITE_FRAGMENT */
348
d62a17ae 349 /* Get one packet from queue. */
350 ep = eigrp_fifo_head(ei->obuf);
351 assert(ep);
352 assert(ep->length >= EIGRP_HEADER_LEN);
7f57883e 353
d62a17ae 354 if (ep->dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS))
355 eigrp_if_ipmulticast(eigrp, ei->address, ei->ifp->ifindex);
7f57883e 356
d62a17ae 357 memset(&iph, 0, sizeof(struct ip));
358 memset(&sa_dst, 0, sizeof(sa_dst));
7f57883e 359
d62a17ae 360 sa_dst.sin_family = AF_INET;
7f57883e 361#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
d62a17ae 362 sa_dst.sin_len = sizeof(sa_dst);
7f57883e 363#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */
d62a17ae 364 sa_dst.sin_addr = ep->dst;
365 sa_dst.sin_port = htons(0);
366
367 /* Set DONTROUTE flag if dst is unicast. */
368 if (!IN_MULTICAST(htonl(ep->dst.s_addr)))
369 flags = MSG_DONTROUTE;
370
371 iph.ip_hl = sizeof(struct ip) >> EIGRP_WRITE_IPHL_SHIFT;
372 /* it'd be very strange for header to not be 4byte-word aligned but.. */
373 if (sizeof(struct ip)
374 > (unsigned int)(iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT))
375 iph.ip_hl++; /* we presume sizeof struct ip cant overflow
376 ip_hl.. */
377
378 iph.ip_v = IPVERSION;
379 iph.ip_tos = IPTOS_PREC_INTERNETCONTROL;
380 iph.ip_len = (iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT) + ep->length;
381
382#if defined(__DragonFly__)
383 /*
384 * DragonFly's raw socket expects ip_len/ip_off in network byte order.
385 */
386 iph.ip_len = htons(iph.ip_len);
7f57883e
DS
387#endif
388
d62a17ae 389 iph.ip_off = 0;
390 iph.ip_ttl = EIGRP_IP_TTL;
391 iph.ip_p = IPPROTO_EIGRPIGP;
392 iph.ip_sum = 0;
393 iph.ip_src.s_addr = ei->address->u.prefix4.s_addr;
394 iph.ip_dst.s_addr = ep->dst.s_addr;
395
396 memset(&msg, 0, sizeof(msg));
397 msg.msg_name = (caddr_t)&sa_dst;
398 msg.msg_namelen = sizeof(sa_dst);
399 msg.msg_iov = iov;
400 msg.msg_iovlen = 2;
401
402 iov[0].iov_base = (char *)&iph;
403 iov[0].iov_len = iph.ip_hl << EIGRP_WRITE_IPHL_SHIFT;
404 iov[1].iov_base = STREAM_PNT(ep->s);
405 iov[1].iov_len = ep->length;
406
407 /* send final fragment (could be first) */
408 sockopt_iphdrincl_swab_htosys(&iph);
409 ret = sendmsg(eigrp->fd, &msg, flags);
410 sockopt_iphdrincl_swab_systoh(&iph);
411
412 if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)) {
413 eigrph = (struct eigrp_header *)STREAM_DATA(ep->s);
414 opcode = eigrph->opcode;
415 zlog_debug("Sending [%s] to [%s] via [%s] ret [%d].",
416 lookup_msg(eigrp_packet_type_str, opcode, NULL),
417 inet_ntoa(ep->dst), IF_NAME(ei), ret);
418 }
419
420 if (ret < 0)
421 zlog_warn(
422 "*** sendmsg in eigrp_write failed to %s, "
423 "id %d, off %d, len %d, interface %s, mtu %u: %s",
424 inet_ntoa(iph.ip_dst), iph.ip_id, iph.ip_off,
425 iph.ip_len, ei->ifp->name, ei->ifp->mtu,
426 safe_strerror(errno));
427
428 /* Show debug sending packet. */
429 if (IS_DEBUG_EIGRP_TRANSMIT(0, SEND)
430 && (IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))) {
431 zlog_debug(
432 "-----------------------------------------------------");
433 eigrp_ip_header_dump(&iph);
434 stream_set_getp(ep->s, 0);
435 eigrp_packet_dump(ep->s);
436 zlog_debug(
437 "-----------------------------------------------------");
438 }
439
440 /* Now delete packet from queue. */
441 eigrp_packet_delete(ei);
442
443 if (eigrp_fifo_head(ei->obuf) == NULL) {
444 ei->on_write_q = 0;
445 list_delete_node(eigrp->oi_write_q, node);
446 }
447
448 /* If packets still remain in queue, call write thread. */
449 if (!list_isempty(eigrp->oi_write_q)) {
450 eigrp->t_write = NULL;
451 thread_add_write(master, eigrp_write, eigrp, eigrp->fd,
452 &eigrp->t_write);
453 }
454
455 return 0;
7f57883e
DS
456}
457
458/* Starting point of packet process function. */
d62a17ae 459int eigrp_read(struct thread *thread)
7f57883e 460{
d62a17ae 461 int ret;
462 struct stream *ibuf;
463 struct eigrp *eigrp;
464 struct eigrp_interface *ei;
465 struct ip *iph;
466 struct eigrp_header *eigrph;
467 struct interface *ifp;
468 struct eigrp_neighbor *nbr;
469
470 u_int16_t opcode = 0;
471 u_int16_t length = 0;
472
473 /* first of all get interface pointer. */
474 eigrp = THREAD_ARG(thread);
475
476 /* prepare for next packet. */
477 eigrp->t_read = NULL;
478 thread_add_read(master, eigrp_read, eigrp, eigrp->fd, &eigrp->t_read);
479
480 stream_reset(eigrp->ibuf);
481 if (!(ibuf = eigrp_recv_packet(eigrp->fd, &ifp, eigrp->ibuf))) {
482 /* This raw packet is known to be at least as big as its IP
483 * header. */
484 return -1;
485 }
486
487 /* Note that there should not be alignment problems with this assignment
488 because this is at the beginning of the stream data buffer. */
489 iph = (struct ip *)STREAM_DATA(ibuf);
490
491 // Substract IPv4 header size from EIGRP Packet itself
492 if (iph->ip_v == 4)
493 length = (iph->ip_len) - 20U;
494
495
496 /* IP Header dump. */
497 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
498 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
499 eigrp_ip_header_dump(iph);
500
501 /* Note that sockopt_iphdrincl_swab_systoh was called in
502 * eigrp_recv_packet. */
503 if (ifp == NULL) {
504 struct connected *c;
505 /* Handle cases where the platform does not support retrieving
506 the ifindex,
507 and also platforms (such as Solaris 8) that claim to support
508 ifindex
509 retrieval but do not. */
510 c = if_lookup_address((void *)&iph->ip_src, AF_INET,
511 VRF_DEFAULT);
512
513 if (c == NULL)
514 return 0;
515
516 ifp = c->ifp;
517 }
518
519 /* associate packet with eigrp interface */
520 ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
521
522 /* eigrp_verify_header() relies on a valid "ei" and thus can be called
523 only
524 after the checks below are passed. These checks in turn access the
525 fields of unverified "eigrph" structure for their own purposes and
526 must remain very accurate in doing this.
527 */
528 if (!ei)
529 return 0;
530
531 /* Self-originated packet should be discarded silently. */
532 if (eigrp_if_lookup_by_local_addr(eigrp, NULL, iph->ip_src)
533 || (IPV4_ADDR_SAME(&iph->ip_src.s_addr, &ei->address->u.prefix4))) {
534 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
535 zlog_debug(
536 "eigrp_read[%s]: Dropping self-originated packet",
537 inet_ntoa(iph->ip_src));
538 return 0;
539 }
540
541 /* Advance from IP header to EIGRP header (iph->ip_hl has been verified
542 by eigrp_recv_packet() to be correct). */
543
544 stream_forward_getp(ibuf, (iph->ip_hl * 4));
545 eigrph = (struct eigrp_header *)STREAM_PNT(ibuf);
546
547 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV)
548 && IS_DEBUG_EIGRP_TRANSMIT(0, PACKET_DETAIL))
549 eigrp_header_dump(eigrph);
550
551 // if (MSG_OK != eigrp_packet_examin(eigrph, stream_get_endp(ibuf) -
552 // stream_get_getp(ibuf)))
553 // return -1;
554
555 /* Now it is safe to access all fields of EIGRP packet header. */
556 /* associate packet with eigrp interface */
557 ei = eigrp_if_lookup_recv_if(eigrp, iph->ip_src, ifp);
558
559 /* eigrp_verify_header() relies on a valid "ei" and thus can be called
560 only
561 after the checks below are passed. These checks in turn access the
562 fields of unverified "eigrph" structure for their own purposes and
563 must remain very accurate in doing this.
564 */
565 if (!ei)
566 return 0;
567
568 /* If incoming interface is passive one, ignore it. */
569 if (ei && EIGRP_IF_PASSIVE_STATUS(ei) == EIGRP_IF_PASSIVE) {
570 char buf[3][INET_ADDRSTRLEN];
571
572 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
573 zlog_debug(
574 "ignoring packet from router %s sent to %s, "
575 "received on a passive interface, %s",
576 inet_ntop(AF_INET, &eigrph->vrid, buf[0],
577 sizeof(buf[0])),
578 inet_ntop(AF_INET, &iph->ip_dst, buf[1],
579 sizeof(buf[1])),
580 inet_ntop(AF_INET, &ei->address->u.prefix4,
581 buf[2], sizeof(buf[2])));
582
583 if (iph->ip_dst.s_addr == htonl(EIGRP_MULTICAST_ADDRESS)) {
584 /* Try to fix multicast membership.
585 * Some OS:es may have problems in this area,
586 * make sure it is removed.
587 */
588 EI_MEMBER_JOINED(ei, MEMBER_ALLROUTERS);
589 eigrp_if_set_multicast(ei);
590 }
591 return 0;
592 }
593
594 /* else it must be a local eigrp interface, check it was received on
595 * correct link
596 */
597 else if (ei->ifp != ifp) {
598 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
599 zlog_warn("Packet from [%s] received on wrong link %s",
600 inet_ntoa(iph->ip_src), ifp->name);
601 return 0;
602 }
603
604 /* Verify more EIGRP header fields. */
605 ret = eigrp_verify_header(ibuf, ei, iph, eigrph);
606 if (ret < 0) {
607 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
608 zlog_debug(
609 "eigrp_read[%s]: Header check failed, dropping.",
610 inet_ntoa(iph->ip_src));
611 return ret;
612 }
613
614 /* calcualte the eigrp packet length, and move the pounter to the
615 start of the eigrp TLVs */
616 opcode = eigrph->opcode;
617
618 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
619 zlog_debug(
620 "Received [%s] length [%u] via [%s] src [%s] dst [%s]",
621 lookup_msg(eigrp_packet_type_str, opcode, NULL), length,
622 IF_NAME(ei), inet_ntoa(iph->ip_src),
623 inet_ntoa(iph->ip_dst));
624
625 /* Read rest of the packet and call each sort of packet routine. */
626 stream_forward_getp(ibuf, EIGRP_HEADER_LEN);
627
628 /* New testing block of code for handling Acks */
629 if (ntohl(eigrph->ack) != 0) {
630 nbr = eigrp_nbr_get(ei, eigrph, iph);
631
632 /* neighbor must be valid, eigrp_nbr_get creates if none existed
633 */
634 assert(nbr);
635
636 struct eigrp_packet *ep;
637
638 ep = eigrp_fifo_tail(nbr->retrans_queue);
639 if (ep) {
640 if (ntohl(eigrph->ack) == ep->sequence_number) {
641 if ((nbr->state == EIGRP_NEIGHBOR_PENDING)
642 && (ntohl(eigrph->ack)
643 == nbr->init_sequence_number)) {
644 eigrp_nbr_state_set(nbr,
645 EIGRP_NEIGHBOR_UP);
646 zlog_info(
647 "Neighbor adjacency became full");
648 nbr->init_sequence_number = 0;
649 nbr->recv_sequence_number =
650 ntohl(eigrph->sequence);
651 eigrp_update_send_EOT(nbr);
652 }
653 ep = eigrp_fifo_pop_tail(nbr->retrans_queue);
654 eigrp_packet_free(ep);
655 if (nbr->retrans_queue->count > 0) {
656 eigrp_send_packet_reliably(nbr);
657 }
658 }
659 }
660 ep = eigrp_fifo_tail(nbr->multicast_queue);
661 if (ep) {
662 if (ntohl(eigrph->ack) == ep->sequence_number) {
663 ep = eigrp_fifo_pop_tail(nbr->multicast_queue);
664 eigrp_packet_free(ep);
665 if (nbr->multicast_queue->count > 0) {
666 eigrp_send_packet_reliably(nbr);
667 }
668 }
669 }
670 }
671
672
673 switch (opcode) {
674 case EIGRP_OPC_HELLO:
675 eigrp_hello_receive(eigrp, iph, eigrph, ibuf, ei, length);
676 break;
677 case EIGRP_OPC_PROBE:
678 // eigrp_probe_receive(eigrp, iph, eigrph, ibuf, ei,
679 // length);
680 break;
681 case EIGRP_OPC_QUERY:
682 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
683 break;
684 case EIGRP_OPC_REPLY:
685 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
686 break;
687 case EIGRP_OPC_REQUEST:
688 // eigrp_request_receive(eigrp, iph, eigrph, ibuf, ei,
689 // length);
690 break;
691 case EIGRP_OPC_SIAQUERY:
692 eigrp_query_receive(eigrp, iph, eigrph, ibuf, ei, length);
693 break;
694 case EIGRP_OPC_SIAREPLY:
695 eigrp_reply_receive(eigrp, iph, eigrph, ibuf, ei, length);
696 break;
697 case EIGRP_OPC_UPDATE:
698 eigrp_update_receive(eigrp, iph, eigrph, ibuf, ei, length);
699 break;
700 default:
701 zlog_warn(
702 "interface %s: EIGRP packet header type %d unsupported",
703 IF_NAME(ei), opcode);
704 break;
705 }
706
707 return 0;
7f57883e
DS
708}
709
d62a17ae 710static struct stream *eigrp_recv_packet(int fd, struct interface **ifp,
711 struct stream *ibuf)
7f57883e 712{
d62a17ae 713 int ret;
714 struct ip *iph;
715 u_int16_t ip_len;
716 unsigned int ifindex = 0;
717 struct iovec iov;
718 /* Header and data both require alignment. */
719 char buff[CMSG_SPACE(SOPT_SIZE_CMSG_IFINDEX_IPV4())];
720 struct msghdr msgh;
721
722 memset(&msgh, 0, sizeof(struct msghdr));
723 msgh.msg_iov = &iov;
724 msgh.msg_iovlen = 1;
725 msgh.msg_control = (caddr_t)buff;
726 msgh.msg_controllen = sizeof(buff);
727
728 ret = stream_recvmsg(ibuf, fd, &msgh, 0, (EIGRP_PACKET_MAX_LEN + 1));
729 if (ret < 0) {
730 zlog_warn("stream_recvmsg failed: %s", safe_strerror(errno));
731 return NULL;
732 }
733 if ((unsigned int)ret < sizeof(iph)) /* ret must be > 0 now */
734 {
735 zlog_warn(
736 "eigrp_recv_packet: discarding runt packet of length %d "
737 "(ip header size is %u)",
738 ret, (u_int)sizeof(iph));
739 return NULL;
740 }
741
742 /* Note that there should not be alignment problems with this assignment
743 because this is at the beginning of the stream data buffer. */
744 iph = (struct ip *)STREAM_DATA(ibuf);
745 sockopt_iphdrincl_swab_systoh(iph);
746
747 ip_len = iph->ip_len;
748
749#if !defined(GNU_LINUX) && (OpenBSD < 200311) && (__FreeBSD_version < 1000000)
750 /*
751 * Kernel network code touches incoming IP header parameters,
752 * before protocol specific processing.
753 *
754 * 1) Convert byteorder to host representation.
755 * --> ip_len, ip_id, ip_off
756 *
757 * 2) Adjust ip_len to strip IP header size!
758 * --> If user process receives entire IP packet via RAW
759 * socket, it must consider adding IP header size to
760 * the "ip_len" field of "ip" structure.
761 *
762 * For more details, see <netinet/ip_input.c>.
763 */
764 ip_len = ip_len + (iph->ip_hl << 2);
7f57883e
DS
765#endif
766
d62a17ae 767#if defined(__DragonFly__)
768 /*
769 * in DragonFly's raw socket, ip_len/ip_off are read
770 * in network byte order.
771 * As OpenBSD < 200311 adjust ip_len to strip IP header size!
772 */
773 ip_len = ntohs(iph->ip_len) + (iph->ip_hl << 2);
7f57883e
DS
774#endif
775
d62a17ae 776 ifindex = getsockopt_ifindex(AF_INET, &msgh);
7f57883e 777
d62a17ae 778 *ifp = if_lookup_by_index(ifindex, VRF_DEFAULT);
7f57883e 779
d62a17ae 780 if (ret != ip_len) {
781 zlog_warn(
782 "eigrp_recv_packet read length mismatch: ip_len is %d, "
783 "but recvmsg returned %d",
784 ip_len, ret);
785 return NULL;
786 }
7f57883e 787
d62a17ae 788 return ibuf;
7f57883e
DS
789}
790
d62a17ae 791struct eigrp_fifo *eigrp_fifo_new(void)
7f57883e 792{
d62a17ae 793 struct eigrp_fifo *new;
7f57883e 794
d62a17ae 795 new = XCALLOC(MTYPE_EIGRP_FIFO, sizeof(struct eigrp_fifo));
796 return new;
7f57883e
DS
797}
798
799/* Free eigrp packet fifo. */
d62a17ae 800void eigrp_fifo_free(struct eigrp_fifo *fifo)
7f57883e 801{
d62a17ae 802 struct eigrp_packet *ep;
803 struct eigrp_packet *next;
804
805 for (ep = fifo->head; ep; ep = next) {
806 next = ep->next;
807 eigrp_packet_free(ep);
808 }
809 fifo->head = fifo->tail = NULL;
810 fifo->count = 0;
811
812 XFREE(MTYPE_EIGRP_FIFO, fifo);
7f57883e
DS
813}
814
815/* Free eigrp fifo entries without destroying fifo itself*/
d62a17ae 816void eigrp_fifo_reset(struct eigrp_fifo *fifo)
7f57883e 817{
d62a17ae 818 struct eigrp_packet *ep;
819 struct eigrp_packet *next;
820
821 for (ep = fifo->head; ep; ep = next) {
822 next = ep->next;
823 eigrp_packet_free(ep);
824 }
825 fifo->head = fifo->tail = NULL;
826 fifo->count = 0;
7f57883e
DS
827}
828
d62a17ae 829struct eigrp_packet *eigrp_packet_new(size_t size)
7f57883e 830{
d62a17ae 831 struct eigrp_packet *new;
7f57883e 832
d62a17ae 833 new = XCALLOC(MTYPE_EIGRP_PACKET, sizeof(struct eigrp_packet));
834 new->s = stream_new(size);
835 new->retrans_counter = 0;
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
844 ep = eigrp_fifo_tail(nbr->retrans_queue);
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*/
850 eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
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,
872 u_int16_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. */
d62a17ae 883void eigrp_packet_header_init(int type, struct eigrp_interface *ei,
884 struct stream *s, u_int32_t flags,
885 u_int32_t sequence, u_int32_t ack)
7f57883e 886{
d62a17ae 887 struct eigrp_header *eigrph;
7f57883e 888
d62a17ae 889 eigrph = (struct eigrp_header *)STREAM_DATA(s);
7f57883e 890
d62a17ae 891 eigrph->version = (u_char)EIGRP_HEADER_VERSION;
892 eigrph->opcode = (u_char)type;
893 eigrph->checksum = 0;
7f57883e 894
d62a17ae 895 eigrph->vrid = htons(ei->eigrp->vrid);
896 eigrph->ASNumber = htons(ei->eigrp->AS);
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
d62a17ae 903 if (IS_DEBUG_EIGRP_TRANSMIT(0, RECV))
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. */
d62a17ae 911void eigrp_fifo_push_head(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
927/* Return first fifo entry. */
d62a17ae 928struct eigrp_packet *eigrp_fifo_head(struct eigrp_fifo *fifo)
7f57883e 929{
d62a17ae 930 return fifo->head;
7f57883e
DS
931}
932
933/* Return last fifo entry. */
d62a17ae 934struct eigrp_packet *eigrp_fifo_tail(struct eigrp_fifo *fifo)
7f57883e 935{
d62a17ae 936 return fifo->tail;
7f57883e
DS
937}
938
d62a17ae 939void eigrp_packet_delete(struct eigrp_interface *ei)
7f57883e 940{
d62a17ae 941 struct eigrp_packet *ep;
7f57883e 942
d62a17ae 943 ep = eigrp_fifo_pop(ei->obuf);
7f57883e 944
d62a17ae 945 if (ep)
946 eigrp_packet_free(ep);
7f57883e
DS
947}
948
949/* Delete first packet from fifo. */
d62a17ae 950struct eigrp_packet *eigrp_fifo_pop(struct eigrp_fifo *fifo)
7f57883e 951{
d62a17ae 952 struct eigrp_packet *ep;
7f57883e 953
d62a17ae 954 ep = fifo->head;
7f57883e 955
d62a17ae 956 if (ep) {
957 fifo->head = ep->next;
7f57883e 958
d62a17ae 959 if (fifo->head == NULL)
960 fifo->tail = NULL;
961 else
962 fifo->head->previous = NULL;
7f57883e 963
d62a17ae 964 fifo->count--;
965 }
7f57883e 966
d62a17ae 967 return ep;
7f57883e
DS
968}
969
d62a17ae 970void eigrp_packet_free(struct eigrp_packet *ep)
7f57883e 971{
d62a17ae 972 if (ep->s)
973 stream_free(ep->s);
7f57883e 974
d62a17ae 975 THREAD_OFF(ep->t_retrans_timer);
7f57883e 976
d62a17ae 977 XFREE(MTYPE_EIGRP_PACKET, ep);
7f57883e 978
d62a17ae 979 ep = NULL;
7f57883e
DS
980}
981
982/* EIGRP Header verification. */
d62a17ae 983static int eigrp_verify_header(struct stream *ibuf, struct eigrp_interface *ei,
984 struct ip *iph, struct eigrp_header *eigrph)
7f57883e 985{
d62a17ae 986 /* Check network mask, Silently discarded. */
987 if (!eigrp_check_network_mask(ei, iph->ip_src)) {
988 zlog_warn(
989 "interface %s: eigrp_read network address is not same [%s]",
990 IF_NAME(ei), inet_ntoa(iph->ip_src));
991 return -1;
992 }
993 //
994 // /* Check authentication. The function handles logging actions, where
995 // required. */
996 // if (! eigrp_check_auth(ei, eigrph))
997 // return -1;
998
999 return 0;
7f57883e
DS
1000}
1001
1002/* Unbound socket will accept any Raw IP packets if proto is matched.
f9e5c9ca
DS
1003 To prevent it, compare src IP address and i/f address with masking
1004 i/f network mask. */
d62a17ae 1005static int eigrp_check_network_mask(struct eigrp_interface *ei,
1006 struct in_addr ip_src)
7f57883e 1007{
d62a17ae 1008 struct in_addr mask, me, him;
7f57883e 1009
d62a17ae 1010 if (ei->type == EIGRP_IFTYPE_POINTOPOINT)
1011 return 1;
7f57883e 1012
d62a17ae 1013 masklen2ip(ei->address->prefixlen, &mask);
7f57883e 1014
d62a17ae 1015 me.s_addr = ei->address->u.prefix4.s_addr & mask.s_addr;
1016 him.s_addr = ip_src.s_addr & mask.s_addr;
7f57883e 1017
d62a17ae 1018 if (IPV4_ADDR_SAME(&me, &him))
1019 return 1;
7f57883e 1020
d62a17ae 1021 return 0;
7f57883e
DS
1022}
1023
d62a17ae 1024int eigrp_unack_packet_retrans(struct thread *thread)
7f57883e 1025{
d62a17ae 1026 struct eigrp_neighbor *nbr;
1027 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
1028
1029 struct eigrp_packet *ep;
1030 ep = eigrp_fifo_tail(nbr->retrans_queue);
1031
1032 if (ep) {
1033 struct eigrp_packet *duplicate;
1034 duplicate = eigrp_packet_duplicate(ep, nbr);
1035
1036 /* Add packet to the top of the interface output queue*/
1037 eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
1038
1039 ep->retrans_counter++;
1040 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1041 return eigrp_retrans_count_exceeded(ep, nbr);
1042
1043 /*Start retransmission timer*/
1044 ep->t_retrans_timer = NULL;
1045 thread_add_timer(master, eigrp_unack_packet_retrans, nbr,
1046 EIGRP_PACKET_RETRANS_TIME,
1047 &ep->t_retrans_timer);
1048
1049 /* Hook thread to write packet. */
1050 if (nbr->ei->on_write_q == 0) {
1051 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1052 nbr->ei->on_write_q = 1;
1053 }
1054 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1055 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1056 }
1057
1058 return 0;
7f57883e
DS
1059}
1060
d62a17ae 1061int eigrp_unack_multicast_packet_retrans(struct thread *thread)
7f57883e 1062{
d62a17ae 1063 struct eigrp_neighbor *nbr;
1064 nbr = (struct eigrp_neighbor *)THREAD_ARG(thread);
1065
1066 struct eigrp_packet *ep;
1067 ep = eigrp_fifo_tail(nbr->multicast_queue);
1068
1069 if (ep) {
1070 struct eigrp_packet *duplicate;
1071 duplicate = eigrp_packet_duplicate(ep, nbr);
1072 /* Add packet to the top of the interface output queue*/
1073 eigrp_fifo_push_head(nbr->ei->obuf, duplicate);
1074
1075 ep->retrans_counter++;
1076 if (ep->retrans_counter == EIGRP_PACKET_RETRANS_MAX)
1077 return eigrp_retrans_count_exceeded(ep, nbr);
1078
1079 /*Start retransmission timer*/
1080 ep->t_retrans_timer = NULL;
1081 thread_add_timer(master, eigrp_unack_multicast_packet_retrans,
1082 nbr, EIGRP_PACKET_RETRANS_TIME,
1083 &ep->t_retrans_timer);
1084
1085 /* Hook thread to write packet. */
1086 if (nbr->ei->on_write_q == 0) {
1087 listnode_add(nbr->ei->eigrp->oi_write_q, nbr->ei);
1088 nbr->ei->on_write_q = 1;
1089 }
1090 thread_add_write(master, eigrp_write, nbr->ei->eigrp,
1091 nbr->ei->eigrp->fd, &nbr->ei->eigrp->t_write);
1092 }
1093
1094 return 0;
7f57883e
DS
1095}
1096
1097/* Get packet from tail of fifo. */
d62a17ae 1098struct eigrp_packet *eigrp_fifo_pop_tail(struct eigrp_fifo *fifo)
7f57883e 1099{
d62a17ae 1100 struct eigrp_packet *ep;
7f57883e 1101
d62a17ae 1102 ep = fifo->tail;
7f57883e 1103
d62a17ae 1104 if (ep) {
1105 fifo->tail = ep->previous;
7f57883e 1106
d62a17ae 1107 if (fifo->tail == NULL)
1108 fifo->head = NULL;
1109 else
1110 fifo->tail->next = NULL;
7f57883e 1111
d62a17ae 1112 fifo->count--;
1113 }
7f57883e 1114
d62a17ae 1115 return ep;
7f57883e
DS
1116}
1117
d62a17ae 1118struct eigrp_packet *eigrp_packet_duplicate(struct eigrp_packet *old,
1119 struct eigrp_neighbor *nbr)
7f57883e 1120{
d62a17ae 1121 struct eigrp_packet *new;
7f57883e 1122
d62a17ae 1123 new = eigrp_packet_new(nbr->ei->ifp->mtu);
1124 new->length = old->length;
1125 new->retrans_counter = old->retrans_counter;
1126 new->dst = old->dst;
1127 new->sequence_number = old->sequence_number;
1128 stream_copy(new->s, old->s);
7f57883e 1129
d62a17ae 1130 return new;
7f57883e
DS
1131}
1132
d62a17ae 1133struct TLV_IPv4_Internal_type *eigrp_read_ipv4_tlv(struct stream *s)
7f57883e 1134{
d62a17ae 1135 struct TLV_IPv4_Internal_type *tlv;
1136
1137 tlv = eigrp_IPv4_InternalTLV_new();
1138
1139 tlv->type = stream_getw(s);
1140 tlv->length = stream_getw(s);
1141 tlv->forward.s_addr = stream_getl(s);
1142 tlv->metric.delay = stream_getl(s);
1143 tlv->metric.bandwith = stream_getl(s);
1144 tlv->metric.mtu[0] = stream_getc(s);
1145 tlv->metric.mtu[1] = stream_getc(s);
1146 tlv->metric.mtu[2] = stream_getc(s);
1147 tlv->metric.hop_count = stream_getc(s);
1148 tlv->metric.reliability = stream_getc(s);
1149 tlv->metric.load = stream_getc(s);
1150 tlv->metric.tag = stream_getc(s);
1151 tlv->metric.flags = stream_getc(s);
1152
1153 tlv->prefix_length = stream_getc(s);
1154
1155 if (tlv->prefix_length <= 8) {
1156 tlv->destination_part[0] = stream_getc(s);
1157 tlv->destination.s_addr = (tlv->destination_part[0]);
1158 } else if (tlv->prefix_length > 8 && tlv->prefix_length <= 16) {
1159 tlv->destination_part[0] = stream_getc(s);
1160 tlv->destination_part[1] = stream_getc(s);
1161 tlv->destination.s_addr = ((tlv->destination_part[1] << 8)
1162 + tlv->destination_part[0]);
1163 } else if (tlv->prefix_length > 16 && tlv->prefix_length <= 24) {
1164 tlv->destination_part[0] = stream_getc(s);
1165 tlv->destination_part[1] = stream_getc(s);
1166 tlv->destination_part[2] = stream_getc(s);
1167 tlv->destination.s_addr = ((tlv->destination_part[2] << 16)
1168 + (tlv->destination_part[1] << 8)
1169 + tlv->destination_part[0]);
1170 } else if (tlv->prefix_length > 24 && tlv->prefix_length <= 32) {
1171 tlv->destination_part[0] = stream_getc(s);
1172 tlv->destination_part[1] = stream_getc(s);
1173 tlv->destination_part[2] = stream_getc(s);
1174 tlv->destination_part[3] = stream_getc(s);
1175 tlv->destination.s_addr = ((tlv->destination_part[3] << 24)
1176 + (tlv->destination_part[2] << 16)
1177 + (tlv->destination_part[1] << 8)
1178 + tlv->destination_part[0]);
1179 }
1180 return tlv;
7f57883e
DS
1181}
1182
d62a17ae 1183u_int16_t eigrp_add_internalTLV_to_stream(struct stream *s,
1184 struct eigrp_prefix_entry *pe)
7f57883e 1185{
d62a17ae 1186 u_int16_t length;
1187
1188 stream_putw(s, EIGRP_TLV_IPv4_INT);
1189 if (pe->destination_ipv4->prefixlen <= 8) {
1190 stream_putw(s, 0x001A);
1191 length = 0x001A;
1192 }
1193 if ((pe->destination_ipv4->prefixlen > 8)
1194 && (pe->destination_ipv4->prefixlen <= 16)) {
1195 stream_putw(s, 0x001B);
1196 length = 0x001B;
1197 }
1198 if ((pe->destination_ipv4->prefixlen > 16)
1199 && (pe->destination_ipv4->prefixlen <= 24)) {
1200 stream_putw(s, 0x001C);
1201 length = 0x001C;
1202 }
1203 if (pe->destination_ipv4->prefixlen > 24) {
1204 stream_putw(s, 0x001D);
1205 length = 0x001D;
1206 }
1207
1208 stream_putl(s, 0x00000000);
1209
1210 /*Metric*/
1211 stream_putl(s, pe->reported_metric.delay);
1212 stream_putl(s, pe->reported_metric.bandwith);
1213 stream_putc(s, pe->reported_metric.mtu[2]);
1214 stream_putc(s, pe->reported_metric.mtu[1]);
1215 stream_putc(s, pe->reported_metric.mtu[0]);
1216 stream_putc(s, pe->reported_metric.hop_count);
1217 stream_putc(s, pe->reported_metric.reliability);
1218 stream_putc(s, pe->reported_metric.load);
1219 stream_putc(s, pe->reported_metric.tag);
1220 stream_putc(s, pe->reported_metric.flags);
1221
1222 stream_putc(s, pe->destination_ipv4->prefixlen);
1223
1224 if (pe->destination_ipv4->prefixlen <= 8) {
1225 stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
1226 }
1227 if ((pe->destination_ipv4->prefixlen > 8)
1228 && (pe->destination_ipv4->prefixlen <= 16)) {
1229 stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
1230 stream_putc(s,
1231 (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
1232 }
1233 if ((pe->destination_ipv4->prefixlen > 16)
1234 && (pe->destination_ipv4->prefixlen <= 24)) {
1235 stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
1236 stream_putc(s,
1237 (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
1238 stream_putc(s,
1239 (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
1240 }
1241 if (pe->destination_ipv4->prefixlen > 24) {
1242 stream_putc(s, pe->destination_ipv4->prefix.s_addr & 0xFF);
1243 stream_putc(s,
1244 (pe->destination_ipv4->prefix.s_addr >> 8) & 0xFF);
1245 stream_putc(s,
1246 (pe->destination_ipv4->prefix.s_addr >> 16) & 0xFF);
1247 stream_putc(s,
1248 (pe->destination_ipv4->prefix.s_addr >> 24) & 0xFF);
1249 }
1250
1251 return length;
7f57883e
DS
1252}
1253
d62a17ae 1254u_int16_t eigrp_add_authTLV_MD5_to_stream(struct stream *s,
1255 struct eigrp_interface *ei)
7f57883e 1256{
d62a17ae 1257 struct key *key;
1258 struct keychain *keychain;
1259 struct TLV_MD5_Authentication_Type *authTLV;
1260
1261 authTLV = eigrp_authTLV_MD5_new();
1262
1263 authTLV->type = htons(EIGRP_TLV_AUTH);
1264 authTLV->length = htons(EIGRP_AUTH_MD5_TLV_SIZE);
1265 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_MD5);
1266 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_MD5_LEN);
1267 authTLV->key_sequence = 0;
1268 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1269
1270 keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain);
1271 if (keychain)
1272 key = key_lookup_for_send(keychain);
1273 else {
1274 free(IF_DEF_PARAMS(ei->ifp)->auth_keychain);
1275 IF_DEF_PARAMS(ei->ifp)->auth_keychain = NULL;
1276 eigrp_authTLV_MD5_free(authTLV);
1277 return 0;
1278 }
1279
1280 if (key) {
1281 authTLV->key_id = htonl(key->index);
1282 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_MD5_LEN);
1283 stream_put(s, authTLV,
1284 sizeof(struct TLV_MD5_Authentication_Type));
1285 eigrp_authTLV_MD5_free(authTLV);
1286 return EIGRP_AUTH_MD5_TLV_SIZE;
1287 }
1288
1289 eigrp_authTLV_MD5_free(authTLV);
1290
1291 return 0;
7f57883e
DS
1292}
1293
d62a17ae 1294u_int16_t eigrp_add_authTLV_SHA256_to_stream(struct stream *s,
1295 struct eigrp_interface *ei)
7f57883e 1296{
d62a17ae 1297 struct key *key;
1298 struct keychain *keychain;
1299 struct TLV_SHA256_Authentication_Type *authTLV;
1300
1301 authTLV = eigrp_authTLV_SHA256_new();
1302
1303 authTLV->type = htons(EIGRP_TLV_AUTH);
1304 authTLV->length = htons(EIGRP_AUTH_SHA256_TLV_SIZE);
1305 authTLV->auth_type = htons(EIGRP_AUTH_TYPE_SHA256);
1306 authTLV->auth_length = htons(EIGRP_AUTH_TYPE_SHA256_LEN);
1307 authTLV->key_sequence = 0;
1308 memset(authTLV->Nullpad, 0, sizeof(authTLV->Nullpad));
1309
1310 keychain = keychain_lookup(IF_DEF_PARAMS(ei->ifp)->auth_keychain);
1311 if (keychain)
1312 key = key_lookup_for_send(keychain);
1313 else {
1314 free(IF_DEF_PARAMS(ei->ifp)->auth_keychain);
1315 IF_DEF_PARAMS(ei->ifp)->auth_keychain = NULL;
1316 eigrp_authTLV_SHA256_free(authTLV);
1317 return 0;
1318 }
1319
1320 if (key) {
1321 authTLV->key_id = 0;
1322 memset(authTLV->digest, 0, EIGRP_AUTH_TYPE_SHA256_LEN);
1323 stream_put(s, authTLV,
1324 sizeof(struct TLV_SHA256_Authentication_Type));
1325 eigrp_authTLV_SHA256_free(authTLV);
1326 return EIGRP_AUTH_SHA256_TLV_SIZE;
1327 }
1328
1329 eigrp_authTLV_SHA256_free(authTLV);
1330
1331 return 0;
7f57883e
DS
1332}
1333
d62a17ae 1334struct TLV_MD5_Authentication_Type *eigrp_authTLV_MD5_new()
7f57883e 1335{
d62a17ae 1336 struct TLV_MD5_Authentication_Type *new;
7f57883e 1337
d62a17ae 1338 new = XCALLOC(MTYPE_EIGRP_AUTH_TLV,
1339 sizeof(struct TLV_MD5_Authentication_Type));
7f57883e 1340
d62a17ae 1341 return new;
7f57883e
DS
1342}
1343
d62a17ae 1344void eigrp_authTLV_MD5_free(struct TLV_MD5_Authentication_Type *authTLV)
7f57883e 1345{
d62a17ae 1346 XFREE(MTYPE_EIGRP_AUTH_TLV, authTLV);
7f57883e
DS
1347}
1348
d62a17ae 1349struct TLV_SHA256_Authentication_Type *eigrp_authTLV_SHA256_new()
7f57883e 1350{
d62a17ae 1351 struct TLV_SHA256_Authentication_Type *new;
7f57883e 1352
d62a17ae 1353 new = XCALLOC(MTYPE_EIGRP_AUTH_SHA256_TLV,
1354 sizeof(struct TLV_SHA256_Authentication_Type));
7f57883e 1355
d62a17ae 1356 return new;
7f57883e
DS
1357}
1358
d62a17ae 1359void eigrp_authTLV_SHA256_free(struct TLV_SHA256_Authentication_Type *authTLV)
7f57883e 1360{
d62a17ae 1361 XFREE(MTYPE_EIGRP_AUTH_SHA256_TLV, authTLV);
7f57883e
DS
1362}
1363
d62a17ae 1364struct TLV_IPv4_Internal_type *eigrp_IPv4_InternalTLV_new()
7f57883e 1365{
d62a17ae 1366 struct TLV_IPv4_Internal_type *new;
7f57883e 1367
d62a17ae 1368 new = XCALLOC(MTYPE_EIGRP_IPV4_INT_TLV,
1369 sizeof(struct TLV_IPv4_Internal_type));
7f57883e 1370
d62a17ae 1371 return new;
7f57883e
DS
1372}
1373
d62a17ae 1374void eigrp_IPv4_InternalTLV_free(
1375 struct TLV_IPv4_Internal_type *IPv4_InternalTLV)
7f57883e 1376{
d62a17ae 1377 XFREE(MTYPE_EIGRP_IPV4_INT_TLV, IPv4_InternalTLV);
7f57883e
DS
1378}
1379
d62a17ae 1380struct TLV_Sequence_Type *eigrp_SequenceTLV_new()
7f57883e 1381{
d62a17ae 1382 struct TLV_Sequence_Type *new;
7f57883e 1383
d62a17ae 1384 new = XCALLOC(MTYPE_EIGRP_SEQ_TLV, sizeof(struct TLV_Sequence_Type));
7f57883e 1385
d62a17ae 1386 return new;
7f57883e 1387}