]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_msdp_packet.c
lib: Remove unnecessary comparison, for linked list
[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_instance.h"
30 #include "pim_str.h"
31 #include "pim_errors.h"
32
33 #include "pim_msdp.h"
34 #include "pim_msdp_packet.h"
35 #include "pim_msdp_socket.h"
36
37 static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type, char *buf,
38 int buf_size)
39 {
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;
66 }
67
68 static void pim_msdp_pkt_sa_dump_one(struct stream *s)
69 {
70 pim_sgaddr sg;
71
72 /* just throw away the three reserved bytes */
73 stream_get3(s);
74 /* throw away the prefix length also */
75 stream_getc(s);
76
77 memset(&sg, 0, sizeof(sg));
78 sg.grp.s_addr = stream_get_ipv4(s);
79 sg.src.s_addr = stream_get_ipv4(s);
80
81 zlog_debug(" sg %pSG", &sg);
82 }
83
84 static void pim_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
105 static void pim_msdp_pkt_dump(struct pim_msdp_peer *mp, int type, int len,
106 bool rx, struct stream *s)
107 {
108 char type_str[PIM_MSDP_PKT_TYPE_STRLEN];
109
110 pim_msdp_pkt_type_dump(type, type_str, sizeof(type_str));
111
112 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp->key_str,
113 rx ? "rx" : "tx", type_str, len);
114
115 if (!s) {
116 return;
117 }
118
119 switch (type) {
120 case PIM_MSDP_V4_SOURCE_ACTIVE:
121 pim_msdp_pkt_sa_dump(s);
122 break;
123 default:;
124 }
125 }
126
127 /* Check file descriptor whether connect is established. */
128 static void pim_msdp_connect_check(struct pim_msdp_peer *mp)
129 {
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) {
151 flog_err_sys(EC_LIB_SOCKET,
152 "can't get sockopt for nonblocking connect");
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 }
167 }
168
169 static void pim_msdp_pkt_delete(struct pim_msdp_peer *mp)
170 {
171 stream_free(stream_fifo_pop(mp->obuf));
172 }
173
174 static void pim_msdp_pkt_add(struct pim_msdp_peer *mp, struct stream *s)
175 {
176 stream_fifo_push(mp->obuf, s);
177 }
178
179 static void pim_msdp_write_proceed_actions(struct pim_msdp_peer *mp)
180 {
181 if (stream_fifo_head(mp->obuf)) {
182 PIM_MSDP_PEER_WRITE_ON(mp);
183 }
184 }
185
186 void pim_msdp_write(struct thread *thread)
187 {
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) {
203 return;
204 }
205
206 /* check if TCP connection is established */
207 if (mp->state != PIM_MSDP_ESTABLISHED) {
208 pim_msdp_connect_check(mp);
209 return;
210 }
211
212 s = stream_fifo_head(mp->obuf);
213 if (!s) {
214 pim_msdp_write_proceed_actions(mp);
215 return;
216 }
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;
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 if (PIM_DEBUG_MSDP_INTERNAL) {
283 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
284 mp->key_str, work_cnt);
285 }
286 }
287
288 static void pim_msdp_pkt_send(struct pim_msdp_peer *mp, struct stream *s)
289 {
290 /* Add packet to the end of list. */
291 pim_msdp_pkt_add(mp, s);
292
293 PIM_MSDP_PEER_WRITE_ON(mp);
294 }
295
296 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer *mp)
297 {
298 struct stream *s;
299
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);
307
308 pim_msdp_pkt_send(mp, s);
309 }
310
311 static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance *pim,
312 struct pim_msdp_peer *mp)
313 {
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 }
320 s = stream_dup(pim->msdp.work_obuf);
321 if (s) {
322 pim_msdp_pkt_send(mp, s);
323 mp->flags |= PIM_MSDP_PEERF_SA_JUST_SENT;
324 }
325 }
326
327 /* push the stream into the obuf fifo of all the peers */
328 static void pim_msdp_pkt_sa_push(struct pim_instance *pim,
329 struct pim_msdp_peer *mp)
330 {
331 struct listnode *mpnode;
332
333 if (mp) {
334 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
335 } else {
336 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
337 if (PIM_DEBUG_MSDP_INTERNAL) {
338 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
339 mp->key_str);
340 }
341 pim_msdp_pkt_sa_push_to_one_peer(pim, mp);
342 }
343 }
344 }
345
346 static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance *pim, int local_cnt,
347 struct in_addr rp)
348 {
349 int curr_tlv_ecnt;
350
351 stream_reset(pim->msdp.work_obuf);
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;
356 stream_putc(pim->msdp.work_obuf, PIM_MSDP_V4_SOURCE_ACTIVE);
357 stream_putw(pim->msdp.work_obuf,
358 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt));
359 stream_putc(pim->msdp.work_obuf, curr_tlv_ecnt);
360 stream_put_ipv4(pim->msdp.work_obuf, rp.s_addr);
361
362 return local_cnt;
363 }
364
365 static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa *sa)
366 {
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);
371 }
372
373 static void pim_msdp_pkt_sa_gen(struct pim_instance *pim,
374 struct pim_msdp_peer *mp)
375 {
376 struct listnode *sanode;
377 struct pim_msdp_sa *sa;
378 int sa_count;
379 int local_cnt = pim->msdp.local_cnt;
380
381 sa_count = 0;
382 if (PIM_DEBUG_MSDP_INTERNAL) {
383 zlog_debug(" sa gen %d", local_cnt);
384 }
385
386 local_cnt = pim_msdp_pkt_sa_fill_hdr(pim, local_cnt,
387 pim->msdp.originator_id);
388
389 for (ALL_LIST_ELEMENTS_RO(pim->msdp.sa_list, sanode, sa)) {
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) {
401 pim_msdp_pkt_sa_push(pim, mp);
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 }
408 local_cnt = pim_msdp_pkt_sa_fill_hdr(
409 pim, local_cnt, pim->msdp.originator_id);
410 }
411 }
412
413 if (sa_count) {
414 pim_msdp_pkt_sa_push(pim, mp);
415 }
416 return;
417 }
418
419 static void pim_msdp_pkt_sa_tx_done(struct pim_instance *pim)
420 {
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 */
426 for (ALL_LIST_ELEMENTS_RO(pim->msdp.peer_list, mpnode, mp)) {
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 }
432 }
433
434 void pim_msdp_pkt_sa_tx(struct pim_instance *pim)
435 {
436 pim_msdp_pkt_sa_gen(pim, NULL /* mp */);
437 pim_msdp_pkt_sa_tx_done(pim);
438 }
439
440 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa *sa)
441 {
442 pim_msdp_pkt_sa_fill_hdr(sa->pim, 1 /* cnt */, sa->rp);
443 pim_msdp_pkt_sa_fill_one(sa);
444 pim_msdp_pkt_sa_push(sa->pim, NULL);
445 pim_msdp_pkt_sa_tx_done(sa->pim);
446 }
447
448 /* when a connection is first established we push all SAs immediately */
449 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer *mp)
450 {
451 pim_msdp_pkt_sa_gen(mp->pim, mp);
452 pim_msdp_pkt_sa_tx_done(mp->pim);
453 }
454
455 void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer *mp,
456 struct in_addr rp, pim_sgaddr sg)
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
473 static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer *mp)
474 {
475 pim_msdp_peer_reset_tcp_conn(mp, "invalid-pkt-rx");
476 }
477
478 static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer *mp, int len)
479 {
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);
486 }
487
488 static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer *mp, struct in_addr rp)
489 {
490 int prefix_len;
491 pim_sgaddr sg;
492 struct listnode *peer_node;
493 struct pim_msdp_peer *peer;
494
495 /* just throw away the three reserved bytes */
496 stream_get3(mp->ibuf);
497 prefix_len = stream_getc(mp->ibuf);
498
499 memset(&sg, 0, sizeof(sg));
500 sg.grp.s_addr = stream_get_ipv4(mp->ibuf);
501 sg.src.s_addr = stream_get_ipv4(mp->ibuf);
502
503 if (prefix_len != IPV4_MAX_BITLEN) {
504 /* ignore SA update if the prefix length is not 32 */
505 flog_err(EC_PIM_MSDP_PACKET,
506 "rxed sa update with invalid prefix length %d",
507 prefix_len);
508 return;
509 }
510 if (PIM_DEBUG_MSDP_PACKETS) {
511 zlog_debug(" sg %pSG", &sg);
512 }
513 pim_msdp_sa_ref(mp->pim, mp, &sg, rp);
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)) {
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);
529 }
530 }
531
532 static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer *mp, int len)
533 {
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
547 * end). we will ignore such data. in the future we may consider pushing
548 * it down the RPT
549 */
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
562 pim_msdp_peer_pkt_rxed(mp);
563
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
573 /* update SA cache */
574 for (i = 0; i < entry_cnt; ++i) {
575 pim_msdp_pkt_sa_rx_one(mp, rp);
576 }
577 }
578
579 static void pim_msdp_pkt_rx(struct pim_msdp_peer *mp)
580 {
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 }
612 }
613
614 /* pim msdp read utility function. */
615 static int pim_msdp_read_packet(struct pim_msdp_peer *mp)
616 {
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;
670 }
671
672 void pim_msdp_read(struct thread *thread)
673 {
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) {
686 return;
687 }
688
689 /* check if TCP connection is established */
690 if (mp->state != PIM_MSDP_ESTABLISHED) {
691 pim_msdp_connect_check(mp);
692 return;
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);
704 if (rc < 0)
705 return;
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);
712 return;
713 }
714 /* read complete TLV */
715 mp->packet_size = len;
716 }
717
718 rc = pim_msdp_read_packet(mp);
719 if (rc < 0)
720 return;
721
722 pim_msdp_pkt_rx(mp);
723
724 /* reset input buffers and get ready for the next packet */
725 mp->packet_size = 0;
726 stream_reset(mp->ibuf);
727 }