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