1 /* $NetBSD: uipc_domain.c,v 1.55 2005/12/08 03:10:12 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1982, 1986, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 * 31 * @(#)uipc_domain.c 8.3 (Berkeley) 2/14/95 32 */ 33 34 #include <sys/cdefs.h> 35 __KERNEL_RCSID(0, "$NetBSD: uipc_domain.c,v 1.55 2005/12/08 03:10:12 thorpej Exp $"); 36 37 #include <sys/param.h> 38 #include <sys/socket.h> 39 #include <sys/socketvar.h> 40 #include <sys/protosw.h> 41 #include <sys/domain.h> 42 #include <sys/mbuf.h> 43 #include <sys/time.h> 44 #include <sys/kernel.h> 45 #include <sys/systm.h> 46 #include <sys/callout.h> 47 #include <sys/queue.h> 48 #include <sys/proc.h> 49 #include <sys/sysctl.h> 50 #include <sys/un.h> 51 #include <sys/unpcb.h> 52 #include <sys/file.h> 53 54 void pffasttimo(void *); 55 void pfslowtimo(void *); 56 57 struct domainhead domains = STAILQ_HEAD_INITIALIZER(domains); 58 59 struct callout pffasttimo_ch, pfslowtimo_ch; 60 61 /* 62 * Current time values for fast and slow timeouts. We can use u_int 63 * relatively safely. The fast timer will roll over in 27 years and 64 * the slow timer in 68 years. 65 */ 66 u_int pfslowtimo_now; 67 u_int pffasttimo_now; 68 69 void 70 domaininit(void) 71 { 72 __link_set_decl(domains, struct domain); 73 struct domain * const * dpp; 74 struct domain *rt_domain = NULL; 75 76 /* 77 * Add all of the domains. Make sure the PF_ROUTE 78 * domain is added last. 79 */ 80 __link_set_foreach(dpp, domains) { 81 if ((*dpp)->dom_family == PF_ROUTE) 82 rt_domain = *dpp; 83 else 84 domain_attach(*dpp); 85 } 86 if (rt_domain) 87 domain_attach(rt_domain); 88 89 callout_init(&pffasttimo_ch); 90 callout_init(&pfslowtimo_ch); 91 92 callout_reset(&pffasttimo_ch, 1, pffasttimo, NULL); 93 callout_reset(&pfslowtimo_ch, 1, pfslowtimo, NULL); 94 } 95 96 void 97 domain_attach(struct domain *dp) 98 { 99 const struct protosw *pr; 100 101 STAILQ_INSERT_TAIL(&domains, dp, dom_link); 102 103 if (dp->dom_init) 104 (*dp->dom_init)(); 105 106 #ifdef MBUFTRACE 107 if (dp->dom_mowner.mo_name[0] == '\0') { 108 strncpy(dp->dom_mowner.mo_name, dp->dom_name, 109 sizeof(dp->dom_mowner.mo_name)); 110 MOWNER_ATTACH(&dp->dom_mowner); 111 } 112 #endif 113 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 114 if (pr->pr_init) 115 (*pr->pr_init)(); 116 } 117 118 if (max_linkhdr < 16) /* XXX */ 119 max_linkhdr = 16; 120 max_hdr = max_linkhdr + max_protohdr; 121 max_datalen = MHLEN - max_hdr; 122 } 123 124 struct domain * 125 pffinddomain(int family) 126 { 127 struct domain *dp; 128 129 DOMAIN_FOREACH(dp) 130 if (dp->dom_family == family) 131 return (dp); 132 return (NULL); 133 } 134 135 const struct protosw * 136 pffindtype(int family, int type) 137 { 138 struct domain *dp; 139 const struct protosw *pr; 140 141 dp = pffinddomain(family); 142 if (dp == NULL) 143 return (NULL); 144 145 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 146 if (pr->pr_type && pr->pr_type == type) 147 return (pr); 148 149 return (NULL); 150 } 151 152 const struct protosw * 153 pffindproto(int family, int protocol, int type) 154 { 155 struct domain *dp; 156 const struct protosw *pr; 157 const struct protosw *maybe = NULL; 158 159 if (family == 0) 160 return (NULL); 161 162 dp = pffinddomain(family); 163 if (dp == NULL) 164 return (NULL); 165 166 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) { 167 if ((pr->pr_protocol == protocol) && (pr->pr_type == type)) 168 return (pr); 169 170 if (type == SOCK_RAW && pr->pr_type == SOCK_RAW && 171 pr->pr_protocol == 0 && maybe == NULL) 172 maybe = pr; 173 } 174 return (maybe); 175 } 176 177 /* 178 * sysctl helper to stuff PF_LOCAL pcbs into sysctl structures 179 */ 180 static void 181 sysctl_dounpcb(struct kinfo_pcb *pcb, const struct socket *so) 182 { 183 struct unpcb *unp = sotounpcb(so); 184 struct sockaddr_un *un = unp->unp_addr; 185 186 memset(pcb, 0, sizeof(*pcb)); 187 188 pcb->ki_family = so->so_proto->pr_domain->dom_family; 189 pcb->ki_type = so->so_proto->pr_type; 190 pcb->ki_protocol = so->so_proto->pr_protocol; 191 pcb->ki_pflags = unp->unp_flags; 192 193 pcb->ki_pcbaddr = PTRTOUINT64(unp); 194 /* pcb->ki_ppcbaddr = unp has no ppcb... */ 195 pcb->ki_sockaddr = PTRTOUINT64(so); 196 197 pcb->ki_sostate = so->so_state; 198 /* pcb->ki_prstate = unp has no state... */ 199 200 pcb->ki_rcvq = so->so_rcv.sb_cc; 201 pcb->ki_sndq = so->so_snd.sb_cc; 202 203 un = (struct sockaddr_un *)&pcb->ki_src; 204 /* 205 * local domain sockets may bind without having a local 206 * endpoint. bleah! 207 */ 208 if (unp->unp_addr != NULL) { 209 un->sun_len = unp->unp_addr->sun_len; 210 un->sun_family = unp->unp_addr->sun_family; 211 strlcpy(un->sun_path, unp->unp_addr->sun_path, 212 sizeof(pcb->ki_s)); 213 } 214 else { 215 un->sun_len = offsetof(struct sockaddr_un, sun_path); 216 un->sun_family = pcb->ki_family; 217 } 218 if (unp->unp_conn != NULL) { 219 un = (struct sockaddr_un *)&pcb->ki_dst; 220 if (unp->unp_conn->unp_addr != NULL) { 221 un->sun_len = unp->unp_conn->unp_addr->sun_len; 222 un->sun_family = unp->unp_conn->unp_addr->sun_family; 223 un->sun_family = unp->unp_conn->unp_addr->sun_family; 224 strlcpy(un->sun_path, unp->unp_conn->unp_addr->sun_path, 225 sizeof(pcb->ki_d)); 226 } 227 else { 228 un->sun_len = offsetof(struct sockaddr_un, sun_path); 229 un->sun_family = pcb->ki_family; 230 } 231 } 232 233 pcb->ki_inode = unp->unp_ino; 234 pcb->ki_vnode = PTRTOUINT64(unp->unp_vnode); 235 pcb->ki_conn = PTRTOUINT64(unp->unp_conn); 236 pcb->ki_refs = PTRTOUINT64(unp->unp_refs); 237 pcb->ki_nextref = PTRTOUINT64(unp->unp_nextref); 238 } 239 240 static int 241 sysctl_unpcblist(SYSCTLFN_ARGS) 242 { 243 struct file *fp; 244 struct socket *so; 245 struct kinfo_pcb pcb; 246 char *dp; 247 u_int op, arg; 248 size_t len, needed, elem_size, out_size; 249 int error, elem_count, pf, type, pf2; 250 251 if (namelen == 1 && name[0] == CTL_QUERY) 252 return (sysctl_query(SYSCTLFN_CALL(rnode))); 253 254 if (namelen != 4) 255 return (EINVAL); 256 257 error = 0; 258 dp = oldp; 259 len = (oldp != NULL) ? *oldlenp : 0; 260 op = name[0]; 261 arg = name[1]; 262 elem_size = name[2]; 263 elem_count = name[3]; 264 out_size = MIN(sizeof(pcb), elem_size); 265 needed = 0; 266 267 elem_count = INT_MAX; 268 elem_size = out_size = sizeof(pcb); 269 270 if (name - oname != 4) 271 return (EINVAL); 272 273 pf = oname[1]; 274 type = oname[2]; 275 pf2 = (oldp == NULL) ? 0 : pf; 276 277 /* 278 * there's no "list" of local domain sockets, so we have 279 * to walk the file list looking for them. :-/ 280 */ 281 LIST_FOREACH(fp, &filehead, f_list) { 282 if (CURTAIN(l->l_proc->p_ucred->cr_uid, fp->f_cred->cr_uid)) 283 continue; 284 if (fp->f_type != DTYPE_SOCKET) 285 continue; 286 so = (struct socket *)fp->f_data; 287 if (so->so_type != type) 288 continue; 289 if (so->so_proto->pr_domain->dom_family != pf) 290 continue; 291 if (len >= elem_size && elem_count > 0) { 292 sysctl_dounpcb(&pcb, so); 293 error = copyout(&pcb, dp, out_size); 294 if (error) 295 break; 296 dp += elem_size; 297 len -= elem_size; 298 } 299 if (elem_count > 0) { 300 needed += elem_size; 301 if (elem_count != INT_MAX) 302 elem_count--; 303 } 304 } 305 306 *oldlenp = needed; 307 if (oldp == NULL) 308 *oldlenp += PCB_SLOP * sizeof(struct kinfo_pcb); 309 310 return (error); 311 } 312 313 SYSCTL_SETUP(sysctl_net_setup, "sysctl net subtree setup") 314 { 315 sysctl_createv(clog, 0, NULL, NULL, 316 CTLFLAG_PERMANENT, 317 CTLTYPE_NODE, "net", NULL, 318 NULL, 0, NULL, 0, 319 CTL_NET, CTL_EOL); 320 sysctl_createv(clog, 0, NULL, NULL, 321 CTLFLAG_PERMANENT, 322 CTLTYPE_NODE, "local", 323 SYSCTL_DESCR("PF_LOCAL related settings"), 324 NULL, 0, NULL, 0, 325 CTL_NET, PF_LOCAL, CTL_EOL); 326 sysctl_createv(clog, 0, NULL, NULL, 327 CTLFLAG_PERMANENT, 328 CTLTYPE_NODE, "stream", 329 SYSCTL_DESCR("SOCK_STREAM settings"), 330 NULL, 0, NULL, 0, 331 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_EOL); 332 sysctl_createv(clog, 0, NULL, NULL, 333 CTLFLAG_PERMANENT, 334 CTLTYPE_NODE, "dgram", 335 SYSCTL_DESCR("SOCK_DGRAM settings"), 336 NULL, 0, NULL, 0, 337 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_EOL); 338 339 sysctl_createv(clog, 0, NULL, NULL, 340 CTLFLAG_PERMANENT, 341 CTLTYPE_STRUCT, "pcblist", 342 SYSCTL_DESCR("SOCK_STREAM protocol control block list"), 343 sysctl_unpcblist, 0, NULL, 0, 344 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_CREATE, CTL_EOL); 345 sysctl_createv(clog, 0, NULL, NULL, 346 CTLFLAG_PERMANENT, 347 CTLTYPE_STRUCT, "pcblist", 348 SYSCTL_DESCR("SOCK_DGRAM protocol control block list"), 349 sysctl_unpcblist, 0, NULL, 0, 350 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_CREATE, CTL_EOL); 351 } 352 353 void 354 pfctlinput(int cmd, struct sockaddr *sa) 355 { 356 struct domain *dp; 357 const struct protosw *pr; 358 359 DOMAIN_FOREACH(dp) 360 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 361 if (pr->pr_ctlinput) 362 (*pr->pr_ctlinput)(cmd, sa, NULL); 363 } 364 365 void 366 pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam) 367 { 368 struct domain *dp; 369 const struct protosw *pr; 370 371 if (!sa) 372 return; 373 374 DOMAIN_FOREACH(dp) { 375 /* 376 * the check must be made by xx_ctlinput() anyways, to 377 * make sure we use data item pointed to by ctlparam in 378 * correct way. the following check is made just for safety. 379 */ 380 if (dp->dom_family != sa->sa_family) 381 continue; 382 383 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 384 if (pr->pr_ctlinput) 385 (*pr->pr_ctlinput)(cmd, sa, ctlparam); 386 } 387 } 388 389 void 390 pfslowtimo(void *arg) 391 { 392 struct domain *dp; 393 const struct protosw *pr; 394 395 pfslowtimo_now++; 396 397 DOMAIN_FOREACH(dp) { 398 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 399 if (pr->pr_slowtimo) 400 (*pr->pr_slowtimo)(); 401 } 402 callout_reset(&pfslowtimo_ch, hz / 2, pfslowtimo, NULL); 403 } 404 405 void 406 pffasttimo(void *arg) 407 { 408 struct domain *dp; 409 const struct protosw *pr; 410 411 pffasttimo_now++; 412 413 DOMAIN_FOREACH(dp) { 414 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 415 if (pr->pr_fasttimo) 416 (*pr->pr_fasttimo)(); 417 } 418 callout_reset(&pffasttimo_ch, hz / 5, pffasttimo, NULL); 419 } 420