1 /* UNIX Domain Sockets - stat.c - network status */ 2 3 #include "uds.h" 4 #include <sys/socketvar.h> 5 #include <sys/unpcb.h> 6 7 /* 8 * Fill the given 'ki' structure with information about the socket 'uds'. 9 */ 10 static void 11 uds_get_info(struct kinfo_pcb * ki, const struct udssock * uds) 12 { 13 struct udssock *peer; 14 socklen_t len; 15 int type; 16 17 type = uds_get_type(uds); 18 peer = uds_get_peer(uds); 19 20 ki->ki_pcbaddr = (uint64_t)(uintptr_t)uds; 21 ki->ki_ppcbaddr = (uint64_t)(uintptr_t)uds; 22 ki->ki_sockaddr = (uint64_t)(uintptr_t)&uds->uds_sock; 23 ki->ki_family = AF_UNIX; 24 ki->ki_type = type; 25 ki->ki_protocol = UDSPROTO_UDS; 26 ki->ki_pflags = 0; 27 if (uds->uds_flags & UDSF_CONNWAIT) 28 ki->ki_pflags |= UNP_CONNWAIT; 29 if (uds->uds_flags & UDSF_PASSCRED) 30 ki->ki_pflags |= UNP_WANTCRED; 31 if (type != SOCK_DGRAM && uds->uds_cred.unp_pid != -1) { 32 if (uds_is_listening(uds)) 33 ki->ki_pflags |= UNP_EIDSBIND; 34 else if (uds_is_connecting(uds) || uds_is_connected(uds)) 35 ki->ki_pflags |= UNP_EIDSVALID; 36 } 37 /* Not sure about NetBSD connection states. First attempt here. */ 38 if (uds_is_connecting(uds)) 39 ki->ki_sostate = SS_ISCONNECTING; 40 else if (uds_is_connected(uds)) 41 ki->ki_sostate = SS_ISCONNECTED; 42 else if (uds_is_disconnected(uds)) 43 ki->ki_sostate = SS_ISDISCONNECTED; 44 ki->ki_rcvq = uds->uds_len; 45 /* We currently mirror the peer's receive queue size when connected. */ 46 if (uds_is_connected(uds)) 47 ki->ki_sndq = peer->uds_len; 48 /* The source is not set for bound connection-type sockets here. */ 49 if (type == SOCK_DGRAM || uds_is_listening(uds)) 50 uds_make_addr(uds->uds_path, (size_t)uds->uds_pathlen, 51 &ki->ki_src, &len); 52 if (peer != NULL) 53 uds_make_addr(peer->uds_path, (size_t)peer->uds_pathlen, 54 &ki->ki_dst, &len); 55 /* TODO: we should set ki_inode and ki_vnode, but to what? */ 56 ki->ki_conn = (uint64_t)(uintptr_t)peer; 57 if (!TAILQ_EMPTY(&uds->uds_queue)) 58 ki->ki_refs = 59 (uint64_t)(uintptr_t)TAILQ_FIRST(&uds->uds_queue); 60 if (uds_has_link(uds)) 61 ki->ki_nextref = 62 (uint64_t)(uintptr_t)TAILQ_NEXT(uds, uds_next); 63 } 64 65 /* 66 * Remote MIB implementation of CTL_NET PF_LOCAL {SOCK_STREAM,SOCK_DGRAM, 67 * SOCK_SEQPACKET} 0. This function handles all queries on the 68 * "net.local.{stream,dgram,seqpacket}.pcblist" sysctl(7) nodes. 69 * 70 * The 0 for "pcblist" is a MINIXism: we use it to keep our arrays small. 71 * NetBSD numbers these nodes dynamically and so they have numbers above 72 * CREATE_BASE. That also means that no userland application can possibly 73 * hardcode their numbers, and must perform lookups by name. In turn, that 74 * means that we can safely change the 0 to another number if NetBSD ever 75 * introduces statically numbered nodes in these subtrees. 76 */ 77 static ssize_t 78 net_local_pcblist(struct rmib_call * call, struct rmib_node * node __unused, 79 struct rmib_oldp * oldp, struct rmib_newp * newp __unused) 80 { 81 struct udssock *uds; 82 struct kinfo_pcb ki; 83 ssize_t off; 84 int r, type, size, max; 85 86 if (call->call_namelen != 4) 87 return EINVAL; 88 89 /* The first two added name fields are not used. */ 90 91 size = call->call_name[2]; 92 if (size < 0 || (size_t)size > sizeof(ki)) 93 return EINVAL; 94 if (size == 0) 95 size = sizeof(ki); 96 max = call->call_name[3]; 97 98 type = call->call_oname[2]; 99 100 off = 0; 101 102 for (uds = uds_enum(NULL, type); uds != NULL; 103 uds = uds_enum(uds, type)) { 104 if (rmib_inrange(oldp, off)) { 105 memset(&ki, 0, sizeof(ki)); 106 107 uds_get_info(&ki, uds); 108 109 if ((r = rmib_copyout(oldp, off, &ki, size)) < 0) 110 return r; 111 } 112 113 off += size; 114 if (max > 0 && --max == 0) 115 break; 116 } 117 118 /* 119 * Margin to limit the possible effects of the inherent race condition 120 * between receiving just the data size and receiving the actual data. 121 */ 122 if (oldp == NULL) 123 off += PCB_SLOP * size; 124 125 return off; 126 } 127 128 /* The CTL_NET PF_LOCAL SOCK_STREAM subtree. */ 129 static struct rmib_node net_local_stream_table[] = { 130 [0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist, 131 "pcblist", "SOCK_STREAM protocol control block list"), 132 }; 133 134 /* The CTL_NET PF_LOCAL SOCK_DGRAM subtree. */ 135 static struct rmib_node net_local_dgram_table[] = { 136 [0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist, 137 "pcblist", "SOCK_DGRAM protocol control block list"), 138 }; 139 140 /* The CTL_NET PF_LOCAL SOCK_SEQPACKET subtree. */ 141 static struct rmib_node net_local_seqpacket_table[] = { 142 [0] = RMIB_FUNC(RMIB_RO | CTLTYPE_NODE, 0, net_local_pcblist, 143 "pcblist", "SOCK_SEQPACKET protocol control block list"), 144 }; 145 146 /* The CTL_NET PF_LOCAL subtree. */ 147 static struct rmib_node net_local_table[] = { 148 /* 1*/ [SOCK_STREAM] = RMIB_NODE(RMIB_RO, net_local_stream_table, 149 "stream", "SOCK_STREAM settings"), 150 /* 2*/ [SOCK_DGRAM] = RMIB_NODE(RMIB_RO, net_local_dgram_table, 151 "dgram", "SOCK_DGRAM settings"), 152 /* 5*/ [SOCK_SEQPACKET] = RMIB_NODE(RMIB_RO, net_local_seqpacket_table, 153 "seqpacket", "SOCK_SEQPACKET settings"), 154 }; 155 156 static struct rmib_node net_local_node = 157 RMIB_NODE(RMIB_RO, net_local_table, "local", "PF_LOCAL related settings"); 158 159 /* 160 * Initialize the status module. 161 */ 162 void 163 uds_stat_init(void) 164 { 165 const int mib[] = { CTL_NET, PF_LOCAL }; 166 int r; 167 168 /* 169 * Register our own "net.local" subtree with the MIB service. 170 * 171 * This call only returns local failures. Remote failures (in the MIB 172 * service) are silently ignored. So, we can safely panic on failure. 173 */ 174 if ((r = rmib_register(mib, __arraycount(mib), &net_local_node)) != OK) 175 panic("UDS: unable to register remote MIB tree: %d", r); 176 } 177 178 /* 179 * Clean up the status module. 180 */ 181 void 182 uds_stat_cleanup(void) 183 { 184 185 rmib_deregister(&net_local_node); 186 } 187