+ struct inpcb *inp = sotoinpcb(so);
+ sae_associd_t aid;
+
+ if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD)
+ return (EINVAL);
+
+ /* INPCB has no concept of association */
+ aid = SAE_ASSOCID_ANY;
+ *cnt = 0;
+
+ /* just asking how many there are? */
+ if (aidp == USER_ADDR_NULL)
+ return (0);
+
+ return (copyout(&aid, aidp, sizeof (aid)));
+}
+
+/*
+ * Handle SIOCGCONNIDS ioctl for PF_INET domain.
+ */
+static int
+in_getconnids(struct socket *so, sae_associd_t aid, uint32_t *cnt,
+ user_addr_t cidp)
+{
+ struct inpcb *inp = sotoinpcb(so);
+ sae_connid_t cid;
+
+ if (inp == NULL || inp->inp_state == INPCB_STATE_DEAD)
+ return (EINVAL);
+
+ if (aid != SAE_ASSOCID_ANY && aid != SAE_ASSOCID_ALL)
+ return (EINVAL);
+
+ /* if connected, return 1 connection count */
+ *cnt = ((so->so_state & SS_ISCONNECTED) ? 1 : 0);
+
+ /* just asking how many there are? */
+ if (cidp == USER_ADDR_NULL)
+ return (0);
+
+ /* if INPCB is connected, assign it connid 1 */
+ cid = ((*cnt != 0) ? 1 : SAE_CONNID_ANY);
+
+ return (copyout(&cid, cidp, sizeof (cid)));
+}
+
+/*
+ * Handle SIOCGCONNINFO ioctl for PF_INET domain.
+ */
+static int
+in_getconninfo(struct socket *so, sae_connid_t cid, uint32_t *flags,
+ uint32_t *ifindex, int32_t *soerror, user_addr_t src, socklen_t *src_len,
+ user_addr_t dst, socklen_t *dst_len, uint32_t *aux_type,
+ user_addr_t aux_data, uint32_t *aux_len)
+{
+#pragma unused(aux_data)
+ struct inpcb *inp = sotoinpcb(so);
+ struct sockaddr_in sin;
+ struct ifnet *ifp = NULL;
+ int error = 0;
+ u_int32_t copy_len = 0;
+
+ /*
+ * Don't test for INPCB_STATE_DEAD since this may be called
+ * after SOF_PCBCLEARING is set, e.g. after tcp_close().
+ */
+ if (inp == NULL) {
+ error = EINVAL;
+ goto out;
+ }
+
+ if (cid != SAE_CONNID_ANY && cid != SAE_CONNID_ALL && cid != 1) {
+ error = EINVAL;
+ goto out;
+ }
+
+ ifp = inp->inp_last_outifp;
+ *ifindex = ((ifp != NULL) ? ifp->if_index : 0);
+ *soerror = so->so_error;
+ *flags = 0;
+ if (so->so_state & SS_ISCONNECTED)
+ *flags |= (CIF_CONNECTED | CIF_PREFERRED);
+ if (inp->inp_flags & INP_BOUND_IF)
+ *flags |= CIF_BOUND_IF;
+ if (!(inp->inp_flags & INP_INADDR_ANY))
+ *flags |= CIF_BOUND_IP;
+ if (!(inp->inp_flags & INP_ANONPORT))
+ *flags |= CIF_BOUND_PORT;
+
+ bzero(&sin, sizeof (sin));
+ sin.sin_len = sizeof (sin);
+ sin.sin_family = AF_INET;
+
+ /* source address and port */
+ sin.sin_port = inp->inp_lport;
+ sin.sin_addr.s_addr = inp->inp_laddr.s_addr;
+ if (*src_len == 0) {
+ *src_len = sin.sin_len;
+ } else {
+ if (src != USER_ADDR_NULL) {
+ copy_len = min(*src_len, sizeof (sin));
+ error = copyout(&sin, src, copy_len);
+ if (error != 0)
+ goto out;
+ *src_len = copy_len;
+ }
+ }
+
+ /* destination address and port */
+ sin.sin_port = inp->inp_fport;
+ sin.sin_addr.s_addr = inp->inp_faddr.s_addr;
+ if (*dst_len == 0) {
+ *dst_len = sin.sin_len;
+ } else {
+ if (dst != USER_ADDR_NULL) {
+ copy_len = min(*dst_len, sizeof (sin));
+ error = copyout(&sin, dst, copy_len);
+ if (error != 0)
+ goto out;
+ *dst_len = copy_len;
+ }
+ }
+
+ *aux_type = 0;
+ *aux_len = 0;
+ if (SOCK_PROTO(so) == IPPROTO_TCP) {
+ struct conninfo_tcp tcp_ci;
+
+ *aux_type = CIAUX_TCP;
+ if (*aux_len == 0) {
+ *aux_len = sizeof (tcp_ci);
+ } else {
+ if (aux_data != USER_ADDR_NULL) {
+ copy_len = min(*aux_len, sizeof (tcp_ci));
+ bzero(&tcp_ci, sizeof (tcp_ci));
+ tcp_getconninfo(so, &tcp_ci);
+ error = copyout(&tcp_ci, aux_data, copy_len);
+ if (error != 0)
+ goto out;
+ *aux_len = copy_len;
+ }
+ }
+ }
+
+out:
+ return (error);