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