]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_msdp_packet.c
pimd: fix MSDP crash on unexpected TLV sizes
[mirror_frr.git] / pimd / pim_msdp_packet.c
CommitLineData
2a333e0f 1/*
2 * IP MSDP packet helper
3 * Copyright (C) 2016 Cumulus Networks, Inc.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
14 *
896014f4
DL
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
2a333e0f 18 */
19#include <zebra.h>
20
21#include <lib/log.h>
22#include <lib/network.h>
23#include <lib/stream.h>
24#include <lib/thread.h>
3c72d654 25#include <lib/vty.h>
3613d898 26#include <lib/lib_errors.h>
2a333e0f 27
28#include "pimd.h"
993e3d8e 29#include "pim_instance.h"
2a333e0f 30#include "pim_str.h"
d9ff4302 31#include "pim_errors.h"
2a333e0f 32
33#include "pim_msdp.h"
34#include "pim_msdp_packet.h"
35#include "pim_msdp_socket.h"
36
d62a17ae 37static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
38 int buf_size)
2a333e0f 39{
d62a17ae 40 switch (type) {
41 case PIM_MSDP_V4_SOURCE_ACTIVE:
42 snprintf(buf, buf_size, "%s", "SA");
43 break;
44 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST:
45 snprintf(buf, buf_size, "%s", "SA_REQ");
46 break;
47 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE:
48 snprintf(buf, buf_size, "%s", "SA_RESP");
49 break;
50 case PIM_MSDP_KEEPALIVE:
51 snprintf(buf, buf_size, "%s", "KA");
52 break;
53 case PIM_MSDP_RESERVED:
54 snprintf(buf, buf_size, "%s", "RSVD");
55 break;
56 case PIM_MSDP_TRACEROUTE_PROGRESS:
57 snprintf(buf, buf_size, "%s", "TRACE_PROG");
58 break;
59 case PIM_MSDP_TRACEROUTE_REPLY:
60 snprintf(buf, buf_size, "%s", "TRACE_REPLY");
61 break;
62 default:
63 snprintf(buf, buf_size, "UNK-%d", type);
64 }
65 return buf;
2a333e0f 66}
67
d62a17ae 68static void pim_msdp_pkt_sa_dump_one(struct stream *s)
15ad0c71 69{
6fff2cc6 70 pim_sgaddr sg;
15ad0c71 71
d62a17ae 72 /* just throw away the three reserved bytes */
73 stream_get3(s);
74 /* throw away the prefix length also */
75 stream_getc(s);
15ad0c71 76
6fff2cc6 77 memset(&sg, 0, sizeof(sg));
d62a17ae 78 sg.grp.s_addr = stream_get_ipv4(s);
79 sg.src.s_addr = stream_get_ipv4(s);
15ad0c71 80
98a81d2b 81 zlog_debug(" sg %pSG", &sg);
15ad0c71 82}
83
d62a17ae 84static void pim_msdp_pkt_sa_dump(struct stream *s)
15ad0c71 85{
d62a17ae 86 int entry_cnt;
87 int i;
88 struct in_addr rp; /* Last RP address associated with this SA */
89
90 entry_cnt = stream_getc(s);
91 rp.s_addr = stream_get_ipv4(s);
92
93 if (PIM_DEBUG_MSDP_PACKETS) {
94 char rp_str[INET_ADDRSTRLEN];
95 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
96 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
97 }
98
99 /* dump SAs */
100 for (i = 0; i < entry_cnt; ++i) {
101 pim_msdp_pkt_sa_dump_one(s);
102 }
15ad0c71 103}
104
d62a17ae 105static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
106 bool rx, struct stream *s)
2a333e0f 107{
d62a17ae 108 char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
2a333e0f 109
d62a17ae 110 pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
2a333e0f 111
d62a17ae 112 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
113 rx ? "rx" : "tx", type_str, len);
15ad0c71 114
d62a17ae 115 if (!s) {
116 return;
117 }
15ad0c71 118
d62a17ae 119 switch (type) {
120 case PIM_MSDP_V4_SOURCE_ACTIVE:
121 pim_msdp_pkt_sa_dump(s);
122 break;
123 default:;
124 }
2a333e0f 125}
126
127/* Check file descriptor whether connect is established. */
d62a17ae 128static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
2a333e0f 129{
d62a17ae 130 int status;
131 socklen_t slen;
132 int ret;
133
134 if (mp->state != PIM_MSDP_CONNECTING) {
135 /* if we are here it means we are not in a connecting or
136 * established state
137 * for now treat this as a fatal error */
138 pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
139 return;
140 }
141
142 PIM_MSDP_PEER_READ_OFF(mp);
143 PIM_MSDP_PEER_WRITE_OFF(mp);
144
145 /* Check file descriptor. */
146 slen = sizeof(status);
147 ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
148
149 /* If getsockopt is fail, this is fatal error. */
150 if (ret < 0) {
450971aa 151 flog_err_sys(EC_LIB_SOCKET,
09c866e3 152 "can't get sockopt for nonblocking connect");
d62a17ae 153 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
154 return;
155 }
156
157 /* When status is 0 then TCP connection is established. */
158 if (PIM_DEBUG_MSDP_INTERNAL) {
159 zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str,
160 status ? "fail" : "success");
161 }
162 if (status == 0) {
163 pim_msdp_peer_established(mp);
164 } else {
165 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
166 }
2a333e0f 167}
168
d62a17ae 169static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
2a333e0f 170{
d62a17ae 171 stream_free(stream_fifo_pop(mp->obuf));
2a333e0f 172}
173
d62a17ae 174static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
3c72d654 175{
d62a17ae 176 stream_fifo_push(mp->obuf, s);
3c72d654 177}
178
d62a17ae 179static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
2a333e0f 180{
d62a17ae 181 if (stream_fifo_head(mp->obuf)) {
182 PIM_MSDP_PEER_WRITE_ON(mp);
183 }
2a333e0f 184}
185
cc9f21da 186void pim_msdp_write(struct thread *thread)
2a333e0f 187{
d62a17ae 188 struct pim_msdp_peer *mp;
189 struct stream *s;
190 int num;
191 enum pim_msdp_tlv type;
192 int len;
193 int work_cnt = 0;
194 int work_max_cnt = 100;
195
196 mp = THREAD_ARG(thread);
197 mp->t_write = NULL;
198
199 if (PIM_DEBUG_MSDP_INTERNAL) {
200 zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
201 }
202 if (mp->fd < 0) {
cc9f21da 203 return;
d62a17ae 204 }
205
206 /* check if TCP connection is established */
207 if (mp->state != PIM_MSDP_ESTABLISHED) {
208 pim_msdp_connect_check(mp);
cc9f21da 209 return;
d62a17ae 210 }
211
212 s = stream_fifo_head(mp->obuf);
213 if (!s) {
214 pim_msdp_write_proceed_actions(mp);
cc9f21da 215 return;
d62a17ae 216 }
217
d62a17ae 218 /* Nonblocking write until TCP output buffer is full */
219 do {
220 int writenum;
221
222 /* Number of bytes to be sent */
223 writenum = stream_get_endp(s) - stream_get_getp(s);
224
225 /* Call write() system call */
2d34fb80 226 num = write(mp->fd, stream_pnt(s), writenum);
d62a17ae 227 if (num < 0) {
228 /* write failed either retry needed or error */
229 if (ERRNO_IO_RETRY(errno)) {
230 if (PIM_DEBUG_MSDP_INTERNAL) {
231 zlog_debug(
232 "MSDP peer %s pim_msdp_write io retry",
233 mp->key_str);
234 }
235 break;
236 }
237
238 pim_msdp_peer_reset_tcp_conn(mp, "pkt-tx-failed");
cc9f21da 239 return;
d62a17ae 240 }
241
242 if (num != writenum) {
243 /* Partial write */
244 stream_forward_getp(s, num);
245 if (PIM_DEBUG_MSDP_INTERNAL) {
246 zlog_debug(
247 "MSDP peer %s pim_msdp_partial_write",
248 mp->key_str);
249 }
250 break;
251 }
252
253 /* Retrieve msdp packet type. */
254 stream_set_getp(s, 0);
255 type = stream_getc(s);
256 len = stream_getw(s);
257 switch (type) {
258 case PIM_MSDP_KEEPALIVE:
259 mp->ka_tx_cnt++;
260 break;
261 case PIM_MSDP_V4_SOURCE_ACTIVE:
262 mp->sa_tx_cnt++;
263 break;
264 default:;
265 }
266 if (PIM_DEBUG_MSDP_PACKETS) {
267 pim_msdp_pkt_dump(mp, type, len, false /*rx*/, s);
268 }
269
270 /* packet sent delete it. */
271 pim_msdp_pkt_delete(mp);
272
273 ++work_cnt;
274 /* may need to pause if we have done too much work in this
275 * loop */
276 if (work_cnt >= work_max_cnt) {
277 break;
278 }
279 } while ((s = stream_fifo_head(mp->obuf)) != NULL);
280 pim_msdp_write_proceed_actions(mp);
281
d62a17ae 282 if (PIM_DEBUG_MSDP_INTERNAL) {
283 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
284 mp->key_str, work_cnt);
285 }
2a333e0f 286}
287
d62a17ae 288static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
2a333e0f 289{
d62a17ae 290 /* Add packet to the end of list. */
291 pim_msdp_pkt_add(mp, s);
2a333e0f 292
d62a17ae 293 PIM_MSDP_PEER_WRITE_ON(mp);
2a333e0f 294}
295
d62a17ae 296void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
2a333e0f 297{
d62a17ae 298 struct stream *s;
2a333e0f 299
d62a17ae 300 if (mp->state != PIM_MSDP_ESTABLISHED) {
301 /* don't tx anything unless a session is established */
302 return;
303 }
304 s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
305 stream_putc(s, PIM_MSDP_KEEPALIVE);
306 stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
2a333e0f 307
d62a17ae 308 pim_msdp_pkt_send(mp, s);
2a333e0f 309}
310
10c899e2
DS
311static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
312 struct pim_msdp_peer *mp)
3c72d654 313{
d62a17ae 314 struct stream *s;
315
316 if (mp->state != PIM_MSDP_ESTABLISHED) {
317 /* don't tx anything unless a session is established */
318 return;
319 }
10c899e2 320 s = stream_dup(pim->msdp.work_obuf);
d62a17ae 321 if (s) {
322 pim_msdp_pkt_send(mp, s);
323 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
324 }
3c72d654 325}
326
327/* push the stream into the obuf fifo of all the peers */
10c899e2
DS
328static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
329 struct pim_msdp_peer *mp)
3c72d654 330{
d62a17ae 331 struct listnode *mpnode;
332
333 if (mp) {
10c899e2 334 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
d62a17ae 335 } else {
10c899e2 336 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
d62a17ae 337 if (PIM_DEBUG_MSDP_INTERNAL) {
338 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
339 mp->key_str);
340 }
10c899e2 341 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
d62a17ae 342 }
343 }
3c72d654 344}
345
9fbd9fc4
AMR
346static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
347 struct in_addr rp)
3c72d654 348{
d62a17ae 349 int curr_tlv_ecnt;
350
472ad383 351 stream_reset(pim->msdp.work_obuf);
d62a17ae 352 curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
353 ? PIM_MSDP_SA_MAX_ENTRY_CNT
354 : local_cnt;
355 local_cnt -= curr_tlv_ecnt;
472ad383
DS
356 stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
357 stream_putw(pim->msdp.work_obuf,
2ad78035 358 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
472ad383 359 stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
9fbd9fc4 360 stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
d62a17ae 361
362 return local_cnt;
3c72d654 363}
364
d62a17ae 365static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
3c72d654 366{
472ad383
DS
367 stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
368 stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
369 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
370 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
3c72d654 371}
372
4097373f
DS
373static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
374 struct pim_msdp_peer *mp)
3c72d654 375{
d62a17ae 376 struct listnode *sanode;
377 struct pim_msdp_sa *sa;
378 int sa_count;
4097373f 379 int local_cnt = pim->msdp.local_cnt;
d62a17ae 380
381 sa_count = 0;
382 if (PIM_DEBUG_MSDP_INTERNAL) {
383 zlog_debug(" sa gen %d", local_cnt);
384 }
385
9fbd9fc4
AMR
386 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
387 pim->msdp.originator_id);
d62a17ae 388
4097373f 389 for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
d62a17ae 390 if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
391 /* current implementation of MSDP is for anycast i.e.
392 * full mesh. so
393 * no re-forwarding of SAs that we learnt from other
394 * peers */
395 continue;
396 }
397 /* add sa into scratch pad */
398 pim_msdp_pkt_sa_fill_one(sa);
399 ++sa_count;
400 if (sa_count >= PIM_MSDP_SA_MAX_ENTRY_CNT) {
10c899e2 401 pim_msdp_pkt_sa_push(pim, mp);
d62a17ae 402 /* reset headers */
403 sa_count = 0;
404 if (PIM_DEBUG_MSDP_INTERNAL) {
405 zlog_debug(" sa gen for remainder %d",
406 local_cnt);
407 }
9fbd9fc4
AMR
408 local_cnt = pim_msdp_pkt_sa_fill_hdr(
409 pim, local_cnt, pim->msdp.originator_id);
d62a17ae 410 }
411 }
412
413 if (sa_count) {
10c899e2 414 pim_msdp_pkt_sa_push(pim, mp);
d62a17ae 415 }
416 return;
3c72d654 417}
418
472ad383 419static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
3c72d654 420{
d62a17ae 421 struct listnode *mpnode;
422 struct pim_msdp_peer *mp;
423
424 /* if SA were sent to the peers we restart ka timer and avoid
425 * unnecessary ka noise */
472ad383 426 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
d62a17ae 427 if (mp->flags & PIM_MSDP_PEERF_SA_JUST_SENT) {
428 mp->flags &= ~PIM_MSDP_PEERF_SA_JUST_SENT;
429 pim_msdp_peer_pkt_txed(mp);
430 }
431 }
3c72d654 432}
433
472ad383 434void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
3c72d654 435{
4097373f 436 pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
472ad383 437 pim_msdp_pkt_sa_tx_done(pim);
3c72d654 438}
439
d62a17ae 440void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
3c72d654 441{
9fbd9fc4 442 pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
d62a17ae 443 pim_msdp_pkt_sa_fill_one(sa);
10c899e2 444 pim_msdp_pkt_sa_push(sa->pim, NULL);
472ad383 445 pim_msdp_pkt_sa_tx_done(sa->pim);
3c72d654 446}
447
448/* when a connection is first established we push all SAs immediately */
d62a17ae 449void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
3c72d654 450{
4097373f 451 pim_msdp_pkt_sa_gen(mp->pim, mp);
472ad383 452 pim_msdp_pkt_sa_tx_done(mp->pim);
3c72d654 453}
454
9fbd9fc4 455void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
6fff2cc6 456 struct in_addr rp, pim_sgaddr sg)
9fbd9fc4
AMR
457{
458 struct pim_msdp_sa sa;
459
460 /* Fills the SA header. */
461 pim_msdp_pkt_sa_fill_hdr(mp->pim, 1, rp);
462
463 /* Fills the message contents. */
464 sa.pim = mp->pim;
465 sa.sg = sg;
466 pim_msdp_pkt_sa_fill_one(&sa);
467
468 /* Pushes the message. */
469 pim_msdp_pkt_sa_push(sa.pim, mp);
470 pim_msdp_pkt_sa_tx_done(sa.pim);
471}
472
d62a17ae 473static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
2a333e0f 474{
d62a17ae 475 pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
2a333e0f 476}
477
d62a17ae 478static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
2a333e0f 479{
d62a17ae 480 mp->ka_rx_cnt++;
481 if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
482 pim_msdp_pkt_rxed_with_fatal_error(mp);
483 return;
484 }
485 pim_msdp_peer_pkt_rxed(mp);
2a333e0f 486}
487
d62a17ae 488static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
3c72d654 489{
d62a17ae 490 int prefix_len;
6fff2cc6 491 pim_sgaddr sg;
9fbd9fc4
AMR
492 struct listnode *peer_node;
493 struct pim_msdp_peer *peer;
d62a17ae 494
495 /* just throw away the three reserved bytes */
496 stream_get3(mp->ibuf);
497 prefix_len = stream_getc(mp->ibuf);
498
6fff2cc6 499 memset(&sg, 0, sizeof(sg));
d62a17ae 500 sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
501 sg.src.s_addr = stream_get_ipv4(mp->ibuf);
502
12256b84 503 if (prefix_len != IPV4_MAX_BITLEN) {
d62a17ae 504 /* ignore SA update if the prefix length is not 32 */
298004a1 505 flog_err(EC_PIM_MSDP_PACKET,
1c50c1c0
QY
506 "rxed sa update with invalid prefix length %d",
507 prefix_len);
d62a17ae 508 return;
509 }
510 if (PIM_DEBUG_MSDP_PACKETS) {
98a81d2b 511 zlog_debug(" sg %pSG", &sg);
d62a17ae 512 }
472ad383 513 pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
9fbd9fc4
AMR
514
515 /* Forwards the SA to the peers that are not in the RPF to the RP nor in
516 * the same mesh group as the peer from which we received the message.
517 * If the message group is not set, i.e. "default", then we assume that
518 * the message must be forwarded.*/
519 for (ALL_LIST_ELEMENTS_RO(mp->pim->msdp.peer_list, peer_node, peer)) {
0ce04a08
RZ
520 /* Not a RPF peer, so skip it. */
521 if (pim_msdp_peer_rpf_check(peer, rp))
522 continue;
523 /* Don't forward inside the meshed group. */
524 if ((mp->flags & PIM_MSDP_PEERF_IN_GROUP)
525 && strcmp(mp->mesh_group_name, peer->mesh_group_name) == 0)
526 continue;
527
528 pim_msdp_pkt_sa_tx_one_to_one_peer(peer, rp, sg);
9fbd9fc4 529 }
3c72d654 530}
531
d62a17ae 532static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
2a333e0f 533{
d62a17ae 534 int entry_cnt;
535 int i;
536 struct in_addr rp; /* Last RP address associated with this SA */
537
538 mp->sa_rx_cnt++;
539
540 if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
541 pim_msdp_pkt_rxed_with_fatal_error(mp);
542 return;
543 }
544
545 entry_cnt = stream_getc(mp->ibuf);
546 /* some vendors include the actual multicast data in the tlv (at the
9fbd9fc4
AMR
547 * end). we will ignore such data. in the future we may consider pushing
548 * it down the RPT
549 */
d62a17ae 550 if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
551 pim_msdp_pkt_rxed_with_fatal_error(mp);
552 return;
553 }
554 rp.s_addr = stream_get_ipv4(mp->ibuf);
555
556 if (PIM_DEBUG_MSDP_PACKETS) {
557 char rp_str[INET_ADDRSTRLEN];
558 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
559 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
560 }
561
9fbd9fc4
AMR
562 pim_msdp_peer_pkt_rxed(mp);
563
d62a17ae 564 if (!pim_msdp_peer_rpf_check(mp, rp)) {
565 /* if peer-RPF check fails don't process the packet any further
566 */
567 if (PIM_DEBUG_MSDP_PACKETS) {
568 zlog_debug(" peer RPF check failed");
569 }
570 return;
571 }
572
d62a17ae 573 /* update SA cache */
574 for (i = 0; i < entry_cnt; ++i) {
575 pim_msdp_pkt_sa_rx_one(mp, rp);
576 }
2a333e0f 577}
578
d62a17ae 579static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
2a333e0f 580{
d62a17ae 581 enum pim_msdp_tlv type;
582 int len;
583
584 /* re-read type and len */
585 type = stream_getc_from(mp->ibuf, 0);
586 len = stream_getw_from(mp->ibuf, 1);
587 if (len < PIM_MSDP_HEADER_SIZE) {
588 pim_msdp_pkt_rxed_with_fatal_error(mp);
589 return;
590 }
591
592 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
593 /* if tlv size if greater than max just ignore the tlv */
594 return;
595 }
596
597 if (PIM_DEBUG_MSDP_PACKETS) {
598 pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
599 }
600
601 switch (type) {
602 case PIM_MSDP_KEEPALIVE:
603 pim_msdp_pkt_ka_rx(mp, len);
604 break;
605 case PIM_MSDP_V4_SOURCE_ACTIVE:
606 mp->sa_rx_cnt++;
607 pim_msdp_pkt_sa_rx(mp, len);
608 break;
609 default:
610 mp->unk_rx_cnt++;
611 }
2a333e0f 612}
613
614/* pim msdp read utility function. */
d62a17ae 615static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
2a333e0f 616{
d62a17ae 617 int nbytes;
618 int readsize;
619 int old_endp;
620 int new_endp;
621
622 old_endp = stream_get_endp(mp->ibuf);
623 readsize = mp->packet_size - old_endp;
624 if (!readsize) {
625 return 0;
626 }
627
628 /* Read packet from fd */
629 nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
630 new_endp = stream_get_endp(mp->ibuf);
631 if (nbytes < 0) {
632 if (PIM_DEBUG_MSDP_INTERNAL) {
633 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
634 nbytes);
635 }
636 if (nbytes == -2) {
637 if (PIM_DEBUG_MSDP_INTERNAL) {
638 zlog_debug(
639 "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
640 mp->key_str, old_endp, new_endp);
641 }
642 /* transient error retry */
643 return -1;
644 }
645 pim_msdp_pkt_rxed_with_fatal_error(mp);
646 return -1;
647 }
648
649 if (!nbytes) {
650 if (PIM_DEBUG_MSDP_INTERNAL) {
651 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
652 nbytes);
653 }
654 pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
655 return -1;
656 }
657
658 /* We read partial packet. */
659 if (stream_get_endp(mp->ibuf) != mp->packet_size) {
660 if (PIM_DEBUG_MSDP_INTERNAL) {
661 zlog_debug(
662 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
663 mp->key_str, mp->packet_size, old_endp,
664 new_endp);
665 }
666 return -1;
667 }
668
669 return 0;
2a333e0f 670}
671
cc9f21da 672void pim_msdp_read(struct thread *thread)
2a333e0f 673{
d62a17ae 674 struct pim_msdp_peer *mp;
675 int rc;
676 uint32_t len;
677
678 mp = THREAD_ARG(thread);
679 mp->t_read = NULL;
680
681 if (PIM_DEBUG_MSDP_INTERNAL) {
682 zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
683 }
684
685 if (mp->fd < 0) {
cc9f21da 686 return;
d62a17ae 687 }
688
689 /* check if TCP connection is established */
690 if (mp->state != PIM_MSDP_ESTABLISHED) {
691 pim_msdp_connect_check(mp);
cc9f21da 692 return;
d62a17ae 693 }
694
695 PIM_MSDP_PEER_READ_ON(mp);
696
697 if (!mp->packet_size) {
698 mp->packet_size = PIM_MSDP_HEADER_SIZE;
699 }
700
701 if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
702 /* start by reading the TLV header */
703 rc = pim_msdp_read_packet(mp);
cc9f21da
DS
704 if (rc < 0)
705 return;
d62a17ae 706
707 /* Find TLV type and len */
708 stream_getc(mp->ibuf);
709 len = stream_getw(mp->ibuf);
710 if (len < PIM_MSDP_HEADER_SIZE) {
711 pim_msdp_pkt_rxed_with_fatal_error(mp);
cc9f21da 712 return;
d62a17ae 713 }
d4981032
RZ
714
715 /*
716 * Handle messages with longer than expected TLV size: resize
717 * the stream to handle reading the whole message.
718 *
719 * RFC 3618 Section 12. 'Packet Formats':
720 * > ... If an implementation receives a TLV whose length
721 * > exceeds the maximum TLV length specified below, the TLV
722 * > SHOULD be accepted. Any additional data, including possible
723 * > next TLV's in the same message, SHOULD be ignored, and the
724 * > MSDP session should not be reset. ...
725 */
726 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
727 /* Check if the current buffer is big enough. */
728 if (mp->ibuf->size < len) {
729 if (PIM_DEBUG_MSDP_PACKETS)
730 zlog_debug(
731 "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
732 mp->key_str, len);
733
734 stream_resize_inplace(&mp->ibuf, len);
735 }
736 }
737
d62a17ae 738 /* read complete TLV */
739 mp->packet_size = len;
740 }
741
742 rc = pim_msdp_read_packet(mp);
cc9f21da
DS
743 if (rc < 0)
744 return;
d62a17ae 745
746 pim_msdp_pkt_rx(mp);
747
748 /* reset input buffers and get ready for the next packet */
749 mp->packet_size = 0;
750 stream_reset(mp->ibuf);
2a333e0f 751}