| Commit | Line | Data |
|---|---|---|
| b06ebda0 MD |
1 | /* |
| 2 | * ng_socket.c | |
| 3 | */ | |
| 4 | ||
| 5 | /*- | |
| 6 | * Copyright (c) 1996-1999 Whistle Communications, Inc. | |
| 7 | * All rights reserved. | |
| 8 | * | |
| 9 | * Subject to the following obligations and disclaimer of warranty, use and | |
| 10 | * redistribution of this software, in source or object code forms, with or | |
| 11 | * without modifications are expressly permitted by Whistle Communications; | |
| 12 | * provided, however, that: | |
| 13 | * 1. Any and all reproductions of the source or object code must include the | |
| 14 | * copyright notice above and the following disclaimer of warranties; and | |
| 15 | * 2. No rights are granted, in any manner or form, to use Whistle | |
| 16 | * Communications, Inc. trademarks, including the mark "WHISTLE | |
| 17 | * COMMUNICATIONS" on advertising, endorsements, or otherwise except as | |
| 18 | * such appears in the above copyright notice or in the software. | |
| 19 | * | |
| 20 | * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND | |
| 21 | * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO | |
| 22 | * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, | |
| 23 | * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF | |
| 24 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. | |
| 25 | * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY | |
| 26 | * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS | |
| 27 | * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. | |
| 28 | * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES | |
| 29 | * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING | |
| 30 | * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, | |
| 31 | * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR | |
| 32 | * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY | |
| 33 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT | |
| 34 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | |
| 35 | * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY | |
| 36 | * OF SUCH DAMAGE. | |
| 37 | * | |
| 38 | * Author: Julian Elischer <julian@freebsd.org> | |
| 39 | * | |
| 40 | * $FreeBSD: src/sys/netgraph/ng_socket.c,v 1.85 2008/03/11 21:58:48 mav Exp $ | |
| 41 | * $Whistle: ng_socket.c,v 1.28 1999/11/01 09:24:52 julian Exp $ | |
| 42 | */ | |
| 43 | ||
| 44 | /* | |
| 45 | * Netgraph socket nodes | |
| 46 | * | |
| 47 | * There are two types of netgraph sockets, control and data. | |
| 48 | * Control sockets have a netgraph node, but data sockets are | |
| 49 | * parasitic on control sockets, and have no node of their own. | |
| 50 | */ | |
| 51 | ||
| b06ebda0 MD |
52 | #include <sys/domain.h> |
| 53 | #include <sys/kernel.h> | |
| 54 | #include <sys/linker.h> | |
| 55 | #include <sys/lock.h> | |
| 56 | #include <sys/malloc.h> | |
| 57 | #include <sys/mbuf.h> | |
| e858b308 | 58 | #include <sys/msgport2.h> |
| 0147868e | 59 | /* |
| b06ebda0 | 60 | #include <sys/mutex.h> |
| 0147868e | 61 | */ |
| e858b308 | 62 | #include <sys/param.h> |
| b06ebda0 | 63 | #include <sys/priv.h> |
| 0147868e | 64 | #include <sys/proc.h> |
| b06ebda0 MD |
65 | #include <sys/protosw.h> |
| 66 | #include <sys/queue.h> | |
| 67 | #include <sys/socket.h> | |
| 68 | #include <sys/socketvar.h> | |
| a48a177f | 69 | #include <sys/socketvar2.h> |
| 0147868e | 70 | /* |
| b06ebda0 | 71 | #include <sys/syscallsubr.h> |
| 0147868e | 72 | */ |
| b06ebda0 | 73 | #include <sys/sysctl.h> |
| e858b308 | 74 | #include <sys/thread2.h> |
| b06ebda0 | 75 | #include <sys/vnode.h> |
| ac58e50c | 76 | |
| 0147868e NA |
77 | #include <netgraph7/ng_message.h> |
| 78 | #include <netgraph7/netgraph.h> | |
| 5a975a3d MD |
79 | #include "ng_socketvar.h" |
| 80 | #include "ng_socket.h" | |
| b06ebda0 MD |
81 | |
| 82 | #ifdef NG_SEPARATE_MALLOC | |
| 83 | MALLOC_DEFINE(M_NETGRAPH_PATH, "netgraph_path", "netgraph path info "); | |
| 84 | MALLOC_DEFINE(M_NETGRAPH_SOCK, "netgraph_sock", "netgraph socket info "); | |
| 85 | #else | |
| 86 | #define M_NETGRAPH_PATH M_NETGRAPH | |
| 87 | #define M_NETGRAPH_SOCK M_NETGRAPH | |
| 88 | #endif | |
| 89 | ||
| 90 | /* | |
| 91 | * It's Ascii-art time! | |
| 92 | * +-------------+ +-------------+ | |
| 93 | * |socket (ctl)| |socket (data)| | |
| 94 | * +-------------+ +-------------+ | |
| 95 | * ^ ^ | |
| 96 | * | | | |
| 97 | * v v | |
| 98 | * +-----------+ +-----------+ | |
| 99 | * |pcb (ctl)| |pcb (data)| | |
| 100 | * +-----------+ +-----------+ | |
| 101 | * ^ ^ | |
| 102 | * | | | |
| 103 | * v v | |
| 104 | * +--------------------------+ | |
| 105 | * | Socket type private | | |
| 106 | * | data | | |
| 107 | * +--------------------------+ | |
| 108 | * ^ | |
| 109 | * | | |
| 110 | * v | |
| 111 | * +----------------+ | |
| 112 | * | struct ng_node | | |
| 113 | * +----------------+ | |
| 114 | */ | |
| 115 | ||
| 116 | /* Netgraph node methods */ | |
| 117 | static ng_constructor_t ngs_constructor; | |
| 118 | static ng_rcvmsg_t ngs_rcvmsg; | |
| 119 | static ng_shutdown_t ngs_shutdown; | |
| 120 | static ng_newhook_t ngs_newhook; | |
| 121 | static ng_connect_t ngs_connect; | |
| 122 | static ng_rcvdata_t ngs_rcvdata; | |
| 123 | static ng_disconnect_t ngs_disconnect; | |
| 124 | ||
| 125 | /* Internal methods */ | |
| 126 | static int ng_attach_data(struct socket *so); | |
| 127 | static int ng_attach_cntl(struct socket *so); | |
| 128 | static int ng_attach_common(struct socket *so, int type); | |
| 129 | static void ng_detach_common(struct ngpcb *pcbp, int type); | |
| 130 | static void ng_socket_free_priv(struct ngsock *priv); | |
| 131 | #ifdef NOTYET | |
| 132 | static int ng_internalize(struct mbuf *m, struct thread *p); | |
| 133 | #endif | |
| 134 | static int ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp); | |
| 135 | static int ng_bind(struct sockaddr *nam, struct ngpcb *pcbp); | |
| 136 | ||
| 137 | static int ngs_mod_event(module_t mod, int event, void *data); | |
| 138 | static void ng_socket_item_applied(void *context, int error); | |
| ac58e50c | 139 | static int linker_api_available(void); |
| b06ebda0 MD |
140 | |
| 141 | /* Netgraph type descriptor */ | |
| 142 | static struct ng_type typestruct = { | |
| 143 | .version = NG_ABI_VERSION, | |
| 144 | .name = NG_SOCKET_NODE_TYPE, | |
| 145 | .mod_event = ngs_mod_event, | |
| 146 | .constructor = ngs_constructor, | |
| 147 | .rcvmsg = ngs_rcvmsg, | |
| 148 | .shutdown = ngs_shutdown, | |
| 149 | .newhook = ngs_newhook, | |
| 150 | .connect = ngs_connect, | |
| 151 | .rcvdata = ngs_rcvdata, | |
| 152 | .disconnect = ngs_disconnect, | |
| 153 | }; | |
| 154 | NETGRAPH_INIT_ORDERED(socket, &typestruct, SI_SUB_PROTO_DOMAIN, SI_ORDER_ANY); | |
| 155 | ||
| 156 | /* Buffer space */ | |
| 157 | static u_long ngpdg_sendspace = 20 * 1024; /* really max datagram size */ | |
| 158 | SYSCTL_INT(_net_graph, OID_AUTO, maxdgram, CTLFLAG_RW, | |
| 159 | &ngpdg_sendspace , 0, "Maximum outgoing Netgraph datagram size"); | |
| 160 | static u_long ngpdg_recvspace = 20 * 1024; | |
| 161 | SYSCTL_INT(_net_graph, OID_AUTO, recvspace, CTLFLAG_RW, | |
| 162 | &ngpdg_recvspace , 0, "Maximum space for incoming Netgraph datagrams"); | |
| 163 | ||
| 164 | #define sotongpcb(so) ((struct ngpcb *)(so)->so_pcb) | |
| 165 | ||
| 166 | /* If getting unexplained errors returned, set this to "kdb_enter("X"); */ | |
| 167 | #ifndef TRAP_ERROR | |
| 168 | #define TRAP_ERROR | |
| 169 | #endif | |
| 170 | ||
| 171 | /*************************************************************** | |
| 172 | Control sockets | |
| 173 | ***************************************************************/ | |
| 174 | ||
| e858b308 NA |
175 | static void |
| 176 | ngc_attach(netmsg_t msg) | |
| b06ebda0 | 177 | { |
| e858b308 NA |
178 | struct socket *so = msg->attach.base.nm_so; |
| 179 | struct pru_attach_info *ai = msg->attach.nm_ai; | |
| b06ebda0 | 180 | struct ngpcb *const pcbp = sotongpcb(so); |
| e858b308 | 181 | int error; |
| b06ebda0 | 182 | |
| 0147868e | 183 | if (priv_check_cred(ai->p_ucred, PRIV_ROOT, NULL_CRED_OKAY) != 0) |
| e858b308 NA |
184 | error = EPERM; |
| 185 | else if (pcbp != NULL) | |
| 186 | error = EISCONN; | |
| 187 | else | |
| 188 | error = ng_attach_cntl(so); | |
| 189 | lwkt_replymsg(&msg->attach.base.lmsg, error); | |
| b06ebda0 MD |
190 | } |
| 191 | ||
| e858b308 NA |
192 | static void |
| 193 | ngc_detach(netmsg_t msg) | |
| b06ebda0 | 194 | { |
| e858b308 | 195 | struct socket *so = msg->detach.base.nm_so; |
| b06ebda0 MD |
196 | struct ngpcb *const pcbp = sotongpcb(so); |
| 197 | ||
| 198 | KASSERT(pcbp != NULL, ("ngc_detach: pcbp == NULL")); | |
| 199 | ng_detach_common(pcbp, NG_CONTROL); | |
| e858b308 | 200 | lwkt_replymsg(&msg->detach.base.lmsg, 0); |
| b06ebda0 MD |
201 | } |
| 202 | ||
| e858b308 NA |
203 | static void |
| 204 | ngc_send(netmsg_t netmsg) | |
| b06ebda0 | 205 | { |
| e858b308 NA |
206 | struct socket *so = netmsg->send.base.nm_so; |
| 207 | struct mbuf *m = netmsg->send.nm_m; | |
| 208 | struct sockaddr *addr = netmsg->send.nm_addr; | |
| 209 | struct mbuf *control = netmsg->send.nm_control; | |
| b06ebda0 MD |
210 | struct ngpcb *const pcbp = sotongpcb(so); |
| 211 | struct ngsock *const priv = NG_NODE_PRIVATE(pcbp->sockdata->node); | |
| 212 | struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; | |
| 213 | struct ng_mesg *msg; | |
| 214 | struct mbuf *m0; | |
| 215 | item_p item; | |
| 216 | char *path = NULL; | |
| 217 | int len, error = 0; | |
| 218 | struct ng_apply_info apply; | |
| 219 | ||
| 220 | #ifdef NOTYET | |
| 221 | if (control && (error = ng_internalize(control, td))) { | |
| 222 | if (pcbp->sockdata == NULL) { | |
| 223 | error = ENOTCONN; | |
| 224 | goto release; | |
| 225 | } | |
| 226 | } | |
| 227 | #else /* NOTYET */ | |
| 228 | if (control) { | |
| 229 | error = EINVAL; | |
| 230 | goto release; | |
| 231 | } | |
| 232 | #endif /* NOTYET */ | |
| 233 | ||
| 234 | /* Require destination as there may be >= 1 hooks on this node. */ | |
| 235 | if (addr == NULL) { | |
| 236 | error = EDESTADDRREQ; | |
| 237 | goto release; | |
| 238 | } | |
| 239 | ||
| 240 | /* | |
| 241 | * Allocate an expendable buffer for the path, chop off | |
| 242 | * the sockaddr header, and make sure it's NUL terminated. | |
| 243 | */ | |
| 244 | len = sap->sg_len - 2; | |
| 5a975a3d | 245 | path = kmalloc(len + 1, M_NETGRAPH_PATH, M_WAITOK); |
| b06ebda0 MD |
246 | bcopy(sap->sg_data, path, len); |
| 247 | path[len] = '\0'; | |
| 248 | ||
| 249 | /* | |
| 250 | * Move the actual message out of mbufs into a linear buffer. | |
| 251 | * Start by adding up the size of the data. (could use mh_len?) | |
| 252 | */ | |
| 253 | for (len = 0, m0 = m; m0 != NULL; m0 = m0->m_next) | |
| 254 | len += m0->m_len; | |
| 255 | ||
| 256 | /* | |
| 257 | * Move the data into a linear buffer as well. | |
| 258 | * Messages are not delivered in mbufs. | |
| 259 | */ | |
| 5a975a3d | 260 | msg = kmalloc(len + 1, M_NETGRAPH_MSG, M_WAITOK); |
| b06ebda0 MD |
261 | m_copydata(m, 0, len, (char *)msg); |
| 262 | ||
| 263 | if (msg->header.version != NG_VERSION) { | |
| 5a975a3d | 264 | kfree(msg, M_NETGRAPH_MSG); |
| b06ebda0 MD |
265 | error = EINVAL; |
| 266 | goto release; | |
| 267 | } | |
| 268 | ||
| 269 | /* | |
| 270 | * Hack alert! | |
| 271 | * We look into the message and if it mkpeers a node of unknown type, we | |
| 272 | * try to load it. We need to do this now, in syscall thread, because if | |
| 273 | * message gets queued and applied later we will get panic. | |
| 274 | */ | |
| 275 | if (msg->header.typecookie == NGM_GENERIC_COOKIE && | |
| 276 | msg->header.cmd == NGM_MKPEER) { | |
| 277 | struct ngm_mkpeer *const mkp = (struct ngm_mkpeer *) msg->data; | |
| 278 | struct ng_type *type; | |
| 279 | ||
| 280 | if ((type = ng_findtype(mkp->type)) == NULL) { | |
| 281 | char filename[NG_TYPESIZ + 3]; | |
| 0147868e NA |
282 | linker_file_t fileid; |
| 283 | ||
| e858b308 NA |
284 | if (!linker_api_available()) { |
| 285 | error = ENXIO; | |
| 286 | goto done; | |
| 287 | } | |
| b06ebda0 MD |
288 | |
| 289 | /* Not found, try to load it as a loadable module. */ | |
| 0147868e | 290 | snprintf(filename, sizeof(filename), "ng_%s.ko", |
| b06ebda0 | 291 | mkp->type); |
| 0147868e | 292 | error = linker_load_file(filename, &fileid); |
| b06ebda0 | 293 | if (error != 0) { |
| 5a975a3d | 294 | kfree(msg, M_NETGRAPH_MSG); |
| b06ebda0 MD |
295 | goto release; |
| 296 | } | |
| 297 | ||
| 298 | /* See if type has been loaded successfully. */ | |
| 299 | if ((type = ng_findtype(mkp->type)) == NULL) { | |
| 5a975a3d | 300 | kfree(msg, M_NETGRAPH_MSG); |
| 0147868e | 301 | (void)linker_file_unload(fileid); |
| b06ebda0 MD |
302 | error = ENXIO; |
| 303 | goto release; | |
| 304 | } | |
| 305 | } | |
| 306 | } | |
| 307 | ||
| 5a975a3d | 308 | item = ng_package_msg(msg, NG_WAITOK); |
| b06ebda0 MD |
309 | if ((error = ng_address_path((pcbp->sockdata->node), item, path, 0)) |
| 310 | != 0) { | |
| 311 | #ifdef TRACE_MESSAGES | |
| 312 | printf("ng_address_path: errx=%d\n", error); | |
| 313 | #endif | |
| 314 | goto release; | |
| 315 | } | |
| 316 | ||
| 317 | #ifdef TRACE_MESSAGES | |
| 318 | printf("[%x]:<---------[socket]: c=<%d>cmd=%x(%s) f=%x #%d (%s)\n", | |
| 319 | item->el_dest->nd_ID, | |
| 320 | msg->header.typecookie, | |
| 321 | msg->header.cmd, | |
| 322 | msg->header.cmdstr, | |
| 323 | msg->header.flags, | |
| 324 | msg->header.token, | |
| 325 | item->el_dest->nd_type->name); | |
| 326 | #endif | |
| 327 | SAVE_LINE(item); | |
| 328 | /* | |
| 329 | * We do not want to return from syscall until the item | |
| 330 | * is processed by destination node. We register callback | |
| 331 | * on the item, which will update priv->error when item | |
| 332 | * was applied. | |
| 333 | * If ng_snd_item() has queued item, we sleep until | |
| 334 | * callback wakes us up. | |
| 335 | */ | |
| 336 | bzero(&apply, sizeof(apply)); | |
| 337 | apply.apply = ng_socket_item_applied; | |
| 338 | apply.context = priv; | |
| 339 | item->apply = &apply; | |
| 340 | priv->error = -1; | |
| 341 | ||
| 342 | error = ng_snd_item(item, 0); | |
| 343 | ||
| 344 | mtx_lock(&priv->mtx); | |
| 345 | if (priv->error == -1) | |
| 0147868e NA |
346 | lock_sleep(priv, 0, "ngsock", 0, |
| 347 | (struct lock *)&priv->mtx); | |
| b06ebda0 MD |
348 | mtx_unlock(&priv->mtx); |
| 349 | KASSERT(priv->error != -1, | |
| 350 | ("ng_socket: priv->error wasn't updated")); | |
| 351 | error = priv->error; | |
| 352 | ||
| 353 | release: | |
| 354 | if (path != NULL) | |
| 5a975a3d | 355 | kfree(path, M_NETGRAPH_PATH); |
| b06ebda0 MD |
356 | if (control != NULL) |
| 357 | m_freem(control); | |
| 358 | if (m != NULL) | |
| 359 | m_freem(m); | |
| e858b308 NA |
360 | done: |
| 361 | lwkt_replymsg(&netmsg->send.base.lmsg, error); | |
| b06ebda0 MD |
362 | } |
| 363 | ||
| e858b308 NA |
364 | static void |
| 365 | ngc_bind(netmsg_t msg) | |
| b06ebda0 | 366 | { |
| e858b308 NA |
367 | struct socket *so = msg->connect.base.nm_so; |
| 368 | struct sockaddr *nam = msg->connect.nm_nam; | |
| b06ebda0 | 369 | struct ngpcb *const pcbp = sotongpcb(so); |
| e858b308 | 370 | int error; |
| b06ebda0 | 371 | |
| 4090d6ff | 372 | if (pcbp == NULL) |
| e858b308 NA |
373 | error = EINVAL; |
| 374 | else | |
| 375 | error = ng_bind(nam, pcbp); | |
| 376 | lwkt_replymsg(&msg->connect.base.lmsg, error); | |
| b06ebda0 MD |
377 | } |
| 378 | ||
| e858b308 NA |
379 | static void |
| 380 | ngc_connect(netmsg_t msg) | |
| b06ebda0 MD |
381 | { |
| 382 | /* | |
| 383 | * At this time refuse to do this.. it used to | |
| 384 | * do something but it was undocumented and not used. | |
| 385 | */ | |
| 386 | printf("program tried to connect control socket to remote node\n"); | |
| e858b308 | 387 | lwkt_replymsg(&msg->connect.base.lmsg, EINVAL); |
| b06ebda0 MD |
388 | } |
| 389 | ||
| 390 | /*************************************************************** | |
| 391 | Data sockets | |
| 392 | ***************************************************************/ | |
| 393 | ||
| e858b308 NA |
394 | static void |
| 395 | ngd_attach(netmsg_t msg) | |
| b06ebda0 | 396 | { |
| e858b308 | 397 | struct socket *so = msg->attach.base.nm_so; |
| b06ebda0 | 398 | struct ngpcb *const pcbp = sotongpcb(so); |
| e858b308 | 399 | int error; |
| b06ebda0 MD |
400 | |
| 401 | if (pcbp != NULL) | |
| e858b308 NA |
402 | error = EISCONN; |
| 403 | else | |
| 404 | error = ng_attach_data(so); | |
| 405 | lwkt_replymsg(&msg->connect.base.lmsg, error); | |
| b06ebda0 MD |
406 | } |
| 407 | ||
| e858b308 NA |
408 | static void |
| 409 | ngd_detach(netmsg_t msg) | |
| b06ebda0 | 410 | { |
| e858b308 | 411 | struct socket *so = msg->detach.base.nm_so; |
| b06ebda0 MD |
412 | struct ngpcb *const pcbp = sotongpcb(so); |
| 413 | ||
| 414 | KASSERT(pcbp != NULL, ("ngd_detach: pcbp == NULL")); | |
| 415 | ng_detach_common(pcbp, NG_DATA); | |
| e858b308 | 416 | lwkt_replymsg(&msg->detach.base.lmsg, 0); |
| b06ebda0 MD |
417 | } |
| 418 | ||
| e858b308 NA |
419 | static void |
| 420 | ngd_send(netmsg_t msg) | |
| b06ebda0 | 421 | { |
| e858b308 NA |
422 | struct socket *so = msg->send.base.nm_so; |
| 423 | struct mbuf *m = msg->send.nm_m; | |
| 424 | struct sockaddr *addr = msg->send.nm_addr; | |
| 425 | struct mbuf *control = msg->send.nm_control; | |
| b06ebda0 MD |
426 | struct ngpcb *const pcbp = sotongpcb(so); |
| 427 | struct sockaddr_ng *const sap = (struct sockaddr_ng *) addr; | |
| 428 | int len, error; | |
| 429 | hook_p hook = NULL; | |
| 430 | char hookname[NG_HOOKSIZ]; | |
| 431 | ||
| 432 | if ((pcbp == NULL) || (control != NULL)) { | |
| 433 | error = EINVAL; | |
| 434 | goto release; | |
| 435 | } | |
| 436 | if (pcbp->sockdata == NULL) { | |
| 437 | error = ENOTCONN; | |
| 438 | goto release; | |
| 439 | } | |
| 440 | ||
| 441 | if (sap == NULL) | |
| 442 | len = 0; /* Make compiler happy. */ | |
| 443 | else | |
| 444 | len = sap->sg_len - 2; | |
| 445 | ||
| 446 | /* | |
| 447 | * If the user used any of these ways to not specify an address | |
| 448 | * then handle specially. | |
| 449 | */ | |
| 450 | if ((sap == NULL) || (len <= 0) || (*sap->sg_data == '\0')) { | |
| 451 | if (NG_NODE_NUMHOOKS(pcbp->sockdata->node) != 1) { | |
| 452 | error = EDESTADDRREQ; | |
| 453 | goto release; | |
| 454 | } | |
| 455 | /* | |
| 456 | * If exactly one hook exists, just use it. | |
| 457 | * Special case to allow write(2) to work on an ng_socket. | |
| 458 | */ | |
| 459 | hook = LIST_FIRST(&pcbp->sockdata->node->nd_hooks); | |
| 460 | } else { | |
| 461 | if (len >= NG_HOOKSIZ) { | |
| 462 | error = EINVAL; | |
| 463 | goto release; | |
| 464 | } | |
| 465 | ||
| 466 | /* | |
| 467 | * chop off the sockaddr header, and make sure it's NUL | |
| 468 | * terminated | |
| 469 | */ | |
| 470 | bcopy(sap->sg_data, hookname, len); | |
| 471 | hookname[len] = '\0'; | |
| 472 | ||
| 473 | /* Find the correct hook from 'hookname' */ | |
| 474 | hook = ng_findhook(pcbp->sockdata->node, hookname); | |
| 475 | if (hook == NULL) { | |
| 476 | error = EHOSTUNREACH; | |
| 477 | goto release; | |
| 478 | } | |
| 479 | } | |
| 480 | ||
| 481 | /* Send data. */ | |
| 482 | NG_SEND_DATA_FLAGS(error, hook, m, NG_WAITOK); | |
| 483 | ||
| 484 | release: | |
| 485 | if (control != NULL) | |
| 486 | m_freem(control); | |
| 487 | if (m != NULL) | |
| 488 | m_freem(m); | |
| e858b308 | 489 | lwkt_replymsg(&msg->send.base.lmsg, error); |
| b06ebda0 MD |
490 | } |
| 491 | ||
| e858b308 NA |
492 | static void |
| 493 | ngd_connect(netmsg_t msg) | |
| b06ebda0 | 494 | { |
| e858b308 NA |
495 | struct socket *so = msg->connect.base.nm_so; |
| 496 | struct sockaddr *nam = msg->connect.nm_nam; | |
| b06ebda0 | 497 | struct ngpcb *const pcbp = sotongpcb(so); |
| e858b308 | 498 | int error; |
| b06ebda0 | 499 | |
| 4090d6ff | 500 | if (pcbp == NULL) |
| e858b308 NA |
501 | error = EINVAL; |
| 502 | else | |
| 503 | error = ng_connect_data(nam, pcbp); | |
| 504 | lwkt_replymsg(&msg->connect.base.lmsg, error); | |
| b06ebda0 MD |
505 | } |
| 506 | ||
| 507 | /* | |
| 508 | * Used for both data and control sockets | |
| 509 | */ | |
| e858b308 NA |
510 | static void |
| 511 | ng_getsockaddr(netmsg_t msg) | |
| b06ebda0 | 512 | { |
| e858b308 NA |
513 | struct socket *so = msg->sockaddr.base.nm_so; |
| 514 | struct sockaddr **addr = msg->sockaddr.nm_nam; | |
| b06ebda0 MD |
515 | struct ngpcb *pcbp; |
| 516 | struct sockaddr_ng *sg; | |
| 517 | int sg_len; | |
| 518 | int error = 0; | |
| 519 | ||
| 520 | /* Why isn't sg_data a `char[1]' ? :-( */ | |
| 521 | sg_len = sizeof(struct sockaddr_ng) - sizeof(sg->sg_data) + 1; | |
| 522 | ||
| 523 | pcbp = sotongpcb(so); | |
| e858b308 | 524 | if ((pcbp == NULL) || (pcbp->sockdata == NULL)) { |
| b06ebda0 | 525 | /* XXXGL: can this still happen? */ |
| e858b308 NA |
526 | error = EINVAL; |
| 527 | goto replymsg; | |
| 528 | } | |
| b06ebda0 MD |
529 | |
| 530 | mtx_lock(&pcbp->sockdata->mtx); | |
| 531 | if (pcbp->sockdata->node != NULL) { | |
| 532 | node_p node = pcbp->sockdata->node; | |
| 533 | int namelen = 0; /* silence compiler! */ | |
| 534 | ||
| 535 | if (NG_NODE_HAS_NAME(node)) | |
| 536 | sg_len += namelen = strlen(NG_NODE_NAME(node)); | |
| 537 | ||
| 5a975a3d | 538 | sg = kmalloc(sg_len, M_SONAME, M_WAITOK | M_ZERO); |
| b06ebda0 MD |
539 | |
| 540 | if (NG_NODE_HAS_NAME(node)) | |
| 541 | bcopy(NG_NODE_NAME(node), sg->sg_data, namelen); | |
| 542 | ||
| 543 | sg->sg_len = sg_len; | |
| 544 | sg->sg_family = AF_NETGRAPH; | |
| 545 | *addr = (struct sockaddr *)sg; | |
| 546 | mtx_unlock(&pcbp->sockdata->mtx); | |
| 547 | } else { | |
| 548 | mtx_unlock(&pcbp->sockdata->mtx); | |
| 549 | error = EINVAL; | |
| 550 | } | |
| 551 | ||
| e858b308 NA |
552 | replymsg: |
| 553 | lwkt_replymsg(&msg->sockaddr.base.lmsg, error); | |
| b06ebda0 MD |
554 | } |
| 555 | ||
| 556 | /* | |
| 557 | * Attach a socket to it's protocol specific partner. | |
| 558 | * For a control socket, actually create a netgraph node and attach | |
| 559 | * to it as well. | |
| 560 | */ | |
| 561 | ||
| 562 | static int | |
| 563 | ng_attach_cntl(struct socket *so) | |
| 564 | { | |
| 565 | struct ngsock *priv; | |
| 566 | struct ngpcb *pcbp; | |
| 567 | int error; | |
| 568 | ||
| 569 | /* Allocate node private info */ | |
| 5a975a3d | 570 | priv = kmalloc(sizeof(*priv), M_NETGRAPH_SOCK, M_WAITOK | M_ZERO); |
| b06ebda0 MD |
571 | |
| 572 | /* Setup protocol control block */ | |
| 573 | if ((error = ng_attach_common(so, NG_CONTROL)) != 0) { | |
| 5a975a3d | 574 | kfree(priv, M_NETGRAPH_SOCK); |
| b06ebda0 MD |
575 | return (error); |
| 576 | } | |
| 577 | pcbp = sotongpcb(so); | |
| 578 | ||
| 579 | /* Link the pcb the private data. */ | |
| 580 | priv->ctlsock = pcbp; | |
| 581 | pcbp->sockdata = priv; | |
| 582 | priv->refs++; | |
| 583 | ||
| 584 | /* Initialize mutex. */ | |
| 585 | mtx_init(&priv->mtx, "ng_socket", NULL, MTX_DEF); | |
| 586 | ||
| 587 | /* Make the generic node components */ | |
| 588 | if ((error = ng_make_node_common(&typestruct, &priv->node)) != 0) { | |
| 5a975a3d | 589 | kfree(priv, M_NETGRAPH_SOCK); |
| b06ebda0 MD |
590 | ng_detach_common(pcbp, NG_CONTROL); |
| 591 | return (error); | |
| 592 | } | |
| 593 | ||
| 594 | /* Link the node and the private data. */ | |
| 595 | NG_NODE_SET_PRIVATE(priv->node, priv); | |
| 596 | NG_NODE_REF(priv->node); | |
| 597 | priv->refs++; | |
| 598 | ||
| 599 | return (0); | |
| 600 | } | |
| 601 | ||
| 602 | static int | |
| 603 | ng_attach_data(struct socket *so) | |
| 604 | { | |
| 605 | return (ng_attach_common(so, NG_DATA)); | |
| 606 | } | |
| 607 | ||
| 608 | /* | |
| 609 | * Set up a socket protocol control block. | |
| 610 | * This code is shared between control and data sockets. | |
| 611 | */ | |
| 612 | static int | |
| 613 | ng_attach_common(struct socket *so, int type) | |
| 614 | { | |
| 615 | struct ngpcb *pcbp; | |
| 616 | int error; | |
| 617 | ||
| 618 | /* Standard socket setup stuff. */ | |
| 0147868e | 619 | error = soreserve(so, ngpdg_sendspace, ngpdg_recvspace, NULL); |
| b06ebda0 MD |
620 | if (error) |
| 621 | return (error); | |
| 622 | ||
| 623 | /* Allocate the pcb. */ | |
| 5a975a3d | 624 | pcbp = kmalloc(sizeof(struct ngpcb), M_PCB, M_WAITOK | M_ZERO); |
| b06ebda0 MD |
625 | pcbp->type = type; |
| 626 | ||
| 627 | /* Link the pcb and the socket. */ | |
| 628 | so->so_pcb = (caddr_t)pcbp; | |
| 629 | pcbp->ng_socket = so; | |
| 630 | ||
| 631 | return (0); | |
| 632 | } | |
| 633 | ||
| 634 | /* | |
| 635 | * Disassociate the socket from it's protocol specific | |
| 636 | * partner. If it's attached to a node's private data structure, | |
| 637 | * then unlink from that too. If we were the last socket attached to it, | |
| 638 | * then shut down the entire node. Shared code for control and data sockets. | |
| 639 | */ | |
| 640 | static void | |
| 641 | ng_detach_common(struct ngpcb *pcbp, int which) | |
| 642 | { | |
| 643 | struct ngsock *priv = pcbp->sockdata; | |
| 644 | ||
| 645 | if (priv != NULL) { | |
| 646 | mtx_lock(&priv->mtx); | |
| 647 | ||
| 648 | switch (which) { | |
| 649 | case NG_CONTROL: | |
| 650 | priv->ctlsock = NULL; | |
| 651 | break; | |
| 652 | case NG_DATA: | |
| 653 | priv->datasock = NULL; | |
| 654 | break; | |
| 655 | default: | |
| 656 | panic(__func__); | |
| 657 | } | |
| 658 | pcbp->sockdata = NULL; | |
| 659 | ||
| 660 | ng_socket_free_priv(priv); | |
| 661 | } | |
| 662 | ||
| 663 | pcbp->ng_socket->so_pcb = NULL; | |
| 5a975a3d | 664 | kfree(pcbp, M_PCB); |
| b06ebda0 MD |
665 | } |
| 666 | ||
| 667 | /* | |
| 668 | * Remove a reference from node private data. | |
| 669 | */ | |
| 670 | static void | |
| 671 | ng_socket_free_priv(struct ngsock *priv) | |
| 672 | { | |
| 673 | mtx_assert(&priv->mtx, MA_OWNED); | |
| 674 | ||
| 675 | priv->refs--; | |
| 676 | ||
| 677 | if (priv->refs == 0) { | |
| 678 | mtx_destroy(&priv->mtx); | |
| 5a975a3d | 679 | kfree(priv, M_NETGRAPH_SOCK); |
| b06ebda0 MD |
680 | return; |
| 681 | } | |
| 682 | ||
| 683 | if ((priv->refs == 1) && (priv->node != NULL)) { | |
| 684 | node_p node = priv->node; | |
| 685 | ||
| 686 | priv->node = NULL; | |
| 687 | mtx_unlock(&priv->mtx); | |
| 688 | NG_NODE_UNREF(node); | |
| 689 | ng_rmnode_self(node); | |
| 690 | } else | |
| 691 | mtx_unlock(&priv->mtx); | |
| 692 | } | |
| 693 | ||
| 694 | #ifdef NOTYET | |
| 695 | /* | |
| 696 | * File descriptors can be passed into an AF_NETGRAPH socket. | |
| 697 | * Note, that file descriptors cannot be passed OUT. | |
| 698 | * Only character device descriptors are accepted. | |
| 699 | * Character devices are useful to connect a graph to a device, | |
| 700 | * which after all is the purpose of this whole system. | |
| 701 | */ | |
| 702 | static int | |
| 703 | ng_internalize(struct mbuf *control, struct thread *td) | |
| 704 | { | |
| 705 | const struct cmsghdr *cm = mtod(control, const struct cmsghdr *); | |
| 706 | struct file *fp; | |
| 707 | struct vnode *vn; | |
| 708 | int oldfds; | |
| 709 | int fd; | |
| 710 | ||
| 711 | if (cm->cmsg_type != SCM_RIGHTS || cm->cmsg_level != SOL_SOCKET || | |
| 712 | cm->cmsg_len != control->m_len) { | |
| 713 | TRAP_ERROR; | |
| 714 | return (EINVAL); | |
| 715 | } | |
| 716 | ||
| 717 | /* Check there is only one FD. XXX what would more than one signify? */ | |
| 718 | oldfds = ((caddr_t)cm + cm->cmsg_len - (caddr_t)data) / sizeof (int); | |
| 719 | if (oldfds != 1) { | |
| 720 | TRAP_ERROR; | |
| 721 | return (EINVAL); | |
| 722 | } | |
| 723 | ||
| 724 | /* Check that the FD given is legit. and change it to a pointer to a | |
| 725 | * struct file. */ | |
| 726 | fd = CMSG_DATA(cm); | |
| 727 | if ((error = fget(td, fd, &fp)) != 0) | |
| 728 | return (error); | |
| 729 | ||
| 730 | /* Depending on what kind of resource it is, act differently. For | |
| 731 | * devices, we treat it as a file. For an AF_NETGRAPH socket, | |
| 732 | * shortcut straight to the node. */ | |
| 733 | switch (fp->f_type) { | |
| 734 | case DTYPE_VNODE: | |
| 735 | vn = fp->f_data; | |
| 736 | if (vn && (vn->v_type == VCHR)) { | |
| 737 | /* for a VCHR, actually reference the FILE */ | |
| 738 | fhold(fp); | |
| 739 | /* XXX then what :) */ | |
| 740 | /* how to pass on to other modules? */ | |
| 741 | } else { | |
| 742 | fdrop(fp, td); | |
| 743 | TRAP_ERROR; | |
| 744 | return (EINVAL); | |
| 745 | } | |
| 746 | break; | |
| 747 | default: | |
| 748 | fdrop(fp, td); | |
| 749 | TRAP_ERROR; | |
| 750 | return (EINVAL); | |
| 751 | } | |
| 752 | fdrop(fp, td); | |
| 753 | return (0); | |
| 754 | } | |
| 755 | #endif /* NOTYET */ | |
| 756 | ||
| 757 | /* | |
| 758 | * Connect the data socket to a named control socket node. | |
| 759 | */ | |
| 760 | static int | |
| 761 | ng_connect_data(struct sockaddr *nam, struct ngpcb *pcbp) | |
| 762 | { | |
| 763 | struct sockaddr_ng *sap; | |
| 764 | node_p farnode; | |
| 765 | struct ngsock *priv; | |
| 766 | int error; | |
| 767 | item_p item; | |
| 768 | ||
| 769 | /* If we are already connected, don't do it again. */ | |
| 770 | if (pcbp->sockdata != NULL) | |
| 771 | return (EISCONN); | |
| 772 | ||
| 773 | /* | |
| 774 | * Find the target (victim) and check it doesn't already have | |
| 775 | * a data socket. Also check it is a 'socket' type node. | |
| 776 | * Use ng_package_data() and ng_address_path() to do this. | |
| 777 | */ | |
| 778 | ||
| 779 | sap = (struct sockaddr_ng *) nam; | |
| 780 | /* The item will hold the node reference. */ | |
| 781 | item = ng_package_data(NULL, NG_WAITOK); | |
| 782 | ||
| 783 | if ((error = ng_address_path(NULL, item, sap->sg_data, 0))) | |
| 784 | return (error); /* item is freed on failure */ | |
| 785 | ||
| 786 | /* | |
| 787 | * Extract node from item and free item. Remember we now have | |
| 788 | * a reference on the node. The item holds it for us. | |
| 789 | * when we free the item we release the reference. | |
| 790 | */ | |
| 791 | farnode = item->el_dest; /* shortcut */ | |
| 792 | if (strcmp(farnode->nd_type->name, NG_SOCKET_NODE_TYPE) != 0) { | |
| 793 | NG_FREE_ITEM(item); /* drop the reference to the node */ | |
| 794 | return (EINVAL); | |
| 795 | } | |
| 796 | priv = NG_NODE_PRIVATE(farnode); | |
| 797 | if (priv->datasock != NULL) { | |
| 798 | NG_FREE_ITEM(item); /* drop the reference to the node */ | |
| 799 | return (EADDRINUSE); | |
| 800 | } | |
| 801 | ||
| 802 | /* | |
| 803 | * Link the PCB and the private data struct. and note the extra | |
| 804 | * reference. Drop the extra reference on the node. | |
| 805 | */ | |
| 806 | mtx_lock(&priv->mtx); | |
| 807 | priv->datasock = pcbp; | |
| 808 | pcbp->sockdata = priv; | |
| 809 | priv->refs++; | |
| 810 | mtx_unlock(&priv->mtx); | |
| 811 | NG_FREE_ITEM(item); /* drop the reference to the node */ | |
| 812 | return (0); | |
| 813 | } | |
| 814 | ||
| 815 | /* | |
| 816 | * Binding a socket means giving the corresponding node a name | |
| 817 | */ | |
| 818 | static int | |
| 819 | ng_bind(struct sockaddr *nam, struct ngpcb *pcbp) | |
| 820 | { | |
| 821 | struct ngsock *const priv = pcbp->sockdata; | |
| 822 | struct sockaddr_ng *const sap = (struct sockaddr_ng *) nam; | |
| 823 | ||
| 824 | if (priv == NULL) { | |
| 825 | TRAP_ERROR; | |
| 826 | return (EINVAL); | |
| 827 | } | |
| 828 | if ((sap->sg_len < 4) || (sap->sg_len > (NG_NODESIZ + 2)) || | |
| 829 | (sap->sg_data[0] == '\0') || | |
| 830 | (sap->sg_data[sap->sg_len - 3] != '\0')) { | |
| 831 | TRAP_ERROR; | |
| 832 | return (EINVAL); | |
| 833 | } | |
| 834 | return (ng_name_node(priv->node, sap->sg_data)); | |
| 835 | } | |
| 836 | ||
| 837 | /*************************************************************** | |
| 838 | Netgraph node | |
| 839 | ***************************************************************/ | |
| 840 | ||
| 841 | /* | |
| 842 | * You can only create new nodes from the socket end of things. | |
| 843 | */ | |
| 844 | static int | |
| 845 | ngs_constructor(node_p nodep) | |
| 846 | { | |
| 847 | return (EINVAL); | |
| 848 | } | |
| 849 | ||
| 850 | /* | |
| 851 | * We allow any hook to be connected to the node. | |
| 852 | * There is no per-hook private information though. | |
| 853 | */ | |
| 854 | static int | |
| 855 | ngs_newhook(node_p node, hook_p hook, const char *name) | |
| 856 | { | |
| 857 | NG_HOOK_SET_PRIVATE(hook, NG_NODE_PRIVATE(node)); | |
| 858 | return (0); | |
| 859 | } | |
| 860 | ||
| 861 | /* | |
| 862 | * If only one hook, allow read(2) and write(2) to work. | |
| 863 | */ | |
| 864 | static int | |
| 865 | ngs_connect(hook_p hook) | |
| 866 | { | |
| 867 | node_p node = NG_HOOK_NODE(hook); | |
| 868 | struct ngsock *priv = NG_NODE_PRIVATE(node); | |
| 869 | ||
| 870 | if ((priv->datasock) && (priv->datasock->ng_socket)) { | |
| 871 | if (NG_NODE_NUMHOOKS(node) == 1) | |
| 6cef7136 | 872 | sosetstate(priv->datasock->ng_socket, SS_ISCONNECTED); |
| b06ebda0 | 873 | else |
| 6cef7136 | 874 | soclrstate(priv->datasock->ng_socket, SS_ISCONNECTED); |
| b06ebda0 MD |
875 | } |
| 876 | return (0); | |
| 877 | } | |
| 878 | ||
| 879 | /* | |
| 880 | * Incoming messages get passed up to the control socket. | |
| 881 | * Unless they are for us specifically (socket_type) | |
| 882 | */ | |
| 883 | static int | |
| 884 | ngs_rcvmsg(node_p node, item_p item, hook_p lasthook) | |
| 885 | { | |
| 886 | struct ngsock *const priv = NG_NODE_PRIVATE(node); | |
| 887 | struct ngpcb *const pcbp = priv->ctlsock; | |
| 888 | struct socket *so; | |
| 889 | struct sockaddr_ng addr; | |
| 890 | struct ng_mesg *msg; | |
| 891 | struct mbuf *m; | |
| 892 | ng_ID_t retaddr = NGI_RETADDR(item); | |
| 893 | int addrlen; | |
| 894 | int error = 0; | |
| 895 | ||
| 896 | NGI_GET_MSG(item, msg); | |
| 897 | NG_FREE_ITEM(item); | |
| 898 | ||
| 899 | /* | |
| 900 | * Only allow mesgs to be passed if we have the control socket. | |
| 901 | * Data sockets can only support the generic messages. | |
| 902 | */ | |
| 903 | if (pcbp == NULL) { | |
| 904 | TRAP_ERROR; | |
| 905 | NG_FREE_MSG(msg); | |
| 906 | return (EINVAL); | |
| 907 | } | |
| 908 | so = pcbp->ng_socket; | |
| 909 | ||
| 910 | #ifdef TRACE_MESSAGES | |
| 911 | printf("[%x]:---------->[socket]: c=<%d>cmd=%x(%s) f=%x #%d\n", | |
| 912 | retaddr, | |
| 913 | msg->header.typecookie, | |
| 914 | msg->header.cmd, | |
| 915 | msg->header.cmdstr, | |
| 916 | msg->header.flags, | |
| 917 | msg->header.token); | |
| 918 | #endif | |
| 919 | ||
| 920 | if (msg->header.typecookie == NGM_SOCKET_COOKIE) { | |
| 921 | switch (msg->header.cmd) { | |
| 922 | case NGM_SOCK_CMD_NOLINGER: | |
| 923 | priv->flags |= NGS_FLAG_NOLINGER; | |
| 924 | break; | |
| 925 | case NGM_SOCK_CMD_LINGER: | |
| 926 | priv->flags &= ~NGS_FLAG_NOLINGER; | |
| 927 | break; | |
| 928 | default: | |
| 929 | error = EINVAL; /* unknown command */ | |
| 930 | } | |
| 931 | /* Free the message and return. */ | |
| 932 | NG_FREE_MSG(msg); | |
| 933 | return (error); | |
| 934 | } | |
| 935 | ||
| 936 | /* Get the return address into a sockaddr. */ | |
| 937 | bzero(&addr, sizeof(addr)); | |
| 938 | addr.sg_len = sizeof(addr); | |
| 939 | addr.sg_family = AF_NETGRAPH; | |
| 940 | addrlen = snprintf((char *)&addr.sg_data, sizeof(addr.sg_data), | |
| 941 | "[%x]:", retaddr); | |
| 942 | if (addrlen < 0 || addrlen > sizeof(addr.sg_data)) { | |
| 943 | printf("%s: snprintf([%x]) failed - %d\n", __func__, retaddr, | |
| 944 | addrlen); | |
| 945 | NG_FREE_MSG(msg); | |
| 946 | return (EINVAL); | |
| 947 | } | |
| 948 | ||
| 949 | /* Copy the message itself into an mbuf chain. */ | |
| 950 | m = m_devget((caddr_t)msg, sizeof(struct ng_mesg) + msg->header.arglen, | |
| 951 | 0, NULL, NULL); | |
| 952 | ||
| 953 | /* | |
| 954 | * Here we free the message. We need to do that | |
| 955 | * regardless of whether we got mbufs. | |
| 956 | */ | |
| 957 | NG_FREE_MSG(msg); | |
| 958 | ||
| 959 | if (m == NULL) { | |
| 960 | TRAP_ERROR; | |
| 961 | return (ENOBUFS); | |
| 962 | } | |
| 963 | ||
| 964 | /* Send it up to the socket. */ | |
| 0147868e | 965 | if (sbappendaddr((struct sockbuf *)&so->so_rcv, (struct sockaddr *)&addr, m, NULL) == 0) { |
| b06ebda0 MD |
966 | TRAP_ERROR; |
| 967 | m_freem(m); | |
| 968 | return (ENOBUFS); | |
| 969 | } | |
| 970 | sorwakeup(so); | |
| 971 | ||
| 972 | return (error); | |
| 973 | } | |
| 974 | ||
| 975 | /* | |
| 976 | * Receive data on a hook | |
| 977 | */ | |
| 978 | static int | |
| 979 | ngs_rcvdata(hook_p hook, item_p item) | |
| 980 | { | |
| 981 | struct ngsock *const priv = NG_NODE_PRIVATE(NG_HOOK_NODE(hook)); | |
| 982 | struct ngpcb *const pcbp = priv->datasock; | |
| 983 | struct socket *so; | |
| 984 | struct sockaddr_ng *addr; | |
| 985 | char *addrbuf[NG_HOOKSIZ + 4]; | |
| 986 | int addrlen; | |
| 987 | struct mbuf *m; | |
| 988 | ||
| 989 | NGI_GET_M(item, m); | |
| 990 | NG_FREE_ITEM(item); | |
| 991 | ||
| 992 | /* If there is no data socket, black-hole it. */ | |
| 993 | if (pcbp == NULL) { | |
| 994 | NG_FREE_M(m); | |
| 995 | return (0); | |
| 996 | } | |
| 997 | so = pcbp->ng_socket; | |
| 998 | ||
| 999 | /* Get the return address into a sockaddr. */ | |
| 1000 | addrlen = strlen(NG_HOOK_NAME(hook)); /* <= NG_HOOKSIZ - 1 */ | |
| 1001 | addr = (struct sockaddr_ng *) addrbuf; | |
| 1002 | addr->sg_len = addrlen + 3; | |
| 1003 | addr->sg_family = AF_NETGRAPH; | |
| 1004 | bcopy(NG_HOOK_NAME(hook), addr->sg_data, addrlen); | |
| 1005 | addr->sg_data[addrlen] = '\0'; | |
| 1006 | ||
| 1007 | /* Try to tell the socket which hook it came in on. */ | |
| 0147868e | 1008 | if (sbappendaddr((struct sockbuf *)&so->so_rcv, (struct sockaddr *)addr, m, NULL) == 0) { |
| b06ebda0 MD |
1009 | m_freem(m); |
| 1010 | TRAP_ERROR; | |
| 1011 | return (ENOBUFS); | |
| 1012 | } | |
| 1013 | sorwakeup(so); | |
| 1014 | return (0); | |
| 1015 | } | |
| 1016 | ||
| 1017 | /* | |
| 1018 | * Hook disconnection | |
| 1019 | * | |
| 1020 | * For this type, removal of the last link destroys the node | |
| 1021 | * if the NOLINGER flag is set. | |
| 1022 | */ | |
| 1023 | static int | |
| 1024 | ngs_disconnect(hook_p hook) | |
| 1025 | { | |
| 1026 | node_p node = NG_HOOK_NODE(hook); | |
| 1027 | struct ngsock *const priv = NG_NODE_PRIVATE(node); | |
| 1028 | ||
| 1029 | if ((priv->datasock) && (priv->datasock->ng_socket)) { | |
| 1030 | if (NG_NODE_NUMHOOKS(node) == 1) | |
| 6cef7136 | 1031 | sosetstate(priv->datasock->ng_socket, SS_ISCONNECTED); |
| b06ebda0 | 1032 | else |
| 6cef7136 | 1033 | soclrstate(priv->datasock->ng_socket, SS_ISCONNECTED); |
| b06ebda0 MD |
1034 | } |
| 1035 | ||
| 1036 | if ((priv->flags & NGS_FLAG_NOLINGER) && | |
| 1037 | (NG_NODE_NUMHOOKS(node) == 0) && (NG_NODE_IS_VALID(node))) | |
| 1038 | ng_rmnode_self(node); | |
| 1039 | ||
| 1040 | return (0); | |
| 1041 | } | |
| 1042 | ||
| 1043 | /* | |
| 1044 | * Do local shutdown processing. | |
| 1045 | * In this case, that involves making sure the socket | |
| 1046 | * knows we should be shutting down. | |
| 1047 | */ | |
| 1048 | static int | |
| 1049 | ngs_shutdown(node_p node) | |
| 1050 | { | |
| 1051 | struct ngsock *const priv = NG_NODE_PRIVATE(node); | |
| 1052 | struct ngpcb *const dpcbp = priv->datasock; | |
| 1053 | struct ngpcb *const pcbp = priv->ctlsock; | |
| 1054 | ||
| 1055 | if (dpcbp != NULL) | |
| 1056 | soisdisconnected(dpcbp->ng_socket); | |
| 1057 | ||
| 1058 | if (pcbp != NULL) | |
| 1059 | soisdisconnected(pcbp->ng_socket); | |
| 1060 | ||
| 1061 | mtx_lock(&priv->mtx); | |
| 1062 | priv->node = NULL; | |
| 1063 | NG_NODE_SET_PRIVATE(node, NULL); | |
| 1064 | ng_socket_free_priv(priv); | |
| 1065 | ||
| 1066 | NG_NODE_UNREF(node); | |
| 1067 | return (0); | |
| 1068 | } | |
| 1069 | ||
| 1070 | static void | |
| 1071 | ng_socket_item_applied(void *context, int error) | |
| 1072 | { | |
| 1073 | struct ngsock *const priv = (struct ngsock *)context; | |
| 1074 | ||
| 1075 | mtx_lock(&priv->mtx); | |
| 1076 | priv->error = error; | |
| 1077 | wakeup(priv); | |
| 1078 | mtx_unlock(&priv->mtx); | |
| 1079 | ||
| 1080 | } | |
| 1081 | ||
| b06ebda0 MD |
1082 | /* |
| 1083 | * Control and data socket type descriptors | |
| 1084 | * | |
| 1085 | * XXXRW: Perhaps _close should do something? | |
| 1086 | */ | |
| 1087 | ||
| 1088 | static struct pr_usrreqs ngc_usrreqs = { | |
| 1089 | .pru_abort = NULL, | |
| 1090 | .pru_attach = ngc_attach, | |
| 1091 | .pru_bind = ngc_bind, | |
| 1092 | .pru_connect = ngc_connect, | |
| 1093 | .pru_detach = ngc_detach, | |
| e858b308 | 1094 | .pru_disconnect = NULL, |
| b06ebda0 MD |
1095 | .pru_peeraddr = NULL, |
| 1096 | .pru_send = ngc_send, | |
| 1097 | .pru_shutdown = NULL, | |
| 1098 | .pru_sockaddr = ng_getsockaddr, | |
| 0147868e NA |
1099 | .pru_sosend = sosend, |
| 1100 | .pru_soreceive = soreceive, | |
| 1101 | /* .pru_close = NULL, */ | |
| b06ebda0 MD |
1102 | }; |
| 1103 | ||
| 1104 | static struct pr_usrreqs ngd_usrreqs = { | |
| 1105 | .pru_abort = NULL, | |
| 1106 | .pru_attach = ngd_attach, | |
| 1107 | .pru_bind = NULL, | |
| 1108 | .pru_connect = ngd_connect, | |
| 1109 | .pru_detach = ngd_detach, | |
| e858b308 | 1110 | .pru_disconnect = NULL, |
| b06ebda0 MD |
1111 | .pru_peeraddr = NULL, |
| 1112 | .pru_send = ngd_send, | |
| 1113 | .pru_shutdown = NULL, | |
| 1114 | .pru_sockaddr = ng_getsockaddr, | |
| 0147868e NA |
1115 | .pru_sosend = sosend, |
| 1116 | .pru_soreceive = soreceive, | |
| 1117 | /* .pru_close = NULL, */ | |
| b06ebda0 MD |
1118 | }; |
| 1119 | ||
| 1120 | /* | |
| 1121 | * Definitions of protocols supported in the NETGRAPH domain. | |
| 1122 | */ | |
| 1123 | ||
| 1124 | extern struct domain ngdomain; /* stop compiler warnings */ | |
| 1125 | ||
| 1126 | static struct protosw ngsw[] = { | |
| 1127 | { | |
| 1128 | .pr_type = SOCK_DGRAM, | |
| 1129 | .pr_domain = &ngdomain, | |
| 1130 | .pr_protocol = NG_CONTROL, | |
| 1131 | .pr_flags = PR_ATOMIC | PR_ADDR /* | PR_RIGHTS */, | |
| 1132 | .pr_usrreqs = &ngc_usrreqs | |
| 1133 | }, | |
| 1134 | { | |
| 1135 | .pr_type = SOCK_DGRAM, | |
| 1136 | .pr_domain = &ngdomain, | |
| 1137 | .pr_protocol = NG_DATA, | |
| 1138 | .pr_flags = PR_ATOMIC | PR_ADDR, | |
| 1139 | .pr_usrreqs = &ngd_usrreqs | |
| 1140 | } | |
| 1141 | }; | |
| 1142 | ||
| 1143 | struct domain ngdomain = { | |
| 1144 | .dom_family = AF_NETGRAPH, | |
| 1145 | .dom_name = "netgraph", | |
| 1146 | .dom_protosw = ngsw, | |
| c157ff7a | 1147 | .dom_protoswNPROTOSW = &ngsw[NELEM(ngsw)] |
| b06ebda0 MD |
1148 | }; |
| 1149 | ||
| 1150 | /* | |
| 1151 | * Handle loading and unloading for this node type. | |
| 1152 | * This is to handle auxiliary linkages (e.g protocol domain addition). | |
| 1153 | */ | |
| 1154 | static int | |
| 1155 | ngs_mod_event(module_t mod, int event, void *data) | |
| 1156 | { | |
| 1157 | int error = 0; | |
| 1158 | ||
| 1159 | switch (event) { | |
| 1160 | case MOD_LOAD: | |
| 1161 | /* Register protocol domain. */ | |
| 1162 | net_add_domain(&ngdomain); | |
| 1163 | break; | |
| 1164 | case MOD_UNLOAD: | |
| 1165 | #ifdef NOTYET | |
| 1166 | /* Unregister protocol domain XXX can't do this yet.. */ | |
| 1167 | if ((error = net_rm_domain(&ngdomain)) != 0) | |
| 1168 | break; | |
| 1169 | else | |
| 1170 | #endif | |
| 1171 | error = EBUSY; | |
| 1172 | break; | |
| 1173 | default: | |
| 1174 | error = EOPNOTSUPP; | |
| 1175 | break; | |
| 1176 | } | |
| 1177 | return (error); | |
| 1178 | } | |
| 1179 | ||
| ac58e50c NA |
1180 | static int |
| 1181 | linker_api_available(void) | |
| 1182 | { | |
| 1183 | /* linker_* API won't work without a process context */ | |
| 1184 | if (curproc == NULL) | |
| 1185 | return 0; | |
| 1186 | /* | |
| 1187 | * nlookup_init() relies on namei_oc to be initialized, | |
| 1188 | * but it's not when the netgraph module is loaded during boot. | |
| 1189 | */ | |
| 1190 | if (namei_oc == NULL) | |
| 1191 | return 0; | |
| 1192 | return 1; | |
| 1193 | } | |
| 1194 | ||
| b06ebda0 MD |
1195 | SYSCTL_INT(_net_graph, OID_AUTO, family, CTLFLAG_RD, 0, AF_NETGRAPH, ""); |
| 1196 | SYSCTL_NODE(_net_graph, OID_AUTO, data, CTLFLAG_RW, 0, "DATA"); | |
| 1197 | SYSCTL_INT(_net_graph_data, OID_AUTO, proto, CTLFLAG_RD, 0, NG_DATA, ""); | |
| 1198 | SYSCTL_NODE(_net_graph, OID_AUTO, control, CTLFLAG_RW, 0, "CONTROL"); | |
| 1199 | SYSCTL_INT(_net_graph_control, OID_AUTO, proto, CTLFLAG_RD, 0, NG_CONTROL, ""); | |
| 1200 |