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