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