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