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