]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msdp_packet.c
pimd: Convert over to use LIB_ERR_XXX for zlog_err
[mirror_frr.git] / pimd / pim_msdp_packet.c
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 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
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>
25 #include <lib/vty.h>
26 #include <lib/lib_errors.h>
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
35 static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
36 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
66 static void pim_msdp_pkt_sa_dump_one(struct stream *s)
67 {
68 struct prefix_sg sg;
69
70 /* just throw away the three reserved bytes */
71 stream_get3(s);
72 /* throw away the prefix length also */
73 stream_getc(s);
74
75 memset(&sg, 0, sizeof(struct prefix_sg));
76 sg.grp.s_addr = stream_get_ipv4(s);
77 sg.src.s_addr = stream_get_ipv4(s);
78
79 zlog_debug(" sg %s", pim_str_sg_dump(&sg));
80 }
81
82 static void pim_msdp_pkt_sa_dump(struct stream *s)
83 {
84 int entry_cnt;
85 int i;
86 struct in_addr rp; /* Last RP address associated with this SA */
87
88 entry_cnt = stream_getc(s);
89 rp.s_addr = stream_get_ipv4(s);
90
91 if (PIM_DEBUG_MSDP_PACKETS) {
92 char rp_str[INET_ADDRSTRLEN];
93 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
94 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
95 }
96
97 /* dump SAs */
98 for (i = 0; i < entry_cnt; ++i) {
99 pim_msdp_pkt_sa_dump_one(s);
100 }
101 }
102
103 static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
104 bool rx, struct stream *s)
105 {
106 char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
107
108 pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
109
110 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
111 rx ? "rx" : "tx", type_str, len);
112
113 if (!s) {
114 return;
115 }
116
117 switch (type) {
118 case PIM_MSDP_V4_SOURCE_ACTIVE:
119 pim_msdp_pkt_sa_dump(s);
120 break;
121 default:;
122 }
123 }
124
125 /* Check file descriptor whether connect is established. */
126 static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
127 {
128 int status;
129 socklen_t slen;
130 int ret;
131
132 if (mp->state != PIM_MSDP_CONNECTING) {
133 /* if we are here it means we are not in a connecting or
134 * established state
135 * for now treat this as a fatal error */
136 pim_msdp_peer_reset_tcp_conn(mp, "invalid-state");
137 return;
138 }
139
140 PIM_MSDP_PEER_READ_OFF(mp);
141 PIM_MSDP_PEER_WRITE_OFF(mp);
142
143 /* Check file descriptor. */
144 slen = sizeof(status);
145 ret = getsockopt(mp->fd, SOL_SOCKET, SO_ERROR, (void *)&status, &slen);
146
147 /* If getsockopt is fail, this is fatal error. */
148 if (ret < 0) {
149 zlog_ferr(LIB_ERR_SOCKET,
150 "can't get sockopt for nonblocking connect");
151 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
152 return;
153 }
154
155 /* When status is 0 then TCP connection is established. */
156 if (PIM_DEBUG_MSDP_INTERNAL) {
157 zlog_debug("MSDP peer %s pim_connect_check %s", mp->key_str,
158 status ? "fail" : "success");
159 }
160 if (status == 0) {
161 pim_msdp_peer_established(mp);
162 } else {
163 pim_msdp_peer_reset_tcp_conn(mp, "connect-failed");
164 }
165 }
166
167 static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
168 {
169 stream_free(stream_fifo_pop(mp->obuf));
170 }
171
172 static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
173 {
174 stream_fifo_push(mp->obuf, s);
175 }
176
177 static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
178 {
179 if (stream_fifo_head(mp->obuf)) {
180 PIM_MSDP_PEER_WRITE_ON(mp);
181 }
182 }
183
184 int pim_msdp_write(struct thread *thread)
185 {
186 struct pim_msdp_peer *mp;
187 struct stream *s;
188 int num;
189 enum pim_msdp_tlv type;
190 int len;
191 int work_cnt = 0;
192 int work_max_cnt = 100;
193
194 mp = THREAD_ARG(thread);
195 mp->t_write = NULL;
196
197 if (PIM_DEBUG_MSDP_INTERNAL) {
198 zlog_debug("MSDP peer %s pim_msdp_write", mp->key_str);
199 }
200 if (mp->fd < 0) {
201 return -1;
202 }
203
204 /* check if TCP connection is established */
205 if (mp->state != PIM_MSDP_ESTABLISHED) {
206 pim_msdp_connect_check(mp);
207 return 0;
208 }
209
210 s = stream_fifo_head(mp->obuf);
211 if (!s) {
212 pim_msdp_write_proceed_actions(mp);
213 return 0;
214 }
215
216 sockopt_cork(mp->fd, 1);
217
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 */
226 num = write(mp->fd, stream_pnt(s), writenum);
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");
239 return 0;
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
282 sockopt_cork(mp->fd, 0);
283
284 if (PIM_DEBUG_MSDP_INTERNAL) {
285 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
286 mp->key_str, work_cnt);
287 }
288
289 return 0;
290 }
291
292 static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
293 {
294 /* Add packet to the end of list. */
295 pim_msdp_pkt_add(mp, s);
296
297 PIM_MSDP_PEER_WRITE_ON(mp);
298 }
299
300 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
301 {
302 struct stream *s;
303
304 if (mp->state != PIM_MSDP_ESTABLISHED) {
305 /* don't tx anything unless a session is established */
306 return;
307 }
308 s = stream_new(PIM_MSDP_KA_TLV_MAX_SIZE);
309 stream_putc(s, PIM_MSDP_KEEPALIVE);
310 stream_putw(s, PIM_MSDP_KA_TLV_MAX_SIZE);
311
312 pim_msdp_pkt_send(mp, s);
313 }
314
315 static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
316 struct pim_msdp_peer *mp)
317 {
318 struct stream *s;
319
320 if (mp->state != PIM_MSDP_ESTABLISHED) {
321 /* don't tx anything unless a session is established */
322 return;
323 }
324 s = stream_dup(pim->msdp.work_obuf);
325 if (s) {
326 pim_msdp_pkt_send(mp, s);
327 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
328 }
329 }
330
331 /* push the stream into the obuf fifo of all the peers */
332 static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
333 struct pim_msdp_peer *mp)
334 {
335 struct listnode *mpnode;
336
337 if (mp) {
338 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
339 } else {
340 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
341 if (PIM_DEBUG_MSDP_INTERNAL) {
342 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
343 mp->key_str);
344 }
345 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
346 }
347 }
348 }
349
350 static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt)
351 {
352 int curr_tlv_ecnt;
353
354 stream_reset(pim->msdp.work_obuf);
355 curr_tlv_ecnt = local_cnt > PIM_MSDP_SA_MAX_ENTRY_CNT
356 ? PIM_MSDP_SA_MAX_ENTRY_CNT
357 : local_cnt;
358 local_cnt -= curr_tlv_ecnt;
359 stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
360 stream_putw(pim->msdp.work_obuf,
361 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
362 stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
363 stream_put_ipv4(pim->msdp.work_obuf, pim->msdp.originator_id.s_addr);
364
365 return local_cnt;
366 }
367
368 static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
369 {
370 stream_put3(sa->pim->msdp.work_obuf, 0 /* reserved */);
371 stream_putc(sa->pim->msdp.work_obuf, 32 /* sprefix len */);
372 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.grp.s_addr);
373 stream_put_ipv4(sa->pim->msdp.work_obuf, sa->sg.src.s_addr);
374 }
375
376 static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
377 struct pim_msdp_peer *mp)
378 {
379 struct listnode *sanode;
380 struct pim_msdp_sa *sa;
381 int sa_count;
382 int local_cnt = pim->msdp.local_cnt;
383
384 sa_count = 0;
385 if (PIM_DEBUG_MSDP_INTERNAL) {
386 zlog_debug(" sa gen %d", local_cnt);
387 }
388
389 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt);
390
391 for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
392 if (!(sa->flags & PIM_MSDP_SAF_LOCAL)) {
393 /* current implementation of MSDP is for anycast i.e.
394 * full mesh. so
395 * no re-forwarding of SAs that we learnt from other
396 * 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(pim, mp);
404 /* reset headers */
405 sa_count = 0;
406 if (PIM_DEBUG_MSDP_INTERNAL) {
407 zlog_debug(" sa gen for remainder %d",
408 local_cnt);
409 }
410 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt);
411 }
412 }
413
414 if (sa_count) {
415 pim_msdp_pkt_sa_push(pim, mp);
416 }
417 return;
418 }
419
420 static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
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(pim->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
435 void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
436 {
437 pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
438 pim_msdp_pkt_sa_tx_done(pim);
439 }
440
441 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
442 {
443 pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */);
444 pim_msdp_pkt_sa_fill_one(sa);
445 pim_msdp_pkt_sa_push(sa->pim, NULL);
446 pim_msdp_pkt_sa_tx_done(sa->pim);
447 }
448
449 /* when a connection is first established we push all SAs immediately */
450 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
451 {
452 pim_msdp_pkt_sa_gen(mp->pim, mp);
453 pim_msdp_pkt_sa_tx_done(mp->pim);
454 }
455
456 static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
457 {
458 pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
459 }
460
461 static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
462 {
463 mp->ka_rx_cnt++;
464 if (len != PIM_MSDP_KA_TLV_MAX_SIZE) {
465 pim_msdp_pkt_rxed_with_fatal_error(mp);
466 return;
467 }
468 pim_msdp_peer_pkt_rxed(mp);
469 }
470
471 static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
472 {
473 int prefix_len;
474 struct prefix_sg sg;
475
476 /* just throw away the three reserved bytes */
477 stream_get3(mp->ibuf);
478 prefix_len = stream_getc(mp->ibuf);
479
480 memset(&sg, 0, sizeof(struct prefix_sg));
481 sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
482 sg.src.s_addr = stream_get_ipv4(mp->ibuf);
483
484 if (prefix_len != 32) {
485 /* ignore SA update if the prefix length is not 32 */
486 zlog_err("rxed sa update with invalid prefix length %d",
487 prefix_len);
488 return;
489 }
490 if (PIM_DEBUG_MSDP_PACKETS) {
491 zlog_debug(" sg %s", pim_str_sg_dump(&sg));
492 }
493 pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
494 }
495
496 static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
497 {
498 int entry_cnt;
499 int i;
500 struct in_addr rp; /* Last RP address associated with this SA */
501
502 mp->sa_rx_cnt++;
503
504 if (len < PIM_MSDP_SA_TLV_MIN_SIZE) {
505 pim_msdp_pkt_rxed_with_fatal_error(mp);
506 return;
507 }
508
509 entry_cnt = stream_getc(mp->ibuf);
510 /* some vendors include the actual multicast data in the tlv (at the
511 * end).
512 * we will ignore such data. in the future we may consider pushing it
513 * down
514 * the RPT */
515 if (len < PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt)) {
516 pim_msdp_pkt_rxed_with_fatal_error(mp);
517 return;
518 }
519 rp.s_addr = stream_get_ipv4(mp->ibuf);
520
521 if (PIM_DEBUG_MSDP_PACKETS) {
522 char rp_str[INET_ADDRSTRLEN];
523 pim_inet4_dump("<rp?>", rp, rp_str, sizeof(rp_str));
524 zlog_debug(" entry_cnt %d rp %s", entry_cnt, rp_str);
525 }
526
527 if (!pim_msdp_peer_rpf_check(mp, rp)) {
528 /* if peer-RPF check fails don't process the packet any further
529 */
530 if (PIM_DEBUG_MSDP_PACKETS) {
531 zlog_debug(" peer RPF check failed");
532 }
533 return;
534 }
535
536 pim_msdp_peer_pkt_rxed(mp);
537
538 /* update SA cache */
539 for (i = 0; i < entry_cnt; ++i) {
540 pim_msdp_pkt_sa_rx_one(mp, rp);
541 }
542 }
543
544 static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
545 {
546 enum pim_msdp_tlv type;
547 int len;
548
549 /* re-read type and len */
550 type = stream_getc_from(mp->ibuf, 0);
551 len = stream_getw_from(mp->ibuf, 1);
552 if (len < PIM_MSDP_HEADER_SIZE) {
553 pim_msdp_pkt_rxed_with_fatal_error(mp);
554 return;
555 }
556
557 if (len > PIM_MSDP_SA_TLV_MAX_SIZE) {
558 /* if tlv size if greater than max just ignore the tlv */
559 return;
560 }
561
562 if (PIM_DEBUG_MSDP_PACKETS) {
563 pim_msdp_pkt_dump(mp, type, len, true /*rx*/, NULL /*s*/);
564 }
565
566 switch (type) {
567 case PIM_MSDP_KEEPALIVE:
568 pim_msdp_pkt_ka_rx(mp, len);
569 break;
570 case PIM_MSDP_V4_SOURCE_ACTIVE:
571 mp->sa_rx_cnt++;
572 pim_msdp_pkt_sa_rx(mp, len);
573 break;
574 default:
575 mp->unk_rx_cnt++;
576 }
577 }
578
579 /* pim msdp read utility function. */
580 static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
581 {
582 int nbytes;
583 int readsize;
584 int old_endp;
585 int new_endp;
586
587 old_endp = stream_get_endp(mp->ibuf);
588 readsize = mp->packet_size - old_endp;
589 if (!readsize) {
590 return 0;
591 }
592
593 /* Read packet from fd */
594 nbytes = stream_read_try(mp->ibuf, mp->fd, readsize);
595 new_endp = stream_get_endp(mp->ibuf);
596 if (nbytes < 0) {
597 if (PIM_DEBUG_MSDP_INTERNAL) {
598 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
599 nbytes);
600 }
601 if (nbytes == -2) {
602 if (PIM_DEBUG_MSDP_INTERNAL) {
603 zlog_debug(
604 "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
605 mp->key_str, old_endp, new_endp);
606 }
607 /* transient error retry */
608 return -1;
609 }
610 pim_msdp_pkt_rxed_with_fatal_error(mp);
611 return -1;
612 }
613
614 if (!nbytes) {
615 if (PIM_DEBUG_MSDP_INTERNAL) {
616 zlog_debug("MSDP peer %s read failed %d", mp->key_str,
617 nbytes);
618 }
619 pim_msdp_peer_reset_tcp_conn(mp, "peer-down");
620 return -1;
621 }
622
623 /* We read partial packet. */
624 if (stream_get_endp(mp->ibuf) != mp->packet_size) {
625 if (PIM_DEBUG_MSDP_INTERNAL) {
626 zlog_debug(
627 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
628 mp->key_str, mp->packet_size, old_endp,
629 new_endp);
630 }
631 return -1;
632 }
633
634 return 0;
635 }
636
637 int pim_msdp_read(struct thread *thread)
638 {
639 struct pim_msdp_peer *mp;
640 int rc;
641 uint32_t len;
642
643 mp = THREAD_ARG(thread);
644 mp->t_read = NULL;
645
646 if (PIM_DEBUG_MSDP_INTERNAL) {
647 zlog_debug("MSDP peer %s pim_msdp_read", mp->key_str);
648 }
649
650 if (mp->fd < 0) {
651 return -1;
652 }
653
654 /* check if TCP connection is established */
655 if (mp->state != PIM_MSDP_ESTABLISHED) {
656 pim_msdp_connect_check(mp);
657 return 0;
658 }
659
660 PIM_MSDP_PEER_READ_ON(mp);
661
662 if (!mp->packet_size) {
663 mp->packet_size = PIM_MSDP_HEADER_SIZE;
664 }
665
666 if (stream_get_endp(mp->ibuf) < PIM_MSDP_HEADER_SIZE) {
667 /* start by reading the TLV header */
668 rc = pim_msdp_read_packet(mp);
669 if (rc < 0) {
670 goto pim_msdp_read_end;
671 }
672
673 /* Find TLV type and len */
674 stream_getc(mp->ibuf);
675 len = stream_getw(mp->ibuf);
676 if (len < PIM_MSDP_HEADER_SIZE) {
677 pim_msdp_pkt_rxed_with_fatal_error(mp);
678 goto pim_msdp_read_end;
679 }
680 /* read complete TLV */
681 mp->packet_size = len;
682 }
683
684 rc = pim_msdp_read_packet(mp);
685 if (rc < 0) {
686 goto pim_msdp_read_end;
687 }
688
689 pim_msdp_pkt_rx(mp);
690
691 /* reset input buffers and get ready for the next packet */
692 mp->packet_size = 0;
693 stream_reset(mp->ibuf);
694
695 pim_msdp_read_end:
696 return 0;
697 }