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