-/*
- * The new sockopt interface makes it possible for us to block in the
- * copyin/out step (if we take a page fault). Taking a page fault at
- * splnet() is probably a Bad Thing. (Since sockets and pcbs both now
- * use TSM, there probably isn't any need for this function to run at
- * splnet() any more. This needs more examination.)
- */
+void
+tcp_clear_keep_alive_offload(struct socket *so)
+{
+ struct inpcb *inp;
+ struct ifnet *ifp;
+
+ inp = sotoinpcb(so);
+ if (inp == NULL) {
+ return;
+ }
+
+ if ((inp->inp_flags2 & INP2_KEEPALIVE_OFFLOAD) == 0) {
+ return;
+ }
+
+ ifp = inp->inp_boundifp != NULL ? inp->inp_boundifp :
+ inp->inp_last_outifp;
+ if (ifp == NULL) {
+ panic("%s: so %p inp %p ifp NULL",
+ __func__, so, inp);
+ }
+
+ ifnet_lock_exclusive(ifp);
+
+ if (ifp->if_tcp_kao_cnt == 0) {
+ panic("%s: so %p inp %p ifp %p if_tcp_kao_cnt == 0",
+ __func__, so, inp, ifp);
+ }
+ ifp->if_tcp_kao_cnt--;
+ inp->inp_flags2 &= ~INP2_KEEPALIVE_OFFLOAD;
+
+ ifnet_lock_done(ifp);
+}
+
+static int
+tcp_set_keep_alive_offload(struct socket *so, struct proc *proc)
+{
+ int error = 0;
+ struct inpcb *inp;
+ struct ifnet *ifp;
+
+ inp = sotoinpcb(so);
+ if (inp == NULL) {
+ return ECONNRESET;
+ }
+ if ((inp->inp_flags2 & INP2_KEEPALIVE_OFFLOAD) != 0) {
+ return 0;
+ }
+
+ ifp = inp->inp_boundifp != NULL ? inp->inp_boundifp :
+ inp->inp_last_outifp;
+ if (ifp == NULL) {
+ error = ENXIO;
+ os_log_info(OS_LOG_DEFAULT,
+ "%s: error %d for proc %s[%u] out ifp is not set\n",
+ __func__, error,
+ proc != NULL ? proc->p_comm : "kernel",
+ proc != NULL ? proc->p_pid : 0);
+ return ENXIO;
+ }
+
+ error = if_get_tcp_kao_max(ifp);
+ if (error != 0) {
+ return error;
+ }
+
+ ifnet_lock_exclusive(ifp);
+ if (ifp->if_tcp_kao_cnt < ifp->if_tcp_kao_max) {
+ ifp->if_tcp_kao_cnt++;
+ inp->inp_flags2 |= INP2_KEEPALIVE_OFFLOAD;
+ } else {
+ error = ETOOMANYREFS;
+ os_log_info(OS_LOG_DEFAULT,
+ "%s: error %d for proc %s[%u] if_tcp_kao_max %u\n",
+ __func__, error,
+ proc != NULL ? proc->p_comm : "kernel",
+ proc != NULL ? proc->p_pid : 0,
+ ifp->if_tcp_kao_max);
+ }
+ ifnet_lock_done(ifp);
+
+ return error;
+}
+
+/*
+ * The new sockopt interface makes it possible for us to block in the
+ * copyin/out step (if we take a page fault). Taking a page fault at
+ * splnet() is probably a Bad Thing. (Since sockets and pcbs both now
+ * use TSM, there probably isn't any need for this function to run at
+ * splnet() any more. This needs more examination.)
+ */