1 /* $NetBSD: in_proto.c,v 1.128 2018/05/03 07:13:48 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.128 2018/05/03 07:13:48 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/tcp_debug.h> 113 #include <netinet/udp.h> 114 #include <netinet/udp_var.h> 115 #include <netinet/ip_encap.h> 116 117 #ifdef DCCP 118 #include <netinet/dccp.h> 119 #include <netinet/dccp_var.h> 120 #endif 121 122 #ifdef SCTP 123 #include <netinet/sctp.h> 124 #include <netinet/sctp_var.h> 125 #endif 126 127 /* 128 * TCP/IP protocol family: IP, ICMP, UDP, TCP. 129 */ 130 131 #ifdef IPSEC 132 #include <netipsec/ipsec.h> 133 #include <netipsec/key.h> 134 #endif /* IPSEC */ 135 136 #include "carp.h" 137 #if NCARP > 0 138 #include <netinet/ip_carp.h> 139 #endif 140 141 #include "pfsync.h" 142 #if NPFSYNC > 0 143 #include <net/pfvar.h> 144 #include <net/if_pfsync.h> 145 #endif 146 147 #include "etherip.h" 148 #if NETHERIP > 0 149 #include <netinet/ip_etherip.h> 150 #endif 151 152 DOMAIN_DEFINE(inetdomain); /* forward declare and add to link set */ 153 154 /* Wrappers to acquire kernel_lock. */ 155 156 PR_WRAP_CTLINPUT(rip_ctlinput) 157 PR_WRAP_CTLINPUT(udp_ctlinput) 158 PR_WRAP_CTLINPUT(tcp_ctlinput) 159 160 #define rip_ctlinput rip_ctlinput_wrapper 161 #define udp_ctlinput udp_ctlinput_wrapper 162 #define tcp_ctlinput tcp_ctlinput_wrapper 163 164 PR_WRAP_CTLOUTPUT(rip_ctloutput) 165 PR_WRAP_CTLOUTPUT(udp_ctloutput) 166 PR_WRAP_CTLOUTPUT(tcp_ctloutput) 167 168 #define rip_ctloutput rip_ctloutput_wrapper 169 #define udp_ctloutput udp_ctloutput_wrapper 170 #define tcp_ctloutput tcp_ctloutput_wrapper 171 172 #ifdef DCCP 173 PR_WRAP_CTLINPUT(dccp_ctlinput) 174 PR_WRAP_CTLOUTPUT(dccp_ctloutput) 175 176 #define dccp_ctlinput dccp_ctlinput_wrapper 177 #define dccp_ctloutput dccp_ctloutput_wrapper 178 #endif 179 180 #ifdef SCTP 181 PR_WRAP_CTLINPUT(sctp_ctlinput) 182 PR_WRAP_CTLOUTPUT(sctp_ctloutput) 183 184 #define sctp_ctlinput sctp_ctlinput_wrapper 185 #define sctp_ctloutput sctp_ctloutput_wrapper 186 #endif 187 188 #ifdef NET_MPSAFE 189 PR_WRAP_INPUT(udp_input) 190 PR_WRAP_INPUT(tcp_input) 191 #ifdef DCCP 192 PR_WRAP_INPUT(dccp_input) 193 #endif 194 #ifdef SCTP 195 PR_WRAP_INPUT(sctp_input) 196 #endif 197 PR_WRAP_INPUT(rip_input) 198 #if NETHERIP > 0 199 PR_WRAP_INPUT(ip_etherip_input) 200 #endif 201 #if NPFSYNC > 0 202 PR_WRAP_INPUT(pfsync_input) 203 #endif 204 PR_WRAP_INPUT(igmp_input) 205 #ifdef PIM 206 PR_WRAP_INPUT(pim_input) 207 #endif 208 209 #define udp_input udp_input_wrapper 210 #define tcp_input tcp_input_wrapper 211 #define dccp_input dccp_input_wrapper 212 #define sctp_input sctp_input_wrapper 213 #define rip_input rip_input_wrapper 214 #define ip_etherip_input ip_etherip_input_wrapper 215 #define pfsync_input pfsync_input_wrapper 216 #define igmp_input igmp_input_wrapper 217 #define pim_input pim_input_wrapper 218 #endif 219 220 #if defined(IPSEC) 221 222 #ifdef IPSEC_RUMPKERNEL 223 /* 224 * .pr_input = ipsec4_common_input won't be resolved on loading 225 * the ipsec shared library. We need a wrapper anyway. 226 */ 227 static void 228 ipsec4_common_input_wrapper(struct mbuf *m, ...) 229 { 230 231 if (ipsec_enabled) { 232 int off, nxt; 233 va_list args; 234 /* XXX just passing args to ipsec4_common_input doesn't work */ 235 va_start(args, m); 236 off = va_arg(args, int); 237 nxt = va_arg(args, int); 238 va_end(args); 239 ipsec4_common_input(m, off, nxt); 240 } else { 241 m_freem(m); 242 } 243 } 244 #define ipsec4_common_input ipsec4_common_input_wrapper 245 246 /* The ctlinput functions may not be loaded */ 247 #define IPSEC_WRAP_CTLINPUT(name) \ 248 static void * \ 249 name##_wrapper(int a, const struct sockaddr *b, void *c)\ 250 { \ 251 void *rv; \ 252 KERNEL_LOCK(1, NULL); \ 253 if (ipsec_enabled) \ 254 rv = name(a, b, c); \ 255 else \ 256 rv = NULL; \ 257 KERNEL_UNLOCK_ONE(NULL); \ 258 return rv; \ 259 } 260 IPSEC_WRAP_CTLINPUT(ah4_ctlinput) 261 IPSEC_WRAP_CTLINPUT(esp4_ctlinput) 262 263 #else /* !IPSEC_RUMPKERNEL */ 264 265 PR_WRAP_CTLINPUT(ah4_ctlinput) 266 PR_WRAP_CTLINPUT(esp4_ctlinput) 267 268 #endif /* !IPSEC_RUMPKERNEL */ 269 270 #define ah4_ctlinput ah4_ctlinput_wrapper 271 #define esp4_ctlinput esp4_ctlinput_wrapper 272 273 #endif /* IPSEC */ 274 275 const struct protosw inetsw[] = { 276 { .pr_domain = &inetdomain, 277 .pr_init = ip_init, 278 .pr_fasttimo = ip_fasttimo, 279 .pr_slowtimo = ip_slowtimo, 280 .pr_drain = ip_drainstub, 281 }, 282 { .pr_type = SOCK_RAW, 283 .pr_domain = &inetdomain, 284 .pr_protocol = IPPROTO_ICMP, 285 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 286 .pr_input = icmp_input, 287 .pr_ctlinput = rip_ctlinput, 288 .pr_ctloutput = rip_ctloutput, 289 .pr_usrreqs = &rip_usrreqs, 290 .pr_init = icmp_init, 291 }, 292 { .pr_type = SOCK_DGRAM, 293 .pr_domain = &inetdomain, 294 .pr_protocol = IPPROTO_UDP, 295 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF, 296 .pr_input = udp_input, 297 .pr_ctlinput = udp_ctlinput, 298 .pr_ctloutput = udp_ctloutput, 299 .pr_usrreqs = &udp_usrreqs, 300 .pr_init = udp_init, 301 }, 302 { .pr_type = SOCK_STREAM, 303 .pr_domain = &inetdomain, 304 .pr_protocol = IPPROTO_TCP, 305 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_LISTEN|PR_ABRTACPTDIS|PR_PURGEIF, 306 .pr_input = tcp_input, 307 .pr_ctlinput = tcp_ctlinput, 308 .pr_ctloutput = tcp_ctloutput, 309 .pr_usrreqs = &tcp_usrreqs, 310 .pr_init = tcp_init, 311 .pr_fasttimo = tcp_fasttimo, 312 .pr_drain = tcp_drainstub, 313 }, 314 #ifdef DCCP 315 { .pr_type = SOCK_CONN_DGRAM, 316 .pr_domain = &inetdomain, 317 .pr_protocol = IPPROTO_DCCP, 318 .pr_flags = PR_CONNREQUIRED|PR_WANTRCVD|PR_ATOMIC|PR_LISTEN|PR_ABRTACPTDIS, 319 .pr_input = dccp_input, 320 .pr_ctlinput = dccp_ctlinput, 321 .pr_ctloutput = dccp_ctloutput, 322 .pr_usrreqs = &dccp_usrreqs, 323 .pr_init = dccp_init, 324 }, 325 #endif 326 #ifdef SCTP 327 { .pr_type = SOCK_DGRAM, 328 .pr_domain = &inetdomain, 329 .pr_protocol = IPPROTO_SCTP, 330 .pr_flags = PR_ADDR_OPT|PR_WANTRCVD, 331 .pr_input = sctp_input, 332 .pr_ctlinput = sctp_ctlinput, 333 .pr_ctloutput = sctp_ctloutput, 334 .pr_usrreqs = &sctp_usrreqs, 335 .pr_init = sctp_init, 336 .pr_drain = sctp_drain 337 }, 338 { .pr_type = SOCK_SEQPACKET, 339 .pr_domain = &inetdomain, 340 .pr_protocol = IPPROTO_SCTP, 341 .pr_flags = PR_ADDR_OPT|PR_WANTRCVD, 342 .pr_input = sctp_input, 343 .pr_ctlinput = sctp_ctlinput, 344 .pr_ctloutput = sctp_ctloutput, 345 .pr_usrreqs = &sctp_usrreqs, 346 .pr_drain = sctp_drain 347 }, 348 { .pr_type = SOCK_STREAM, 349 .pr_domain = &inetdomain, 350 .pr_protocol = IPPROTO_SCTP, 351 .pr_flags = PR_CONNREQUIRED|PR_ADDR_OPT|PR_WANTRCVD|PR_LISTEN, 352 .pr_input = sctp_input, 353 .pr_ctlinput = sctp_ctlinput, 354 .pr_ctloutput = sctp_ctloutput, 355 .pr_usrreqs = &sctp_usrreqs, 356 .pr_drain = sctp_drain 357 }, 358 #endif /* SCTP */ 359 { .pr_type = SOCK_RAW, 360 .pr_domain = &inetdomain, 361 .pr_protocol = IPPROTO_RAW, 362 .pr_flags = PR_ATOMIC|PR_ADDR|PR_PURGEIF, 363 .pr_input = rip_input, 364 .pr_ctlinput = rip_ctlinput, 365 .pr_ctloutput = rip_ctloutput, 366 .pr_usrreqs = &rip_usrreqs, 367 }, 368 #ifdef GATEWAY 369 { .pr_domain = &inetdomain, 370 .pr_protocol = IPPROTO_IP, 371 .pr_slowtimo = ipflow_slowtimo, 372 .pr_init = ipflow_poolinit, 373 }, 374 #endif /* GATEWAY */ 375 #ifdef IPSEC 376 { .pr_type = SOCK_RAW, 377 .pr_domain = &inetdomain, 378 .pr_protocol = IPPROTO_AH, 379 .pr_flags = PR_ATOMIC|PR_ADDR, 380 .pr_input = ipsec4_common_input, 381 .pr_ctlinput = ah4_ctlinput, 382 }, 383 { .pr_type = SOCK_RAW, 384 .pr_domain = &inetdomain, 385 .pr_protocol = IPPROTO_ESP, 386 .pr_flags = PR_ATOMIC|PR_ADDR, 387 .pr_input = ipsec4_common_input, 388 .pr_ctlinput = esp4_ctlinput, 389 }, 390 { .pr_type = SOCK_RAW, 391 .pr_domain = &inetdomain, 392 .pr_protocol = IPPROTO_IPCOMP, 393 .pr_flags = PR_ATOMIC|PR_ADDR, 394 .pr_input = ipsec4_common_input, 395 }, 396 #endif /* IPSEC */ 397 { .pr_type = SOCK_RAW, 398 .pr_domain = &inetdomain, 399 .pr_protocol = IPPROTO_IPV4, 400 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 401 .pr_input = encap4_input, 402 .pr_ctlinput = rip_ctlinput, 403 .pr_ctloutput = rip_ctloutput, 404 .pr_usrreqs = &rip_usrreqs, 405 .pr_init = encap_init, 406 }, 407 #ifdef INET6 408 { .pr_type = SOCK_RAW, 409 .pr_domain = &inetdomain, 410 .pr_protocol = IPPROTO_IPV6, 411 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 412 .pr_input = encap4_input, 413 .pr_ctlinput = rip_ctlinput, 414 .pr_ctloutput = rip_ctloutput, 415 .pr_usrreqs = &rip_usrreqs, 416 .pr_init = encap_init, 417 }, 418 #endif /* INET6 */ 419 #if NETHERIP > 0 420 { .pr_type = SOCK_RAW, 421 .pr_domain = &inetdomain, 422 .pr_protocol = IPPROTO_ETHERIP, 423 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 424 .pr_input = ip_etherip_input, 425 .pr_ctlinput = rip_ctlinput, 426 .pr_ctloutput = rip_ctloutput, 427 .pr_usrreqs = &rip_usrreqs, 428 }, 429 #endif /* NETHERIP > 0 */ 430 #if NCARP > 0 431 { .pr_type = SOCK_RAW, 432 .pr_domain = &inetdomain, 433 .pr_protocol = IPPROTO_CARP, 434 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 435 .pr_input = carp_proto_input, 436 .pr_ctloutput = rip_ctloutput, 437 .pr_usrreqs = &rip_usrreqs, 438 .pr_init = carp_init, 439 }, 440 #endif /* NCARP > 0 */ 441 { .pr_type = SOCK_RAW, 442 .pr_domain = &inetdomain, 443 .pr_protocol = IPPROTO_L2TP, 444 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 445 .pr_input = encap4_input, 446 .pr_ctlinput = rip_ctlinput, 447 .pr_ctloutput = rip_ctloutput, 448 .pr_usrreqs = &rip_usrreqs, /*XXX*/ 449 .pr_init = encap_init, 450 }, 451 #if NPFSYNC > 0 452 { .pr_type = SOCK_RAW, 453 .pr_domain = &inetdomain, 454 .pr_protocol = IPPROTO_PFSYNC, 455 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 456 .pr_input = pfsync_input, 457 .pr_ctloutput = rip_ctloutput, 458 .pr_usrreqs = &rip_usrreqs, 459 }, 460 #endif /* NPFSYNC > 0 */ 461 { .pr_type = SOCK_RAW, 462 .pr_domain = &inetdomain, 463 .pr_protocol = IPPROTO_IGMP, 464 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 465 .pr_input = igmp_input, 466 .pr_ctloutput = rip_ctloutput, 467 .pr_ctlinput = rip_ctlinput, 468 .pr_usrreqs = &rip_usrreqs, 469 .pr_fasttimo = igmp_fasttimo, 470 .pr_slowtimo = igmp_slowtimo, 471 .pr_init = igmp_init, 472 }, 473 #ifdef PIM 474 { .pr_type = SOCK_RAW, 475 .pr_domain = &inetdomain, 476 .pr_protocol = IPPROTO_PIM, 477 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 478 .pr_input = pim_input, 479 .pr_ctloutput = rip_ctloutput, 480 .pr_ctlinput = rip_ctlinput, 481 .pr_usrreqs = &rip_usrreqs, 482 }, 483 #endif /* PIM */ 484 /* raw wildcard */ 485 { .pr_type = SOCK_RAW, 486 .pr_domain = &inetdomain, 487 .pr_flags = PR_ATOMIC|PR_ADDR|PR_LASTHDR, 488 .pr_input = rip_input, 489 .pr_ctloutput = rip_ctloutput, 490 .pr_ctlinput = rip_ctlinput, 491 .pr_usrreqs = &rip_usrreqs, 492 .pr_init = rip_init, 493 }, 494 }; 495 496 const struct sockaddr_in in_any = { 497 .sin_len = sizeof(struct sockaddr_in) 498 , .sin_family = AF_INET 499 , .sin_port = 0 500 , .sin_addr = {.s_addr = 0 /* INADDR_ANY */} 501 }; 502 503 struct domain inetdomain = { 504 .dom_family = PF_INET, .dom_name = "internet", .dom_init = NULL, 505 .dom_externalize = NULL, .dom_dispose = NULL, 506 .dom_protosw = inetsw, 507 .dom_protoswNPROTOSW = &inetsw[__arraycount(inetsw)], 508 .dom_rtattach = rt_inithead, 509 .dom_rtoffset = 32, 510 .dom_maxrtkey = sizeof(struct ip_pack4), 511 .dom_if_up = in_if_up, 512 .dom_if_down = in_if_down, 513 .dom_ifattach = in_domifattach, 514 .dom_ifdetach = in_domifdetach, 515 .dom_if_link_state_change = in_if_link_state_change, 516 .dom_ifqueues = { NULL, NULL }, 517 .dom_link = { NULL }, 518 .dom_mowner = MOWNER_INIT("",""), 519 .dom_sa_cmpofs = offsetof(struct sockaddr_in, sin_addr), 520 .dom_sa_cmplen = sizeof(struct in_addr), 521 .dom_sa_any = (const struct sockaddr *)&in_any, 522 .dom_sockaddr_const_addr = sockaddr_in_const_addr, 523 .dom_sockaddr_addr = sockaddr_in_addr, 524 }; 525 526 u_char ip_protox[IPPROTO_MAX]; 527 528 static void 529 sockaddr_in_addrlen(const struct sockaddr *sa, socklen_t *slenp) 530 { 531 socklen_t slen; 532 533 if (slenp == NULL) 534 return; 535 536 slen = sockaddr_getlen(sa); 537 *slenp = (socklen_t)MIN(sizeof(struct in_addr), 538 slen - MIN(slen, offsetof(struct sockaddr_in, sin_addr))); 539 } 540 541 const void * 542 sockaddr_in_const_addr(const struct sockaddr *sa, socklen_t *slenp) 543 { 544 const struct sockaddr_in *sin; 545 546 sockaddr_in_addrlen(sa, slenp); 547 sin = (const struct sockaddr_in *)sa; 548 return &sin->sin_addr; 549 } 550 551 void * 552 sockaddr_in_addr(struct sockaddr *sa, socklen_t *slenp) 553 { 554 struct sockaddr_in *sin; 555 556 sockaddr_in_addrlen(sa, slenp); 557 sin = (struct sockaddr_in *)sa; 558 return &sin->sin_addr; 559 } 560 561 int 562 sockaddr_in_cmp(const struct sockaddr *sa1, const struct sockaddr *sa2) 563 { 564 uint_fast8_t len; 565 const uint_fast8_t addrofs = offsetof(struct sockaddr_in, sin_addr), 566 addrend = addrofs + sizeof(struct in_addr); 567 int rc; 568 const struct sockaddr_in *sin1, *sin2; 569 570 sin1 = satocsin(sa1); 571 sin2 = satocsin(sa2); 572 573 len = MIN(addrend, MIN(sin1->sin_len, sin2->sin_len)); 574 575 if (len > addrofs && 576 (rc = memcmp(&sin1->sin_addr, &sin2->sin_addr, 577 len - addrofs)) != 0) 578 return rc; 579 580 return sin1->sin_len - sin2->sin_len; 581 } 582