1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2021 Ng Peng Nam Sean 5 * Copyright (c) 2022 Alexander V. Chernikov <melifaro@FreeBSD.org> 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 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 /* 30 * This file contains socket and protocol bindings for netlink. 31 */ 32 33 #include <sys/param.h> 34 #include <sys/kernel.h> 35 #include <sys/malloc.h> 36 #include <sys/lock.h> 37 #include <sys/rmlock.h> 38 #include <sys/domain.h> 39 #include <sys/jail.h> 40 #include <sys/mbuf.h> 41 #include <sys/protosw.h> 42 #include <sys/proc.h> 43 #include <sys/ck.h> 44 #include <sys/socket.h> 45 #include <sys/socketvar.h> 46 #include <sys/sysent.h> 47 #include <sys/syslog.h> 48 #include <sys/priv.h> /* priv_check */ 49 50 #include <netlink/netlink.h> 51 #include <netlink/netlink_ctl.h> 52 #include <netlink/netlink_var.h> 53 54 #define DEBUG_MOD_NAME nl_domain 55 #define DEBUG_MAX_LEVEL LOG_DEBUG3 56 #include <netlink/netlink_debug.h> 57 _DECLARE_DEBUG(LOG_DEBUG); 58 59 _Static_assert((NLP_MAX_GROUPS % 64) == 0, 60 "NLP_MAX_GROUPS has to be multiple of 64"); 61 _Static_assert(NLP_MAX_GROUPS >= 64, 62 "NLP_MAX_GROUPS has to be at least 64"); 63 64 #define NLCTL_TRACKER struct rm_priotracker nl_tracker 65 #define NLCTL_RLOCK(_ctl) rm_rlock(&((_ctl)->ctl_lock), &nl_tracker) 66 #define NLCTL_RUNLOCK(_ctl) rm_runlock(&((_ctl)->ctl_lock), &nl_tracker) 67 68 #define NLCTL_WLOCK(_ctl) rm_wlock(&((_ctl)->ctl_lock)) 69 #define NLCTL_WUNLOCK(_ctl) rm_wunlock(&((_ctl)->ctl_lock)) 70 71 static u_long nl_sendspace = NLSNDQ; 72 SYSCTL_ULONG(_net_netlink, OID_AUTO, sendspace, CTLFLAG_RW, &nl_sendspace, 0, 73 "Default netlink socket send space"); 74 75 static u_long nl_recvspace = NLSNDQ; 76 SYSCTL_ULONG(_net_netlink, OID_AUTO, recvspace, CTLFLAG_RW, &nl_recvspace, 0, 77 "Default netlink socket receive space"); 78 79 extern u_long sb_max_adj; 80 static u_long nl_maxsockbuf = 512 * 1024 * 1024; /* 512M, XXX: init based on physmem */ 81 static int sysctl_handle_nl_maxsockbuf(SYSCTL_HANDLER_ARGS); 82 SYSCTL_OID(_net_netlink, OID_AUTO, nl_maxsockbuf, 83 CTLTYPE_ULONG | CTLFLAG_RW | CTLFLAG_MPSAFE, &nl_maxsockbuf, 0, 84 sysctl_handle_nl_maxsockbuf, "LU", 85 "Maximum Netlink socket buffer size"); 86 87 /* 88 * Looks up a nlpcb struct based on the @portid. Need to claim nlsock_mtx. 89 * Returns nlpcb pointer if present else NULL 90 */ 91 static struct nlpcb * 92 nl_port_lookup(uint32_t port_id) 93 { 94 struct nlpcb *nlp; 95 96 CK_LIST_FOREACH(nlp, &V_nl_ctl->ctl_port_head, nl_port_next) { 97 if (nlp->nl_port == port_id) 98 return (nlp); 99 } 100 return (NULL); 101 } 102 103 static void 104 nl_add_group_locked(struct nlpcb *nlp, unsigned int group_id) 105 { 106 MPASS(group_id <= NLP_MAX_GROUPS); 107 --group_id; 108 109 /* TODO: add family handler callback */ 110 if (!nlp_unconstrained_vnet(nlp)) 111 return; 112 113 nlp->nl_groups[group_id / 64] |= (uint64_t)1 << (group_id % 64); 114 } 115 116 static void 117 nl_del_group_locked(struct nlpcb *nlp, unsigned int group_id) 118 { 119 MPASS(group_id <= NLP_MAX_GROUPS); 120 --group_id; 121 122 nlp->nl_groups[group_id / 64] &= ~((uint64_t)1 << (group_id % 64)); 123 } 124 125 static bool 126 nl_isset_group_locked(struct nlpcb *nlp, unsigned int group_id) 127 { 128 MPASS(group_id <= NLP_MAX_GROUPS); 129 --group_id; 130 131 return (nlp->nl_groups[group_id / 64] & ((uint64_t)1 << (group_id % 64))); 132 } 133 134 static uint32_t 135 nl_get_groups_compat(struct nlpcb *nlp) 136 { 137 uint32_t groups_mask = 0; 138 139 for (int i = 0; i < 32; i++) { 140 if (nl_isset_group_locked(nlp, i + 1)) 141 groups_mask |= (1 << i); 142 } 143 144 return (groups_mask); 145 } 146 147 /* 148 * Broadcasts message @m to the protocol @proto group specified by @group_id 149 */ 150 void 151 nl_send_group(struct mbuf *m, int num_messages, int proto, int group_id) 152 { 153 struct nlpcb *nlp_last = NULL; 154 struct nlpcb *nlp; 155 NLCTL_TRACKER; 156 157 IF_DEBUG_LEVEL(LOG_DEBUG2) { 158 struct nlmsghdr *hdr = mtod(m, struct nlmsghdr *); 159 NL_LOG(LOG_DEBUG2, "MCAST mbuf len %u msg type %d len %u to group %d/%d", 160 m->m_len, hdr->nlmsg_type, hdr->nlmsg_len, proto, group_id); 161 } 162 163 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 164 if (__predict_false(ctl == NULL)) { 165 /* 166 * Can be the case when notification is sent within VNET 167 * which doesn't have any netlink sockets. 168 */ 169 m_freem(m); 170 return; 171 } 172 173 NLCTL_RLOCK(ctl); 174 175 int io_flags = NL_IOF_UNTRANSLATED; 176 177 CK_LIST_FOREACH(nlp, &ctl->ctl_pcb_head, nl_next) { 178 if (nl_isset_group_locked(nlp, group_id) && nlp->nl_proto == proto) { 179 if (nlp_last != NULL) { 180 struct mbuf *m_copy; 181 m_copy = m_copym(m, 0, M_COPYALL, M_NOWAIT); 182 if (m_copy != NULL) 183 nl_send_one(m_copy, nlp_last, num_messages, io_flags); 184 else { 185 NLP_LOCK(nlp_last); 186 if (nlp_last->nl_socket != NULL) 187 sorwakeup(nlp_last->nl_socket); 188 NLP_UNLOCK(nlp_last); 189 } 190 } 191 nlp_last = nlp; 192 } 193 } 194 if (nlp_last != NULL) 195 nl_send_one(m, nlp_last, num_messages, io_flags); 196 else 197 m_freem(m); 198 199 NLCTL_RUNLOCK(ctl); 200 } 201 202 bool 203 nl_has_listeners(int netlink_family, uint32_t groups_mask) 204 { 205 return (V_nl_ctl != NULL); 206 } 207 208 static uint32_t 209 nl_find_port(void) 210 { 211 /* 212 * app can open multiple netlink sockets. 213 * Start with current pid, if already taken, 214 * try random numbers in 65k..256k+65k space, 215 * avoiding clash with pids. 216 */ 217 if (nl_port_lookup(curproc->p_pid) == NULL) 218 return (curproc->p_pid); 219 for (int i = 0; i < 16; i++) { 220 uint32_t nl_port = (arc4random() % 65536) + 65536 * 4; 221 if (nl_port_lookup(nl_port) == 0) 222 return (nl_port); 223 NL_LOG(LOG_DEBUG3, "tried %u\n", nl_port); 224 } 225 return (curproc->p_pid); 226 } 227 228 static int 229 nl_bind_locked(struct nlpcb *nlp, struct sockaddr_nl *snl) 230 { 231 if (nlp->nl_bound) { 232 if (nlp->nl_port != snl->nl_pid) { 233 NL_LOG(LOG_DEBUG, 234 "bind() failed: program pid %d " 235 "is different from provided pid %d", 236 nlp->nl_port, snl->nl_pid); 237 return (EINVAL); // XXX: better error 238 } 239 } else { 240 if (snl->nl_pid == 0) 241 snl->nl_pid = nl_find_port(); 242 if (nl_port_lookup(snl->nl_pid) != NULL) 243 return (EADDRINUSE); 244 nlp->nl_port = snl->nl_pid; 245 nlp->nl_bound = true; 246 CK_LIST_INSERT_HEAD(&V_nl_ctl->ctl_port_head, nlp, nl_port_next); 247 } 248 for (int i = 0; i < 32; i++) { 249 if (snl->nl_groups & ((uint32_t)1 << i)) 250 nl_add_group_locked(nlp, i + 1); 251 else 252 nl_del_group_locked(nlp, i + 1); 253 } 254 255 return (0); 256 } 257 258 static int 259 nl_pru_attach(struct socket *so, int proto, struct thread *td) 260 { 261 struct nlpcb *nlp; 262 int error; 263 264 if (__predict_false(netlink_unloading != 0)) 265 return (EAFNOSUPPORT); 266 267 error = nl_verify_proto(proto); 268 if (error != 0) 269 return (error); 270 271 bool is_linux = SV_PROC_ABI(td->td_proc) == SV_ABI_LINUX; 272 NL_LOG(LOG_DEBUG2, "socket %p, %sPID %d: attaching socket to %s", 273 so, is_linux ? "(linux) " : "", curproc->p_pid, 274 nl_get_proto_name(proto)); 275 276 /* Create per-VNET state on first socket init */ 277 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 278 if (ctl == NULL) 279 ctl = vnet_nl_ctl_init(); 280 KASSERT(V_nl_ctl != NULL, ("nl_attach: vnet_sock_init() failed")); 281 282 MPASS(sotonlpcb(so) == NULL); 283 284 nlp = malloc(sizeof(struct nlpcb), M_PCB, M_WAITOK | M_ZERO); 285 error = soreserve(so, nl_sendspace, nl_recvspace); 286 if (error != 0) { 287 free(nlp, M_PCB); 288 return (error); 289 } 290 so->so_pcb = nlp; 291 nlp->nl_socket = so; 292 /* Copy so_cred to avoid having socket_var.h in every header */ 293 nlp->nl_cred = so->so_cred; 294 nlp->nl_proto = proto; 295 nlp->nl_process_id = curproc->p_pid; 296 nlp->nl_linux = is_linux; 297 nlp->nl_active = true; 298 nlp->nl_unconstrained_vnet = !jailed_without_vnet(so->so_cred); 299 NLP_LOCK_INIT(nlp); 300 refcount_init(&nlp->nl_refcount, 1); 301 nl_init_io(nlp); 302 303 nlp->nl_taskqueue = taskqueue_create("netlink_socket", M_WAITOK, 304 taskqueue_thread_enqueue, &nlp->nl_taskqueue); 305 TASK_INIT(&nlp->nl_task, 0, nl_taskqueue_handler, nlp); 306 taskqueue_start_threads(&nlp->nl_taskqueue, 1, PWAIT, 307 "netlink_socket (PID %u)", nlp->nl_process_id); 308 309 NLCTL_WLOCK(ctl); 310 /* XXX: check ctl is still alive */ 311 CK_LIST_INSERT_HEAD(&ctl->ctl_pcb_head, nlp, nl_next); 312 NLCTL_WUNLOCK(ctl); 313 314 soisconnected(so); 315 316 return (0); 317 } 318 319 static void 320 nl_pru_abort(struct socket *so) 321 { 322 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 323 MPASS(sotonlpcb(so) != NULL); 324 soisdisconnected(so); 325 } 326 327 static int 328 nl_pru_bind(struct socket *so, struct sockaddr *sa, struct thread *td) 329 { 330 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 331 struct nlpcb *nlp = sotonlpcb(so); 332 struct sockaddr_nl *snl = (struct sockaddr_nl *)sa; 333 int error; 334 335 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 336 if (snl->nl_len != sizeof(*snl)) { 337 NL_LOG(LOG_DEBUG, "socket %p, wrong sizeof(), ignoring bind()", so); 338 return (EINVAL); 339 } 340 341 342 NLCTL_WLOCK(ctl); 343 NLP_LOCK(nlp); 344 error = nl_bind_locked(nlp, snl); 345 NLP_UNLOCK(nlp); 346 NLCTL_WUNLOCK(ctl); 347 NL_LOG(LOG_DEBUG2, "socket %p, bind() to %u, groups %u, error %d", so, 348 snl->nl_pid, snl->nl_groups, error); 349 350 return (error); 351 } 352 353 354 static int 355 nl_assign_port(struct nlpcb *nlp, uint32_t port_id) 356 { 357 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 358 struct sockaddr_nl snl = { 359 .nl_pid = port_id, 360 }; 361 int error; 362 363 NLCTL_WLOCK(ctl); 364 NLP_LOCK(nlp); 365 snl.nl_groups = nl_get_groups_compat(nlp); 366 error = nl_bind_locked(nlp, &snl); 367 NLP_UNLOCK(nlp); 368 NLCTL_WUNLOCK(ctl); 369 370 NL_LOG(LOG_DEBUG3, "socket %p, port assign: %d, error: %d", nlp->nl_socket, port_id, error); 371 return (error); 372 } 373 374 /* 375 * nl_autobind_port binds a unused portid to @nlp 376 * @nlp: pcb data for the netlink socket 377 * @candidate_id: first id to consider 378 */ 379 static int 380 nl_autobind_port(struct nlpcb *nlp, uint32_t candidate_id) 381 { 382 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 383 uint32_t port_id = candidate_id; 384 NLCTL_TRACKER; 385 bool exist; 386 int error = EADDRINUSE; 387 388 for (int i = 0; i < 10; i++) { 389 NL_LOG(LOG_DEBUG3, "socket %p, trying to assign port %d", nlp->nl_socket, port_id); 390 NLCTL_RLOCK(ctl); 391 exist = nl_port_lookup(port_id) != 0; 392 NLCTL_RUNLOCK(ctl); 393 if (!exist) { 394 error = nl_assign_port(nlp, port_id); 395 if (error != EADDRINUSE) 396 break; 397 } 398 port_id++; 399 } 400 NL_LOG(LOG_DEBUG3, "socket %p, autobind to %d, error: %d", nlp->nl_socket, port_id, error); 401 return (error); 402 } 403 404 static int 405 nl_pru_connect(struct socket *so, struct sockaddr *sa, struct thread *td) 406 { 407 struct sockaddr_nl *snl = (struct sockaddr_nl *)sa; 408 struct nlpcb *nlp; 409 410 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 411 if (snl->nl_len != sizeof(*snl)) { 412 NL_LOG(LOG_DEBUG, "socket %p, wrong sizeof(), ignoring bind()", so); 413 return (EINVAL); 414 } 415 416 nlp = sotonlpcb(so); 417 if (!nlp->nl_bound) { 418 int error = nl_autobind_port(nlp, td->td_proc->p_pid); 419 if (error != 0) { 420 NL_LOG(LOG_DEBUG, "socket %p, nl_autobind() failed: %d", so, error); 421 return (error); 422 } 423 } 424 /* XXX: Handle socket flags & multicast */ 425 soisconnected(so); 426 427 NL_LOG(LOG_DEBUG2, "socket %p, connect to %u", so, snl->nl_pid); 428 429 return (0); 430 } 431 432 static void 433 destroy_nlpcb(struct nlpcb *nlp) 434 { 435 NLP_LOCK(nlp); 436 nl_free_io(nlp); 437 NLP_LOCK_DESTROY(nlp); 438 free(nlp, M_PCB); 439 } 440 441 static void 442 destroy_nlpcb_epoch(epoch_context_t ctx) 443 { 444 struct nlpcb *nlp; 445 446 nlp = __containerof(ctx, struct nlpcb, nl_epoch_ctx); 447 448 destroy_nlpcb(nlp); 449 } 450 451 452 static void 453 nl_pru_detach(struct socket *so) 454 { 455 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 456 MPASS(sotonlpcb(so) != NULL); 457 struct nlpcb *nlp; 458 459 NL_LOG(LOG_DEBUG2, "detaching socket %p, PID %d", so, curproc->p_pid); 460 nlp = sotonlpcb(so); 461 462 /* Mark as inactive so no new work can be enqueued */ 463 NLP_LOCK(nlp); 464 bool was_bound = nlp->nl_bound; 465 nlp->nl_active = false; 466 NLP_UNLOCK(nlp); 467 468 /* Wait till all scheduled work has been completed */ 469 taskqueue_drain_all(nlp->nl_taskqueue); 470 taskqueue_free(nlp->nl_taskqueue); 471 472 NLCTL_WLOCK(ctl); 473 NLP_LOCK(nlp); 474 if (was_bound) { 475 CK_LIST_REMOVE(nlp, nl_port_next); 476 NL_LOG(LOG_DEBUG3, "socket %p, unlinking bound pid %u", so, nlp->nl_port); 477 } 478 CK_LIST_REMOVE(nlp, nl_next); 479 nlp->nl_socket = NULL; 480 NLP_UNLOCK(nlp); 481 NLCTL_WUNLOCK(ctl); 482 483 so->so_pcb = NULL; 484 485 NL_LOG(LOG_DEBUG3, "socket %p, detached", so); 486 487 /* XXX: is delayed free needed? */ 488 NET_EPOCH_CALL(destroy_nlpcb_epoch, &nlp->nl_epoch_ctx); 489 } 490 491 static int 492 nl_pru_disconnect(struct socket *so) 493 { 494 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 495 MPASS(sotonlpcb(so) != NULL); 496 return (ENOTCONN); 497 } 498 499 static int 500 nl_pru_peeraddr(struct socket *so, struct sockaddr **sa) 501 { 502 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 503 MPASS(sotonlpcb(so) != NULL); 504 return (ENOTCONN); 505 } 506 507 static int 508 nl_pru_shutdown(struct socket *so) 509 { 510 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 511 MPASS(sotonlpcb(so) != NULL); 512 socantsendmore(so); 513 return (0); 514 } 515 516 static int 517 nl_pru_sockaddr(struct socket *so, struct sockaddr **sa) 518 { 519 struct sockaddr_nl *snl; 520 521 snl = malloc(sizeof(struct sockaddr_nl), M_SONAME, M_WAITOK | M_ZERO); 522 /* TODO: set other fields */ 523 snl->nl_len = sizeof(struct sockaddr_nl); 524 snl->nl_family = AF_NETLINK; 525 snl->nl_pid = sotonlpcb(so)->nl_port; 526 *sa = (struct sockaddr *)snl; 527 return (0); 528 } 529 530 static void 531 nl_pru_close(struct socket *so) 532 { 533 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 534 MPASS(sotonlpcb(so) != NULL); 535 soisdisconnected(so); 536 } 537 538 static int 539 nl_pru_output(struct mbuf *m, struct socket *so, ...) 540 { 541 542 if (__predict_false(m == NULL || 543 ((m->m_len < sizeof(struct nlmsghdr)) && 544 (m = m_pullup(m, sizeof(struct nlmsghdr))) == NULL))) 545 return (ENOBUFS); 546 MPASS((m->m_flags & M_PKTHDR) != 0); 547 548 NL_LOG(LOG_DEBUG3, "sending message to kernel async processing"); 549 nl_receive_async(m, so); 550 return (0); 551 } 552 553 554 static int 555 nl_pru_send(struct socket *so, int flags, struct mbuf *m, struct sockaddr *sa, 556 struct mbuf *control, struct thread *td) 557 { 558 NL_LOG(LOG_DEBUG2, "sending message to kernel"); 559 560 if (__predict_false(control != NULL)) { 561 if (control->m_len) { 562 m_freem(control); 563 return (EINVAL); 564 } 565 m_freem(control); 566 } 567 568 return (nl_pru_output(m, so)); 569 } 570 571 static int 572 nl_pru_rcvd(struct socket *so, int flags) 573 { 574 NL_LOG(LOG_DEBUG3, "socket %p, PID %d", so, curproc->p_pid); 575 MPASS(sotonlpcb(so) != NULL); 576 577 nl_on_transmit(sotonlpcb(so)); 578 579 return (0); 580 } 581 582 static int 583 nl_getoptflag(int sopt_name) 584 { 585 switch (sopt_name) { 586 case NETLINK_CAP_ACK: 587 return (NLF_CAP_ACK); 588 case NETLINK_EXT_ACK: 589 return (NLF_EXT_ACK); 590 case NETLINK_GET_STRICT_CHK: 591 return (NLF_STRICT); 592 } 593 594 return (0); 595 } 596 597 static int 598 nl_ctloutput(struct socket *so, struct sockopt *sopt) 599 { 600 struct nl_control *ctl = atomic_load_ptr(&V_nl_ctl); 601 struct nlpcb *nlp = sotonlpcb(so); 602 uint32_t flag; 603 int optval, error = 0; 604 NLCTL_TRACKER; 605 606 NL_LOG(LOG_DEBUG2, "%ssockopt(%p, %d)", (sopt->sopt_dir) ? "set" : "get", 607 so, sopt->sopt_name); 608 609 switch (sopt->sopt_dir) { 610 case SOPT_SET: 611 switch (sopt->sopt_name) { 612 case NETLINK_ADD_MEMBERSHIP: 613 case NETLINK_DROP_MEMBERSHIP: 614 error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 615 if (error != 0) 616 break; 617 if (optval <= 0 || optval >= NLP_MAX_GROUPS) { 618 error = ERANGE; 619 break; 620 } 621 NL_LOG(LOG_DEBUG2, "ADD/DEL group %d", (uint32_t)optval); 622 623 NLCTL_WLOCK(ctl); 624 if (sopt->sopt_name == NETLINK_ADD_MEMBERSHIP) 625 nl_add_group_locked(nlp, optval); 626 else 627 nl_del_group_locked(nlp, optval); 628 NLCTL_WUNLOCK(ctl); 629 break; 630 case NETLINK_CAP_ACK: 631 case NETLINK_EXT_ACK: 632 case NETLINK_GET_STRICT_CHK: 633 error = sooptcopyin(sopt, &optval, sizeof(optval), sizeof(optval)); 634 if (error != 0) 635 break; 636 637 flag = nl_getoptflag(sopt->sopt_name); 638 639 NLCTL_WLOCK(ctl); 640 if (optval != 0) 641 nlp->nl_flags |= flag; 642 else 643 nlp->nl_flags &= ~flag; 644 NLCTL_WUNLOCK(ctl); 645 break; 646 default: 647 error = ENOPROTOOPT; 648 } 649 break; 650 case SOPT_GET: 651 switch (sopt->sopt_name) { 652 case NETLINK_LIST_MEMBERSHIPS: 653 NLCTL_RLOCK(ctl); 654 optval = nl_get_groups_compat(nlp); 655 NLCTL_RUNLOCK(ctl); 656 error = sooptcopyout(sopt, &optval, sizeof(optval)); 657 break; 658 case NETLINK_CAP_ACK: 659 case NETLINK_EXT_ACK: 660 case NETLINK_GET_STRICT_CHK: 661 NLCTL_RLOCK(ctl); 662 optval = (nlp->nl_flags & nl_getoptflag(sopt->sopt_name)) != 0; 663 NLCTL_RUNLOCK(ctl); 664 error = sooptcopyout(sopt, &optval, sizeof(optval)); 665 break; 666 default: 667 error = ENOPROTOOPT; 668 } 669 break; 670 default: 671 error = ENOPROTOOPT; 672 } 673 674 return (error); 675 } 676 677 static int 678 sysctl_handle_nl_maxsockbuf(SYSCTL_HANDLER_ARGS) 679 { 680 int error = 0; 681 u_long tmp_maxsockbuf = nl_maxsockbuf; 682 683 error = sysctl_handle_long(oidp, &tmp_maxsockbuf, arg2, req); 684 if (error || !req->newptr) 685 return (error); 686 if (tmp_maxsockbuf < MSIZE + MCLBYTES) 687 return (EINVAL); 688 nl_maxsockbuf = tmp_maxsockbuf; 689 690 return (0); 691 } 692 693 static int 694 nl_setsbopt(struct socket *so, struct sockopt *sopt) 695 { 696 int error, optval; 697 bool result; 698 699 if (sopt->sopt_name != SO_RCVBUF) 700 return (sbsetopt(so, sopt)); 701 702 /* Allow to override max buffer size in certain conditions */ 703 704 error = sooptcopyin(sopt, &optval, sizeof optval, sizeof optval); 705 if (error != 0) 706 return (error); 707 NL_LOG(LOG_DEBUG2, "socket %p, PID %d, SO_RCVBUF=%d", so, curproc->p_pid, optval); 708 if (optval > sb_max_adj) { 709 if (priv_check(curthread, PRIV_NET_ROUTE) != 0) 710 return (EPERM); 711 } 712 713 SOCK_RECVBUF_LOCK(so); 714 result = sbreserve_locked_limit(so, SO_RCV, optval, nl_maxsockbuf, curthread); 715 SOCK_RECVBUF_UNLOCK(so); 716 717 return (result ? 0 : ENOBUFS); 718 } 719 720 #define NETLINK_PROTOSW \ 721 .pr_flags = PR_ATOMIC | PR_ADDR | PR_WANTRCVD, \ 722 .pr_ctloutput = nl_ctloutput, \ 723 .pr_setsbopt = nl_setsbopt, \ 724 .pr_abort = nl_pru_abort, \ 725 .pr_attach = nl_pru_attach, \ 726 .pr_bind = nl_pru_bind, \ 727 .pr_connect = nl_pru_connect, \ 728 .pr_detach = nl_pru_detach, \ 729 .pr_disconnect = nl_pru_disconnect, \ 730 .pr_peeraddr = nl_pru_peeraddr, \ 731 .pr_send = nl_pru_send, \ 732 .pr_rcvd = nl_pru_rcvd, \ 733 .pr_shutdown = nl_pru_shutdown, \ 734 .pr_sockaddr = nl_pru_sockaddr, \ 735 .pr_close = nl_pru_close 736 737 static struct protosw netlink_raw_sw = { 738 .pr_type = SOCK_RAW, 739 NETLINK_PROTOSW 740 }; 741 742 static struct protosw netlink_dgram_sw = { 743 .pr_type = SOCK_DGRAM, 744 NETLINK_PROTOSW 745 }; 746 747 static struct domain netlinkdomain = { 748 .dom_family = PF_NETLINK, 749 .dom_name = "netlink", 750 .dom_flags = DOMF_UNLOADABLE, 751 .dom_nprotosw = 2, 752 .dom_protosw = { &netlink_raw_sw, &netlink_dgram_sw }, 753 }; 754 755 DOMAIN_SET(netlink); 756