1 /* $NetBSD: uipc_domain.c,v 1.56 2006/04/15 04:41:52 christos 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.56 2006/04/15 04:41:52 christos 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 if (oldp != NULL) { 258 len = *oldlenp; 259 elem_size = name[2]; 260 elem_count = name[3]; 261 if (elem_size != sizeof(pcb)) 262 return EINVAL; 263 } else { 264 len = 0; 265 elem_size = sizeof(pcb); 266 elem_count = INT_MAX; 267 } 268 error = 0; 269 dp = oldp; 270 op = name[0]; 271 arg = name[1]; 272 out_size = elem_size; 273 needed = 0; 274 275 if (name - oname != 4) 276 return (EINVAL); 277 278 pf = oname[1]; 279 type = oname[2]; 280 pf2 = (oldp == NULL) ? 0 : pf; 281 282 /* 283 * there's no "list" of local domain sockets, so we have 284 * to walk the file list looking for them. :-/ 285 */ 286 LIST_FOREACH(fp, &filehead, f_list) { 287 if (CURTAIN(l->l_proc->p_ucred->cr_uid, fp->f_cred->cr_uid)) 288 continue; 289 if (fp->f_type != DTYPE_SOCKET) 290 continue; 291 so = (struct socket *)fp->f_data; 292 if (so->so_type != type) 293 continue; 294 if (so->so_proto->pr_domain->dom_family != pf) 295 continue; 296 if (len >= elem_size && elem_count > 0) { 297 sysctl_dounpcb(&pcb, so); 298 error = copyout(&pcb, dp, out_size); 299 if (error) 300 break; 301 dp += elem_size; 302 len -= elem_size; 303 } 304 if (elem_count > 0) { 305 needed += elem_size; 306 if (elem_count != INT_MAX) 307 elem_count--; 308 } 309 } 310 311 *oldlenp = needed; 312 if (oldp == NULL) 313 *oldlenp += PCB_SLOP * sizeof(struct kinfo_pcb); 314 315 return (error); 316 } 317 318 SYSCTL_SETUP(sysctl_net_setup, "sysctl net subtree setup") 319 { 320 sysctl_createv(clog, 0, NULL, NULL, 321 CTLFLAG_PERMANENT, 322 CTLTYPE_NODE, "net", NULL, 323 NULL, 0, NULL, 0, 324 CTL_NET, CTL_EOL); 325 sysctl_createv(clog, 0, NULL, NULL, 326 CTLFLAG_PERMANENT, 327 CTLTYPE_NODE, "local", 328 SYSCTL_DESCR("PF_LOCAL related settings"), 329 NULL, 0, NULL, 0, 330 CTL_NET, PF_LOCAL, CTL_EOL); 331 sysctl_createv(clog, 0, NULL, NULL, 332 CTLFLAG_PERMANENT, 333 CTLTYPE_NODE, "stream", 334 SYSCTL_DESCR("SOCK_STREAM settings"), 335 NULL, 0, NULL, 0, 336 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_EOL); 337 sysctl_createv(clog, 0, NULL, NULL, 338 CTLFLAG_PERMANENT, 339 CTLTYPE_NODE, "dgram", 340 SYSCTL_DESCR("SOCK_DGRAM settings"), 341 NULL, 0, NULL, 0, 342 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_EOL); 343 344 sysctl_createv(clog, 0, NULL, NULL, 345 CTLFLAG_PERMANENT, 346 CTLTYPE_STRUCT, "pcblist", 347 SYSCTL_DESCR("SOCK_STREAM protocol control block list"), 348 sysctl_unpcblist, 0, NULL, 0, 349 CTL_NET, PF_LOCAL, SOCK_STREAM, CTL_CREATE, CTL_EOL); 350 sysctl_createv(clog, 0, NULL, NULL, 351 CTLFLAG_PERMANENT, 352 CTLTYPE_STRUCT, "pcblist", 353 SYSCTL_DESCR("SOCK_DGRAM protocol control block list"), 354 sysctl_unpcblist, 0, NULL, 0, 355 CTL_NET, PF_LOCAL, SOCK_DGRAM, CTL_CREATE, CTL_EOL); 356 } 357 358 void 359 pfctlinput(int cmd, struct sockaddr *sa) 360 { 361 struct domain *dp; 362 const struct protosw *pr; 363 364 DOMAIN_FOREACH(dp) 365 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 366 if (pr->pr_ctlinput) 367 (*pr->pr_ctlinput)(cmd, sa, NULL); 368 } 369 370 void 371 pfctlinput2(int cmd, struct sockaddr *sa, void *ctlparam) 372 { 373 struct domain *dp; 374 const struct protosw *pr; 375 376 if (!sa) 377 return; 378 379 DOMAIN_FOREACH(dp) { 380 /* 381 * the check must be made by xx_ctlinput() anyways, to 382 * make sure we use data item pointed to by ctlparam in 383 * correct way. the following check is made just for safety. 384 */ 385 if (dp->dom_family != sa->sa_family) 386 continue; 387 388 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 389 if (pr->pr_ctlinput) 390 (*pr->pr_ctlinput)(cmd, sa, ctlparam); 391 } 392 } 393 394 void 395 pfslowtimo(void *arg) 396 { 397 struct domain *dp; 398 const struct protosw *pr; 399 400 pfslowtimo_now++; 401 402 DOMAIN_FOREACH(dp) { 403 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 404 if (pr->pr_slowtimo) 405 (*pr->pr_slowtimo)(); 406 } 407 callout_reset(&pfslowtimo_ch, hz / 2, pfslowtimo, NULL); 408 } 409 410 void 411 pffasttimo(void *arg) 412 { 413 struct domain *dp; 414 const struct protosw *pr; 415 416 pffasttimo_now++; 417 418 DOMAIN_FOREACH(dp) { 419 for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++) 420 if (pr->pr_fasttimo) 421 (*pr->pr_fasttimo)(); 422 } 423 callout_reset(&pffasttimo_ch, hz / 5, pffasttimo, NULL); 424 } 425