+
+__private_extern__ int
+inp_limit_companion_link(struct inpcbinfo *pcbinfo, u_int32_t limit)
+{
+ struct inpcb *inp;
+ struct socket *so = NULL;
+
+ lck_rw_lock_shared(pcbinfo->ipi_lock);
+ inp_gen_t gencnt = pcbinfo->ipi_gencnt;
+ for (inp = LIST_FIRST(pcbinfo->ipi_listhead);
+ inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+ if (inp->inp_gencnt <= gencnt &&
+ inp->inp_state != INPCB_STATE_DEAD &&
+ inp->inp_socket != NULL) {
+ so = inp->inp_socket;
+
+ if ((so->so_state & SS_DEFUNCT) || so->so_state & SS_ISDISCONNECTED ||
+ SOCK_PROTO(so) != IPPROTO_TCP || inp->inp_last_outifp == NULL ||
+ !IFNET_IS_COMPANION_LINK(inp->inp_last_outifp)) {
+ continue;
+ }
+ so->so_snd.sb_flags &= ~SB_LIMITED;
+ u_int32_t new_size = MAX(MIN(limit, so->so_snd.sb_lowat), so->so_snd.sb_cc);
+ sbreserve(&so->so_snd, new_size);
+ so->so_snd.sb_flags |= SB_LIMITED;
+ }
+ }
+ lck_rw_done(pcbinfo->ipi_lock);
+ return 0;
+}
+
+__private_extern__ int
+inp_recover_companion_link(struct inpcbinfo *pcbinfo)
+{
+ struct inpcb *inp;
+ inp_gen_t gencnt = pcbinfo->ipi_gencnt;
+ struct socket *so = NULL;
+
+ lck_rw_lock_shared(pcbinfo->ipi_lock);
+ for (inp = LIST_FIRST(pcbinfo->ipi_listhead);
+ inp != NULL; inp = LIST_NEXT(inp, inp_list)) {
+ if (inp->inp_gencnt <= gencnt &&
+ inp->inp_state != INPCB_STATE_DEAD &&
+ inp->inp_socket != NULL) {
+ so = inp->inp_socket;
+
+ if (SOCK_PROTO(so) != IPPROTO_TCP || inp->inp_last_outifp == NULL ||
+ !(so->so_snd.sb_flags & SB_LIMITED)) {
+ continue;
+ }
+
+ so->so_snd.sb_flags &= ~SB_LIMITED;
+ }
+ }
+ lck_rw_done(pcbinfo->ipi_lock);
+ return 0;
+}