1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IP MSDP packet helper
4 * Copyright (C) 2016 Cumulus Networks, Inc.
9 #include <lib/network.h>
10 #include <lib/stream.h>
11 #include <lib/thread.h>
13 #include <lib/lib_errors.h>
16 #include "pim_instance.h"
18 #include "pim_errors.h"
21 #include "pim_msdp_packet.h"
22 #include "pim_msdp_socket.h"
24 static char *pim_msdp_pkt_type_dump(enum pim_msdp_tlv type
, char *buf
,
28 case PIM_MSDP_V4_SOURCE_ACTIVE
:
29 snprintf(buf
, buf_size
, "%s", "SA");
31 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST
:
32 snprintf(buf
, buf_size
, "%s", "SA_REQ");
34 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE
:
35 snprintf(buf
, buf_size
, "%s", "SA_RESP");
37 case PIM_MSDP_KEEPALIVE
:
38 snprintf(buf
, buf_size
, "%s", "KA");
40 case PIM_MSDP_RESERVED
:
41 snprintf(buf
, buf_size
, "%s", "RSVD");
43 case PIM_MSDP_TRACEROUTE_PROGRESS
:
44 snprintf(buf
, buf_size
, "%s", "TRACE_PROG");
46 case PIM_MSDP_TRACEROUTE_REPLY
:
47 snprintf(buf
, buf_size
, "%s", "TRACE_REPLY");
50 snprintf(buf
, buf_size
, "UNK-%d", type
);
55 static void pim_msdp_pkt_sa_dump_one(struct stream
*s
)
59 /* just throw away the three reserved bytes */
61 /* throw away the prefix length also */
64 memset(&sg
, 0, sizeof(sg
));
65 sg
.grp
.s_addr
= stream_get_ipv4(s
);
66 sg
.src
.s_addr
= stream_get_ipv4(s
);
68 zlog_debug(" sg %pSG", &sg
);
71 static void pim_msdp_pkt_sa_dump(struct stream
*s
)
73 const size_t header_length
= PIM_MSDP_SA_X_SIZE
- PIM_MSDP_HEADER_SIZE
;
74 size_t payload_length
;
77 struct in_addr rp
; /* Last RP address associated with this SA */
79 if (header_length
> STREAM_READABLE(s
)) {
80 zlog_err("BUG MSDP SA bad header (readable %zu expected %zu)",
81 STREAM_READABLE(s
), header_length
);
85 entry_cnt
= stream_getc(s
);
86 rp
.s_addr
= stream_get_ipv4(s
);
88 if (PIM_DEBUG_MSDP_PACKETS
) {
89 char rp_str
[INET_ADDRSTRLEN
];
90 pim_inet4_dump("<rp?>", rp
, rp_str
, sizeof(rp_str
));
91 zlog_debug(" entry_cnt %d rp %s", entry_cnt
, rp_str
);
94 payload_length
= (size_t)entry_cnt
* PIM_MSDP_SA_ONE_ENTRY_SIZE
;
95 if (payload_length
> STREAM_READABLE(s
)) {
96 zlog_err("BUG MSDP SA bad length (readable %zu expected %zu)",
97 STREAM_READABLE(s
), payload_length
);
102 for (i
= 0; i
< entry_cnt
; ++i
) {
103 pim_msdp_pkt_sa_dump_one(s
);
107 static void pim_msdp_pkt_dump(struct pim_msdp_peer
*mp
, int type
, int len
,
108 bool rx
, struct stream
*s
)
110 char type_str
[PIM_MSDP_PKT_TYPE_STRLEN
];
112 pim_msdp_pkt_type_dump(type
, type_str
, sizeof(type_str
));
114 zlog_debug("MSDP peer %s pkt %s type %s len %d", mp
->key_str
,
115 rx
? "rx" : "tx", type_str
, len
);
121 if (len
< PIM_MSDP_HEADER_SIZE
) {
122 zlog_err("invalid MSDP header length");
127 case PIM_MSDP_V4_SOURCE_ACTIVE
:
128 pim_msdp_pkt_sa_dump(s
);
134 /* Check file descriptor whether connect is established. */
135 static void pim_msdp_connect_check(struct pim_msdp_peer
*mp
)
141 if (mp
->state
!= PIM_MSDP_CONNECTING
) {
142 /* if we are here it means we are not in a connecting or
144 * for now treat this as a fatal error */
145 pim_msdp_peer_reset_tcp_conn(mp
, "invalid-state");
149 PIM_MSDP_PEER_READ_OFF(mp
);
150 PIM_MSDP_PEER_WRITE_OFF(mp
);
152 /* Check file descriptor. */
153 slen
= sizeof(status
);
154 ret
= getsockopt(mp
->fd
, SOL_SOCKET
, SO_ERROR
, (void *)&status
, &slen
);
156 /* If getsockopt is fail, this is fatal error. */
158 flog_err_sys(EC_LIB_SOCKET
,
159 "can't get sockopt for nonblocking connect");
160 pim_msdp_peer_reset_tcp_conn(mp
, "connect-failed");
164 /* When status is 0 then TCP connection is established. */
165 if (PIM_DEBUG_MSDP_INTERNAL
) {
166 zlog_debug("MSDP peer %s pim_connect_check %s", mp
->key_str
,
167 status
? "fail" : "success");
170 pim_msdp_peer_established(mp
);
172 pim_msdp_peer_reset_tcp_conn(mp
, "connect-failed");
176 static void pim_msdp_pkt_delete(struct pim_msdp_peer
*mp
)
178 stream_free(stream_fifo_pop(mp
->obuf
));
181 static void pim_msdp_pkt_add(struct pim_msdp_peer
*mp
, struct stream
*s
)
183 stream_fifo_push(mp
->obuf
, s
);
186 static void pim_msdp_write_proceed_actions(struct pim_msdp_peer
*mp
)
188 if (stream_fifo_head(mp
->obuf
)) {
189 PIM_MSDP_PEER_WRITE_ON(mp
);
193 void pim_msdp_write(struct thread
*thread
)
195 struct pim_msdp_peer
*mp
;
198 enum pim_msdp_tlv type
;
201 int work_max_cnt
= 100;
203 mp
= THREAD_ARG(thread
);
206 if (PIM_DEBUG_MSDP_INTERNAL
) {
207 zlog_debug("MSDP peer %s pim_msdp_write", mp
->key_str
);
213 /* check if TCP connection is established */
214 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
215 pim_msdp_connect_check(mp
);
219 s
= stream_fifo_head(mp
->obuf
);
221 pim_msdp_write_proceed_actions(mp
);
225 /* Nonblocking write until TCP output buffer is full */
229 /* Number of bytes to be sent */
230 writenum
= stream_get_endp(s
) - stream_get_getp(s
);
232 /* Call write() system call */
233 num
= write(mp
->fd
, stream_pnt(s
), writenum
);
235 /* write failed either retry needed or error */
236 if (ERRNO_IO_RETRY(errno
)) {
237 if (PIM_DEBUG_MSDP_INTERNAL
) {
239 "MSDP peer %s pim_msdp_write io retry",
245 pim_msdp_peer_reset_tcp_conn(mp
, "pkt-tx-failed");
249 if (num
!= writenum
) {
251 stream_forward_getp(s
, num
);
252 if (PIM_DEBUG_MSDP_INTERNAL
) {
254 "MSDP peer %s pim_msdp_partial_write",
260 /* Retrieve msdp packet type. */
261 stream_set_getp(s
, 0);
262 type
= stream_getc(s
);
263 len
= stream_getw(s
);
265 case PIM_MSDP_KEEPALIVE
:
268 case PIM_MSDP_V4_SOURCE_ACTIVE
:
271 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST
:
272 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE
:
273 case PIM_MSDP_RESERVED
:
274 case PIM_MSDP_TRACEROUTE_PROGRESS
:
275 case PIM_MSDP_TRACEROUTE_REPLY
:
278 if (PIM_DEBUG_MSDP_PACKETS
) {
279 pim_msdp_pkt_dump(mp
, type
, len
, false /*rx*/, s
);
282 /* packet sent delete it. */
283 pim_msdp_pkt_delete(mp
);
286 /* may need to pause if we have done too much work in this
288 if (work_cnt
>= work_max_cnt
) {
291 } while ((s
= stream_fifo_head(mp
->obuf
)) != NULL
);
292 pim_msdp_write_proceed_actions(mp
);
294 if (PIM_DEBUG_MSDP_INTERNAL
) {
295 zlog_debug("MSDP peer %s pim_msdp_write wrote %d packets",
296 mp
->key_str
, work_cnt
);
300 static void pim_msdp_pkt_send(struct pim_msdp_peer
*mp
, struct stream
*s
)
302 /* Add packet to the end of list. */
303 pim_msdp_pkt_add(mp
, s
);
305 PIM_MSDP_PEER_WRITE_ON(mp
);
308 void pim_msdp_pkt_ka_tx(struct pim_msdp_peer
*mp
)
312 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
313 /* don't tx anything unless a session is established */
316 s
= stream_new(PIM_MSDP_KA_TLV_MAX_SIZE
);
317 stream_putc(s
, PIM_MSDP_KEEPALIVE
);
318 stream_putw(s
, PIM_MSDP_KA_TLV_MAX_SIZE
);
320 pim_msdp_pkt_send(mp
, s
);
323 static void pim_msdp_pkt_sa_push_to_one_peer(struct pim_instance
*pim
,
324 struct pim_msdp_peer
*mp
)
328 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
329 /* don't tx anything unless a session is established */
332 s
= stream_dup(pim
->msdp
.work_obuf
);
334 pim_msdp_pkt_send(mp
, s
);
335 mp
->flags
|= PIM_MSDP_PEERF_SA_JUST_SENT
;
339 /* push the stream into the obuf fifo of all the peers */
340 static void pim_msdp_pkt_sa_push(struct pim_instance
*pim
,
341 struct pim_msdp_peer
*mp
)
343 struct listnode
*mpnode
;
346 pim_msdp_pkt_sa_push_to_one_peer(pim
, mp
);
348 for (ALL_LIST_ELEMENTS_RO(pim
->msdp
.peer_list
, mpnode
, mp
)) {
349 if (PIM_DEBUG_MSDP_INTERNAL
) {
350 zlog_debug("MSDP peer %s pim_msdp_pkt_sa_push",
353 pim_msdp_pkt_sa_push_to_one_peer(pim
, mp
);
358 static int pim_msdp_pkt_sa_fill_hdr(struct pim_instance
*pim
, int local_cnt
,
363 stream_reset(pim
->msdp
.work_obuf
);
364 curr_tlv_ecnt
= local_cnt
> PIM_MSDP_SA_MAX_ENTRY_CNT
365 ? PIM_MSDP_SA_MAX_ENTRY_CNT
367 local_cnt
-= curr_tlv_ecnt
;
368 stream_putc(pim
->msdp
.work_obuf
, PIM_MSDP_V4_SOURCE_ACTIVE
);
369 stream_putw(pim
->msdp
.work_obuf
,
370 PIM_MSDP_SA_ENTRY_CNT2SIZE(curr_tlv_ecnt
));
371 stream_putc(pim
->msdp
.work_obuf
, curr_tlv_ecnt
);
372 stream_put_ipv4(pim
->msdp
.work_obuf
, rp
.s_addr
);
377 static void pim_msdp_pkt_sa_fill_one(struct pim_msdp_sa
*sa
)
379 stream_put3(sa
->pim
->msdp
.work_obuf
, 0 /* reserved */);
380 stream_putc(sa
->pim
->msdp
.work_obuf
, 32 /* sprefix len */);
381 stream_put_ipv4(sa
->pim
->msdp
.work_obuf
, sa
->sg
.grp
.s_addr
);
382 stream_put_ipv4(sa
->pim
->msdp
.work_obuf
, sa
->sg
.src
.s_addr
);
385 static void pim_msdp_pkt_sa_gen(struct pim_instance
*pim
,
386 struct pim_msdp_peer
*mp
)
388 struct listnode
*sanode
;
389 struct pim_msdp_sa
*sa
;
391 int local_cnt
= pim
->msdp
.local_cnt
;
394 if (PIM_DEBUG_MSDP_INTERNAL
) {
395 zlog_debug(" sa gen %d", local_cnt
);
398 local_cnt
= pim_msdp_pkt_sa_fill_hdr(pim
, local_cnt
,
399 pim
->msdp
.originator_id
);
401 for (ALL_LIST_ELEMENTS_RO(pim
->msdp
.sa_list
, sanode
, sa
)) {
402 if (!(sa
->flags
& PIM_MSDP_SAF_LOCAL
)) {
403 /* current implementation of MSDP is for anycast i.e.
405 * no re-forwarding of SAs that we learnt from other
409 /* add sa into scratch pad */
410 pim_msdp_pkt_sa_fill_one(sa
);
412 if (sa_count
>= PIM_MSDP_SA_MAX_ENTRY_CNT
) {
413 pim_msdp_pkt_sa_push(pim
, mp
);
416 if (PIM_DEBUG_MSDP_INTERNAL
) {
417 zlog_debug(" sa gen for remainder %d",
420 local_cnt
= pim_msdp_pkt_sa_fill_hdr(
421 pim
, local_cnt
, pim
->msdp
.originator_id
);
426 pim_msdp_pkt_sa_push(pim
, mp
);
431 static void pim_msdp_pkt_sa_tx_done(struct pim_instance
*pim
)
433 struct listnode
*mpnode
;
434 struct pim_msdp_peer
*mp
;
436 /* if SA were sent to the peers we restart ka timer and avoid
437 * unnecessary ka noise */
438 for (ALL_LIST_ELEMENTS_RO(pim
->msdp
.peer_list
, mpnode
, mp
)) {
439 if (mp
->flags
& PIM_MSDP_PEERF_SA_JUST_SENT
) {
440 mp
->flags
&= ~PIM_MSDP_PEERF_SA_JUST_SENT
;
441 pim_msdp_peer_pkt_txed(mp
);
446 void pim_msdp_pkt_sa_tx(struct pim_instance
*pim
)
448 pim_msdp_pkt_sa_gen(pim
, NULL
/* mp */);
449 pim_msdp_pkt_sa_tx_done(pim
);
452 void pim_msdp_pkt_sa_tx_one(struct pim_msdp_sa
*sa
)
454 pim_msdp_pkt_sa_fill_hdr(sa
->pim
, 1 /* cnt */, sa
->rp
);
455 pim_msdp_pkt_sa_fill_one(sa
);
456 pim_msdp_pkt_sa_push(sa
->pim
, NULL
);
457 pim_msdp_pkt_sa_tx_done(sa
->pim
);
460 /* when a connection is first established we push all SAs immediately */
461 void pim_msdp_pkt_sa_tx_to_one_peer(struct pim_msdp_peer
*mp
)
463 pim_msdp_pkt_sa_gen(mp
->pim
, mp
);
464 pim_msdp_pkt_sa_tx_done(mp
->pim
);
467 void pim_msdp_pkt_sa_tx_one_to_one_peer(struct pim_msdp_peer
*mp
,
468 struct in_addr rp
, pim_sgaddr sg
)
470 struct pim_msdp_sa sa
;
472 /* Fills the SA header. */
473 pim_msdp_pkt_sa_fill_hdr(mp
->pim
, 1, rp
);
475 /* Fills the message contents. */
478 pim_msdp_pkt_sa_fill_one(&sa
);
480 /* Pushes the message. */
481 pim_msdp_pkt_sa_push(sa
.pim
, mp
);
482 pim_msdp_pkt_sa_tx_done(sa
.pim
);
485 static void pim_msdp_pkt_rxed_with_fatal_error(struct pim_msdp_peer
*mp
)
487 pim_msdp_peer_reset_tcp_conn(mp
, "invalid-pkt-rx");
490 static void pim_msdp_pkt_ka_rx(struct pim_msdp_peer
*mp
, int len
)
493 if (len
!= PIM_MSDP_KA_TLV_MAX_SIZE
) {
494 pim_msdp_pkt_rxed_with_fatal_error(mp
);
497 pim_msdp_peer_pkt_rxed(mp
);
500 static void pim_msdp_pkt_sa_rx_one(struct pim_msdp_peer
*mp
, struct in_addr rp
)
504 struct listnode
*peer_node
;
505 struct pim_msdp_peer
*peer
;
507 /* just throw away the three reserved bytes */
508 stream_get3(mp
->ibuf
);
509 prefix_len
= stream_getc(mp
->ibuf
);
511 memset(&sg
, 0, sizeof(sg
));
512 sg
.grp
.s_addr
= stream_get_ipv4(mp
->ibuf
);
513 sg
.src
.s_addr
= stream_get_ipv4(mp
->ibuf
);
515 if (prefix_len
!= IPV4_MAX_BITLEN
) {
516 /* ignore SA update if the prefix length is not 32 */
517 flog_err(EC_PIM_MSDP_PACKET
,
518 "rxed sa update with invalid prefix length %d",
522 if (PIM_DEBUG_MSDP_PACKETS
) {
523 zlog_debug(" sg %pSG", &sg
);
525 pim_msdp_sa_ref(mp
->pim
, mp
, &sg
, rp
);
527 /* Forwards the SA to the peers that are not in the RPF to the RP nor in
528 * the same mesh group as the peer from which we received the message.
529 * If the message group is not set, i.e. "default", then we assume that
530 * the message must be forwarded.*/
531 for (ALL_LIST_ELEMENTS_RO(mp
->pim
->msdp
.peer_list
, peer_node
, peer
)) {
532 /* Not a RPF peer, so skip it. */
533 if (pim_msdp_peer_rpf_check(peer
, rp
))
535 /* Don't forward inside the meshed group. */
536 if ((mp
->flags
& PIM_MSDP_PEERF_IN_GROUP
)
537 && strcmp(mp
->mesh_group_name
, peer
->mesh_group_name
) == 0)
540 pim_msdp_pkt_sa_tx_one_to_one_peer(peer
, rp
, sg
);
544 static void pim_msdp_pkt_sa_rx(struct pim_msdp_peer
*mp
, int len
)
548 struct in_addr rp
; /* Last RP address associated with this SA */
552 if (len
< PIM_MSDP_SA_TLV_MIN_SIZE
) {
553 pim_msdp_pkt_rxed_with_fatal_error(mp
);
557 entry_cnt
= stream_getc(mp
->ibuf
);
558 /* some vendors include the actual multicast data in the tlv (at the
559 * end). we will ignore such data. in the future we may consider pushing
562 if (len
< PIM_MSDP_SA_ENTRY_CNT2SIZE(entry_cnt
)) {
563 pim_msdp_pkt_rxed_with_fatal_error(mp
);
566 rp
.s_addr
= stream_get_ipv4(mp
->ibuf
);
568 if (PIM_DEBUG_MSDP_PACKETS
) {
569 char rp_str
[INET_ADDRSTRLEN
];
570 pim_inet4_dump("<rp?>", rp
, rp_str
, sizeof(rp_str
));
571 zlog_debug(" entry_cnt %d rp %s", entry_cnt
, rp_str
);
574 pim_msdp_peer_pkt_rxed(mp
);
576 if (!pim_msdp_peer_rpf_check(mp
, rp
)) {
577 /* if peer-RPF check fails don't process the packet any further
579 if (PIM_DEBUG_MSDP_PACKETS
) {
580 zlog_debug(" peer RPF check failed");
585 /* update SA cache */
586 for (i
= 0; i
< entry_cnt
; ++i
) {
587 pim_msdp_pkt_sa_rx_one(mp
, rp
);
591 static void pim_msdp_pkt_rx(struct pim_msdp_peer
*mp
)
593 enum pim_msdp_tlv type
;
596 /* re-read type and len */
597 type
= stream_getc_from(mp
->ibuf
, 0);
598 len
= stream_getw_from(mp
->ibuf
, 1);
599 if (len
< PIM_MSDP_HEADER_SIZE
) {
600 pim_msdp_pkt_rxed_with_fatal_error(mp
);
604 if (len
> PIM_MSDP_SA_TLV_MAX_SIZE
) {
605 /* if tlv size if greater than max just ignore the tlv */
609 if (PIM_DEBUG_MSDP_PACKETS
) {
610 pim_msdp_pkt_dump(mp
, type
, len
, true /*rx*/, NULL
/*s*/);
614 case PIM_MSDP_KEEPALIVE
:
615 pim_msdp_pkt_ka_rx(mp
, len
);
617 case PIM_MSDP_V4_SOURCE_ACTIVE
:
619 pim_msdp_pkt_sa_rx(mp
, len
);
621 case PIM_MSDP_V4_SOURCE_ACTIVE_REQUEST
:
622 case PIM_MSDP_V4_SOURCE_ACTIVE_RESPONSE
:
623 case PIM_MSDP_RESERVED
:
624 case PIM_MSDP_TRACEROUTE_PROGRESS
:
625 case PIM_MSDP_TRACEROUTE_REPLY
:
631 /* pim msdp read utility function. */
632 static int pim_msdp_read_packet(struct pim_msdp_peer
*mp
)
639 old_endp
= stream_get_endp(mp
->ibuf
);
640 readsize
= mp
->packet_size
- old_endp
;
645 /* Read packet from fd */
646 nbytes
= stream_read_try(mp
->ibuf
, mp
->fd
, readsize
);
647 new_endp
= stream_get_endp(mp
->ibuf
);
649 if (PIM_DEBUG_MSDP_INTERNAL
) {
650 zlog_debug("MSDP peer %s read failed %d", mp
->key_str
,
654 if (PIM_DEBUG_MSDP_INTERNAL
) {
656 "MSDP peer %s pim_msdp_read io retry old_end: %d new_end: %d",
657 mp
->key_str
, old_endp
, new_endp
);
659 /* transient error retry */
662 pim_msdp_pkt_rxed_with_fatal_error(mp
);
667 if (PIM_DEBUG_MSDP_INTERNAL
) {
668 zlog_debug("MSDP peer %s read failed %d", mp
->key_str
,
671 pim_msdp_peer_reset_tcp_conn(mp
, "peer-down");
675 /* We read partial packet. */
676 if (stream_get_endp(mp
->ibuf
) != mp
->packet_size
) {
677 if (PIM_DEBUG_MSDP_INTERNAL
) {
679 "MSDP peer %s read partial len %d old_endp %d new_endp %d",
680 mp
->key_str
, mp
->packet_size
, old_endp
,
689 void pim_msdp_read(struct thread
*thread
)
691 struct pim_msdp_peer
*mp
;
695 mp
= THREAD_ARG(thread
);
698 if (PIM_DEBUG_MSDP_INTERNAL
) {
699 zlog_debug("MSDP peer %s pim_msdp_read", mp
->key_str
);
706 /* check if TCP connection is established */
707 if (mp
->state
!= PIM_MSDP_ESTABLISHED
) {
708 pim_msdp_connect_check(mp
);
712 PIM_MSDP_PEER_READ_ON(mp
);
714 if (!mp
->packet_size
) {
715 mp
->packet_size
= PIM_MSDP_HEADER_SIZE
;
718 if (stream_get_endp(mp
->ibuf
) < PIM_MSDP_HEADER_SIZE
) {
719 /* start by reading the TLV header */
720 rc
= pim_msdp_read_packet(mp
);
724 /* Find TLV type and len */
725 stream_getc(mp
->ibuf
);
726 len
= stream_getw(mp
->ibuf
);
727 if (len
< PIM_MSDP_HEADER_SIZE
) {
728 pim_msdp_pkt_rxed_with_fatal_error(mp
);
733 * Handle messages with longer than expected TLV size: resize
734 * the stream to handle reading the whole message.
736 * RFC 3618 Section 12. 'Packet Formats':
737 * > ... If an implementation receives a TLV whose length
738 * > exceeds the maximum TLV length specified below, the TLV
739 * > SHOULD be accepted. Any additional data, including possible
740 * > next TLV's in the same message, SHOULD be ignored, and the
741 * > MSDP session should not be reset. ...
743 if (len
> PIM_MSDP_SA_TLV_MAX_SIZE
) {
744 /* Check if the current buffer is big enough. */
745 if (mp
->ibuf
->size
< len
) {
746 if (PIM_DEBUG_MSDP_PACKETS
)
748 "MSDP peer %s sent TLV with unexpected large length (%d bytes)",
751 stream_resize_inplace(&mp
->ibuf
, len
);
755 /* read complete TLV */
756 mp
->packet_size
= len
;
759 rc
= pim_msdp_read_packet(mp
);
765 /* reset input buffers and get ready for the next packet */
767 stream_reset(mp
->ibuf
);