1 /* $NetBSD: in_proto.c,v 1.127 2018/03/15 08:15:21 maxv Exp $ */ 2 3 /* 4 * Copyright (C) 1995, 1996, 1997, and 1998 WIDE Project. 5 * All rights reserved. 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 * 3. Neither the name of the project nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32 /* 33 * Copyright (c) 1982, 1986, 1993 34 * The Regents of the University of California. All rights reserved. 35 * 36 * Redistribution and use in source and binary forms, with or without 37 * modification, are permitted provided that the following conditions 38 * are met: 39 * 1. Redistributions of source code must retain the above copyright 40 * notice, this list of conditions and the following disclaimer. 41 * 2. Redistributions in binary form must reproduce the above copyright 42 * notice, this list of conditions and the following disclaimer in the 43 * documentation and/or other materials provided with the distribution. 44 * 3. Neither the name of the University nor the names of its contributors 45 * may be used to endorse or promote products derived from this software 46 * without specific prior written permission. 47 * 48 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 49 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 50 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 51 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 52 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 53 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 54 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 55 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 56 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 57 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 58 * SUCH DAMAGE. 59 * 60 * @(#)in_proto.c 8.2 (Berkeley) 2/9/95 61 */ 62 63 #include <sys/cdefs.h> 64 __KERNEL_RCSID(0, "$NetBSD: in_proto.c,v 1.127 2018/03/15 08:15:21 maxv Exp $"); 65 66 #ifdef _KERNEL_OPT 67 #include "opt_mrouting.h" 68 #include "opt_inet.h" 69 #include "opt_ipsec.h" 70 #include "opt_pim.h" 71 #include "opt_gateway.h" 72 #include "opt_dccp.h" 73 #include "opt_sctp.h" 74 #include "opt_compat_netbsd.h" 75 #include "opt_net_mpsafe.h" 76 #endif 77 78 #include <sys/param.h> 79 #include <sys/socket.h> 80 #include <sys/protosw.h> 81 #include <sys/domain.h> 82 #include <sys/mbuf.h> 83 84 #include <net/if.h> 85 86 #include <netinet/in.h> 87 #include <netinet/in_systm.h> 88 #include <netinet/in_var.h> 89 #include <netinet/ip.h> 90 #include <netinet/ip_var.h> 91 #include <netinet/ip_icmp.h> 92 #include <netinet/in_ifattach.h> 93 #include <netinet/in_pcb.h> 94 #include <netinet/in_proto.h> 95 96 #ifdef INET6 97 #ifndef INET 98 #include <netinet/in.h> 99 #endif 100 #include <netinet/ip6.h> 101 #endif 102 103 #include <netinet/igmp_var.h> 104 #ifdef PIM 105 #include <netinet/pim_var.h> 106 #endif 107 #include <netinet/tcp.h> 108 #include <netinet/tcp_fsm.h> 109 #include <netinet/tcp_seq.h> 110 #include <netinet/tcp_timer.h> 111 #include <netinet/tcp_var.h> 112 #include <netinet/tcpip.h> 113 #include <netinet/tcp_debug.h> 114 #include <netinet/udp.h> 115 #include <netinet/udp_var.h> 116 #include <netinet/ip_encap.h> 117 118 #ifdef DCCP 119 #include <netinet/dccp.h> 120 #include <netinet/dccp_var.h> 121 #endif 122 123 #ifdef SCTP 124 #include <netinet/sctp.h> 125 #include <netinet/sctp_var.h> 126 #endif 127 128 /* 129 * TCP/IP protocol family: IP, ICMP, UDP, TCP. 130 */ 131 132 #ifdef IPSEC 133 #include <netipsec/ipsec.h> 134 #include <netipsec/key.h> 135 #endif /* IPSEC */ 136 137 #include "carp.h" 138 #if NCARP > 0 139 #include <netinet/ip_carp.h> 140 #endif 141 142 #include "pfsync.h" 143 #if NPFSYNC > 0 144 #include <net/pfvar.h> 145 #include <net/if_pfsync.h> 146 #endif 147 148 #include "etherip.h" 149 #if NETHERIP > 0 150 #include <netinet/ip_etherip.h> 151 #endif 152 153 DOMAIN_DEFINE(inetdomain); /* forward declare and add to link set */ 154 155 /* Wrappers to acquire kernel_lock. */ 156 157 PR_WRAP_CTLINPUT(rip_ctlinput) 158 PR_WRAP_CTLINPUT(udp_ctlinput) 159 PR_WRAP_CTLINPUT(tcp_ctlinput) 160 161 #define rip_ctlinput rip_ctlinput_wrapper 162 #define udp_ctlinput udp_ctlinput_wrapper 163 #define tcp_ctlinput tcp_ctlinput_wrapper 164 165 PR_WRAP_CTLOUTPUT(rip_ctloutput) 166 PR_WRAP_CTLOUTPUT(udp_ctloutput) 167 PR_WRAP_CTLOUTPUT(tcp_ctloutput) 168 169 #define rip_ctloutput rip_ctloutput_wrapper 170 #define udp_ctloutput udp_ctloutput_wrapper 171 #define tcp_ctloutput tcp_ctloutput_wrapper 172 173 #ifdef DCCP 174 PR_WRAP_CTLINPUT(dccp_ctlinput) 175 PR_WRAP_CTLOUTPUT(dccp_ctloutput) 176 177 #define dccp_ctlinput dccp_ctlinput_wrapper 178 #define dccp_ctloutput dccp_ctloutput_wrapper 179 #endif 180 181 #ifdef SCTP 182 PR_WRAP_CTLINPUT(sctp_ctlinput) 183 PR_WRAP_CTLOUTPUT(sctp_ctloutput) 184 185 #define sctp_ctlinput sctp_ctlinput_wrapper 186 #define sctp_ctloutput sctp_ctloutput_wrapper 187 #endif 188 189 #ifdef NET_MPSAFE 190 PR_WRAP_INPUT(udp_input) 191 PR_WRAP_INPUT(tcp_input) 192 #ifdef DCCP 193 PR_WRAP_INPUT(dccp_input) 194 #endif 195 #ifdef SCTP 196 PR_WRAP_INPUT(sctp_input) 197 #endif 198 PR_WRAP_INPUT(rip_input) 199 #if NETHERIP > 0 200 PR_WRAP_INPUT(ip_etherip_input) 201 #endif 202 #if NPFSYNC > 0 203 PR_WRAP_INPUT(pfsync_input) 204 #endif 205 PR_WRAP_INPUT(igmp_input) 206 #ifdef PIM 207 PR_WRAP_INPUT(pim_input) 208 #endif 209 210 #define udp_input udp_input_wrapper 211 #define tcp_input tcp_input_wrapper 212 #define dccp_input dccp_input_wrapper 213 #define sctp_input sctp_input_wrapper 214 #define rip_input rip_input_wrapper 215 #define ip_etherip_input ip_etherip_input_wrapper 216 #define pfsync_input pfsync_input_wrapper 217 #define igmp_input igmp_input_wrapper 218 #define pim_input pim_input_wrapper 219 #endif 220 221 #if defined(IPSEC) 222 223 #ifdef IPSEC_RUMPKERNEL 224 /* 225 * .pr_input = ipsec4_common_input won't be resolved on loading 226 * the ipsec shared library. We need a wrapper anyway. 227 */ 228 static void 229 ipsec4_common_input_wrapper(struct mbuf *m, ...) 230 { 231 232 if (ipsec_enabled) { 233 int off, nxt; 234 va_list args; 235 /* XXX just passing args to ipsec4_common_input doesn't work */ 236 va_start(args, m); 237 off = va_arg(args, int); 238 nxt = va_arg(args, int); 239 va_end(args); 240 ipsec4_common_input(m, off, nxt); 241 } else { 242 m_freem(m); 243 } 244 } 245 #define ipsec4_common_input ipsec4_common_input_wrapper 246 247 /* The ctlinput functions may not be loaded */ 248 #define IPSEC_WRAP_CTLINPUT(name) \ 249 static void * \ 250 name##_wrapper(int a, const struct sockaddr *b, void *c)\ 251 { \ 252 void *rv; \ 253 KERNEL_LOCK(1, NULL); \ 254 if (ipsec_enabled) \ 255 rv = name(a, b, c); \ 256 else \ 257 rv = NULL; \ 258 KERNEL_UNLOCK_ONE(NULL); \ 259 return rv; \ 260 } 261 IPSEC_WRAP_CTLINPUT(ah4_ctlinput) 262 IPSEC_WRAP_CTLINPUT(esp4_ctlinput) 263 264 #else /* !IPSEC_RUMPKERNEL */ 265 266 PR_WRAP_CTLINPUT(ah4_ctlinput) 267 PR_WRAP_CTLINPUT(esp4_ctlinput) 268 269 #endif /* !IPSEC_RUMPKERNEL */ 270 271 #define ah4_ctlinput ah4_ctlinput_wrapper 272 #define esp4_ctlinput esp4_ctlinput_wrapper 273 274 #endif /* IPSEC */ 275 276 const struct protosw inetsw[] = { 277 { .pr_domain = &inetdomain, 278 .pr_init = ip_init, 279 .pr_fasttimo = ip_fasttimo, 280 .pr_slowtimo = ip_slowtimo, 281 .pr_drain = ip_drainstub, 282 }, 283 { .pr_type = SOCK_RAW, 284 .pr_domain = &inetdomain, 285 .pr_protocol = IPPROTO_ICMP, 286 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 287 .pr_input = icmp_input, 288 .pr_ctlinput = rip_ctlinput, 289 .pr_ctloutput = rip_ctloutput, 290 .pr_usrreqs = &rip_usrreqs, 291 .pr_init = icmp_init, 292 }, 293 { .pr_type = SOCK_DGRAM, 294 .pr_domain = &inetdomain, 295 .pr_protocol = IPPROTO_UDP, 296 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF, 297 .pr_input = udp_input, 298 .pr_ctlinput = udp_ctlinput, 299 .pr_ctloutput = udp_ctloutput, 300 .pr_usrreqs = &udp_usrreqs, 301 .pr_init = udp_init, 302 }, 303 { .pr_type = SOCK_STREAM, 304 .pr_domain = &inetdomain, 305 .pr_protocol = IPPROTO_TCP, 306 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS|PR_PURGEIF, 307 .pr_input = tcp_input, 308 .pr_ctlinput = tcp_ctlinput, 309 .pr_ctloutput = tcp_ctloutput, 310 .pr_usrreqs = &tcp_usrreqs, 311 .pr_init = tcp_init, 312 .pr_fasttimo = tcp_fasttimo, 313 .pr_drain = tcp_drainstub, 314 }, 315 #ifdef DCCP 316 { .pr_type = SOCK_CONN_DGRAM, 317 .pr_domain = &inetdomain, 318 .pr_protocol = IPPROTO_DCCP, 319 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC|PR_LISTEN|PR_ABRTACPTDIS, 320 .pr_input = dccp_input, 321 .pr_ctlinput = dccp_ctlinput, 322 .pr_ctloutput = dccp_ctloutput, 323 .pr_usrreqs = &dccp_usrreqs, 324 .pr_init = dccp_init, 325 }, 326 #endif 327 #ifdef SCTP 328 { .pr_type = SOCK_DGRAM, 329 .pr_domain = &inetdomain, 330 .pr_protocol = IPPROTO_SCTP, 331 .pr_flags = PR_ADDR_OPT|PR_WANTRCVD, 332 .pr_input = sctp_input, 333 .pr_ctlinput = sctp_ctlinput, 334 .pr_ctloutput = sctp_ctloutput, 335 .pr_usrreqs = &sctp_usrreqs, 336 .pr_init = sctp_init, 337 .pr_drain = sctp_drain 338 }, 339 { .pr_type = SOCK_SEQPACKET, 340 .pr_domain = &inetdomain, 341 .pr_protocol = IPPROTO_SCTP, 342 .pr_flags = PR_ADDR_OPT|PR_WANTRCVD, 343 .pr_input = sctp_input, 344 .pr_ctlinput = sctp_ctlinput, 345 .pr_ctloutput = sctp_ctloutput, 346 .pr_usrreqs = &sctp_usrreqs, 347 .pr_drain = sctp_drain 348 }, 349 { .pr_type = SOCK_STREAM, 350 .pr_domain = &inetdomain, 351 .pr_protocol = IPPROTO_SCTP, 352 .pr_flags = PR_CONNREQUIRED|PR_ADDR_OPT|PR_WANTRCVD|PR_LISTEN, 353 .pr_input = sctp_input, 354 .pr_ctlinput = sctp_ctlinput, 355 .pr_ctloutput = sctp_ctloutput, 356 .pr_usrreqs = &sctp_usrreqs, 357 .pr_drain = sctp_drain 358 }, 359 #endif /* SCTP */ 360 { .pr_type = SOCK_RAW, 361 .pr_domain = &inetdomain, 362 .pr_protocol = IPPROTO_RAW, 363 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF, 364 .pr_input = rip_input, 365 .pr_ctlinput = rip_ctlinput, 366 .pr_ctloutput = rip_ctloutput, 367 .pr_usrreqs = &rip_usrreqs, 368 }, 369 #ifdef GATEWAY 370 { .pr_domain = &inetdomain, 371 .pr_protocol = IPPROTO_IP, 372 .pr_slowtimo = ipflow_slowtimo, 373 .pr_init = ipflow_poolinit, 374 }, 375 #endif /* GATEWAY */ 376 #ifdef IPSEC 377 { .pr_type = SOCK_RAW, 378 .pr_domain = &inetdomain, 379 .pr_protocol = IPPROTO_AH, 380 .pr_flags = PR_ATOMIC|PR_ADDR, 381 .pr_input = ipsec4_common_input, 382 .pr_ctlinput = ah4_ctlinput, 383 }, 384 { .pr_type = SOCK_RAW, 385 .pr_domain = &inetdomain, 386 .pr_protocol = IPPROTO_ESP, 387 .pr_flags = PR_ATOMIC|PR_ADDR, 388 .pr_input = ipsec4_common_input, 389 .pr_ctlinput = esp4_ctlinput, 390 }, 391 { .pr_type = SOCK_RAW, 392 .pr_domain = &inetdomain, 393 .pr_protocol = IPPROTO_IPCOMP, 394 .pr_flags = PR_ATOMIC|PR_ADDR, 395 .pr_input = ipsec4_common_input, 396 }, 397 #endif /* IPSEC */ 398 { .pr_type = SOCK_RAW, 399 .pr_domain = &inetdomain, 400 .pr_protocol = IPPROTO_IPV4, 401 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 402 .pr_input = encap4_input, 403 .pr_ctlinput = rip_ctlinput, 404 .pr_ctloutput = rip_ctloutput, 405 .pr_usrreqs = &rip_usrreqs, 406 .pr_init = encap_init, 407 }, 408 #ifdef INET6 409 { .pr_type = SOCK_RAW, 410 .pr_domain = &inetdomain, 411 .pr_protocol = IPPROTO_IPV6, 412 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 413 .pr_input = encap4_input, 414 .pr_ctlinput = rip_ctlinput, 415 .pr_ctloutput = rip_ctloutput, 416 .pr_usrreqs = &rip_usrreqs, 417 .pr_init = encap_init, 418 }, 419 #endif /* INET6 */ 420 #if NETHERIP > 0 421 { .pr_type = SOCK_RAW, 422 .pr_domain = &inetdomain, 423 .pr_protocol = IPPROTO_ETHERIP, 424 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 425 .pr_input = ip_etherip_input, 426 .pr_ctlinput = rip_ctlinput, 427 .pr_ctloutput = rip_ctloutput, 428 .pr_usrreqs = &rip_usrreqs, 429 }, 430 #endif /* NETHERIP > 0 */ 431 #if NCARP > 0 432 { .pr_type = SOCK_RAW, 433 .pr_domain = &inetdomain, 434 .pr_protocol = IPPROTO_CARP, 435 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 436 .pr_input = carp_proto_input, 437 .pr_ctloutput = rip_ctloutput, 438 .pr_usrreqs = &rip_usrreqs, 439 .pr_init = carp_init, 440 }, 441 #endif /* NCARP > 0 */ 442 { .pr_type = SOCK_RAW, 443 .pr_domain = &inetdomain, 444 .pr_protocol = IPPROTO_L2TP, 445 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 446 .pr_input = encap4_input, 447 .pr_ctlinput = rip_ctlinput, 448 .pr_ctloutput = rip_ctloutput, 449 .pr_usrreqs = &rip_usrreqs, /*XXX*/ 450 .pr_init = encap_init, 451 }, 452 #if NPFSYNC > 0 453 { .pr_type = SOCK_RAW, 454 .pr_domain = &inetdomain, 455 .pr_protocol = IPPROTO_PFSYNC, 456 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 457 .pr_input = pfsync_input, 458 .pr_ctloutput = rip_ctloutput, 459 .pr_usrreqs = &rip_usrreqs, 460 }, 461 #endif /* NPFSYNC > 0 */ 462 { .pr_type = SOCK_RAW, 463 .pr_domain = &inetdomain, 464 .pr_protocol = IPPROTO_IGMP, 465 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 466 .pr_input = igmp_input, 467 .pr_ctloutput = rip_ctloutput, 468 .pr_ctlinput = rip_ctlinput, 469 .pr_usrreqs = &rip_usrreqs, 470 .pr_fasttimo = igmp_fasttimo, 471 .pr_slowtimo = igmp_slowtimo, 472 .pr_init = igmp_init, 473 }, 474 #ifdef PIM 475 { .pr_type = SOCK_RAW, 476 .pr_domain = &inetdomain, 477 .pr_protocol = IPPROTO_PIM, 478 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 479 .pr_input = pim_input, 480 .pr_ctloutput = rip_ctloutput, 481 .pr_ctlinput = rip_ctlinput, 482 .pr_usrreqs = &rip_usrreqs, 483 }, 484 #endif /* PIM */ 485 /* raw wildcard */ 486 { .pr_type = SOCK_RAW, 487 .pr_domain = &inetdomain, 488 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 489 .pr_input = rip_input, 490 .pr_ctloutput = rip_ctloutput, 491 .pr_ctlinput = rip_ctlinput, 492 .pr_usrreqs = &rip_usrreqs, 493 .pr_init = rip_init, 494 }, 495 }; 496 497 const struct sockaddr_in in_any = { 498 .sin_len = sizeof(struct sockaddr_in) 499 , .sin_family = AF_INET 500 , .sin_port = 0 501 , .sin_addr = {.s_addr = 0 /* INADDR_ANY */} 502 }; 503 504 struct domain inetdomain = { 505 .dom_family = PF_INET, .dom_name = "internet", .dom_init = NULL, 506 .dom_externalize = NULL, .dom_dispose = NULL, 507 .dom_protosw = inetsw, 508 .dom_protoswNPROTOSW = &inetsw[__arraycount(inetsw)], 509 .dom_rtattach = rt_inithead, 510 .dom_rtoffset = 32, 511 .dom_maxrtkey = sizeof(struct ip_pack4), 512 .dom_if_up = in_if_up, 513 .dom_if_down = in_if_down, 514 .dom_ifattach = in_domifattach, 515 .dom_ifdetach = in_domifdetach, 516 .dom_if_link_state_change = in_if_link_state_change, 517 .dom_ifqueues = { NULL, NULL }, 518 .dom_link = { NULL }, 519 .dom_mowner = MOWNER_INIT("",""), 520 .dom_sa_cmpofs = offsetof(struct sockaddr_in, sin_addr), 521 .dom_sa_cmplen = sizeof(struct in_addr), 522 .dom_sa_any = (const struct sockaddr *)&in_any, 523 .dom_sockaddr_const_addr = sockaddr_in_const_addr, 524 .dom_sockaddr_addr = sockaddr_in_addr, 525 }; 526 527 u_char ip_protox[IPPROTO_MAX]; 528 529 static void 530 sockaddr_in_addrlen(const struct sockaddr *sa, socklen_t *slenp) 531 { 532 socklen_t slen; 533 534 if (slenp == NULL) 535 return; 536 537 slen = sockaddr_getlen(sa); 538 *slenp = (socklen_t)MIN(sizeof(struct in_addr), 539 slen - MIN(slen, offsetof(struct sockaddr_in, sin_addr))); 540 } 541 542 const void * 543 sockaddr_in_const_addr(const struct sockaddr *sa, socklen_t *slenp) 544 { 545 const struct sockaddr_in *sin; 546 547 sockaddr_in_addrlen(sa, slenp); 548 sin = (const struct sockaddr_in *)sa; 549 return &sin->sin_addr; 550 } 551 552 void * 553 sockaddr_in_addr(struct sockaddr *sa, socklen_t *slenp) 554 { 555 struct sockaddr_in *sin; 556 557 sockaddr_in_addrlen(sa, slenp); 558 sin = (struct sockaddr_in *)sa; 559 return &sin->sin_addr; 560 } 561 562 int 563 sockaddr_in_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 564 { 565 uint_fast8_t len; 566 const uint_fast8_t addrofs = offsetof(struct sockaddr_in, sin_addr), 567 addrend = addrofs + sizeof(struct in_addr); 568 int rc; 569 const struct sockaddr_in *sin1, *sin2; 570 571 sin1 = satocsin(sa1); 572 sin2 = satocsin(sa2); 573 574 len = MIN(addrend, MIN(sin1->sin_len, sin2->sin_len)); 575 576 if (len > addrofs && 577 (rc = memcmp(&sin1->sin_addr, &sin2->sin_addr, 578 len - addrofs)) != 0) 579 return rc; 580 581 return sin1->sin_len - sin2->sin_len; 582 } 583