1/* $KAME: dccp6_usrreq.c,v 1.13 2005/07/27 08:42:56 nishida Exp $ */ 2/* $NetBSD: dccp6_usrreq.c,v 1.15 2022/11/04 09:01:53 ozaki-r Exp $ */ 3 4/* 5 * Copyright (C) 2003 WIDE Project. 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. Neither the name of the project nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 */ 32 33#include <sys/cdefs.h> 34__KERNEL_RCSID(0, "$NetBSD: dccp6_usrreq.c,v 1.15 2022/11/04 09:01:53 ozaki-r Exp $"); 35 36#ifdef _KERNEL_OPT 37#include "opt_inet.h" 38#include "opt_dccp.h" 39#include "opt_net_mpsafe.h" 40#endif 41 42#include <sys/param.h> 43#include <sys/systm.h> 44#include <sys/domain.h> 45#include <sys/kernel.h> 46#include <sys/pool.h> 47#include <sys/lock.h> 48#include <sys/malloc.h> 49#include <sys/mbuf.h> 50#include <sys/proc.h> 51#include <sys/protosw.h> 52#include <sys/signalvar.h> 53#include <sys/socket.h> 54#include <sys/socketvar.h> 55#include <sys/mutex.h> 56#include <sys/sysctl.h> 57#include <sys/syslog.h> 58#include <sys/queue.h> 59 60#include <net/if.h> 61 62#include <netinet/in.h> 63#include <netinet/in_systm.h> 64#include <netinet/ip.h> 65#include <netinet/in_pcb.h> 66#include <netinet/in_var.h> 67#include <netinet/ip6.h> 68#include <netinet/ip_icmp.h> 69#include <netinet/icmp_var.h> 70#include <netinet/ip_var.h> 71#include <netinet6/in6_pcb.h> 72#include <netinet6/ip6_var.h> 73#include <netinet/dccp.h> 74#include <netinet/dccp_var.h> 75#include <netinet6/dccp6_var.h> 76#include <netinet/dccp_cc_sw.h> 77 78#if !defined(__FreeBSD__) || __FreeBSD_version < 500000 79#define INP_INFO_LOCK_INIT(x,y) 80#define INP_INFO_WLOCK(x) 81#define INP_INFO_WUNLOCK(x) 82#define INP_INFO_RLOCK(x) 83#define INP_INFO_RUNLOCK(x) 84#define INP_LOCK(x) 85#define INP_UNLOCK(x) 86#endif 87 88#define PULLDOWN_TEST 89 90int 91dccp6_input(struct mbuf **mp, int *offp, int proto) 92{ 93 struct mbuf *m = *mp; 94 DCCP_DEBUG((LOG_INFO, "In dccp6_input!\n")); 95#ifndef PULLDOWN_TEST 96 IP6_EXTHDR_CHECK(m, *offp, sizeof(struct dccphdr), IPPROTO_DONE); 97#endif 98 99 dccp_input(m, *offp, proto); 100 return IPPROTO_DONE; 101} 102 103void * 104dccp6_ctlinput(int cmd, const struct sockaddr *sa, void *d) 105{ 106 if (sa->sa_family != AF_INET6 || 107 sa->sa_len != sizeof(struct sockaddr_in6)) 108 return NULL; 109 110 /* FIX LATER */ 111 return NULL; 112} 113 114int 115dccp6_bind(struct socket *so, struct sockaddr *nam, struct lwp *td) 116{ 117 struct inpcb *inp; 118 int error; 119 struct sockaddr_in6 *sinp = (struct sockaddr_in6 *)nam; 120 121 DCCP_DEBUG((LOG_INFO, "Entering dccp6_bind!\n")); 122 INP_INFO_WLOCK(&dccpbinfo); 123 inp = sotoinpcb(so); 124 if (inp == 0) { 125 INP_INFO_WUNLOCK(&dccpbinfo); 126 DCCP_DEBUG((LOG_INFO, "dccp6_bind: inp == 0!\n")); 127 return EINVAL; 128 } 129 /* Do not bind to multicast addresses! */ 130 if (sinp->sin6_family == AF_INET6 && 131 IN6_IS_ADDR_MULTICAST(&sinp->sin6_addr)) { 132 INP_INFO_WUNLOCK(&dccpbinfo); 133 return EAFNOSUPPORT; 134 } 135 INP_LOCK(inp); 136 137 intodccpcb(inp)->inp_vflag &= ~INP_IPV4; 138 intodccpcb(inp)->inp_vflag |= INP_IPV6; 139 140 error = in6pcb_bind(inp, sinp, td); 141 INP_UNLOCK(inp); 142 INP_INFO_WUNLOCK(&dccpbinfo); 143 return error; 144} 145 146int 147dccp6_connect(struct socket *so, struct sockaddr *nam, struct lwp *l) 148{ 149 struct inpcb *inp; 150 struct dccpcb *dp; 151 int error; 152 struct sockaddr_in6 *sin6; 153 char test[2]; 154 155 DCCP_DEBUG((LOG_INFO, "Entering dccp6_connect!\n")); 156 157#ifndef __NetBSD__ 158 INP_INFO_WLOCK(&dccpbinfo); 159 inp = sotoinpcb(so); 160 if (inp == 0) { 161 INP_INFO_WUNLOCK(&dccpbinfo); 162 return EINVAL; 163 } 164 INP_LOCK(inp); 165 if (in6p_faddr(inp).s_addr != INADDR_ANY) { 166 INP_UNLOCK(inp); 167 INP_INFO_WUNLOCK(&dccpbinfo); 168 return EISCONN; 169 } 170 171 dp = (struct dccpcb *)inp->inp_ppcb; 172#else 173 inp = sotoinpcb(so); 174 if (inp == 0) { 175 return EINVAL; 176 } 177 if (!IN6_IS_ADDR_UNSPECIFIED(&in6p_faddr(inp))) { 178 return EISCONN; 179 } 180 181 dp = (struct dccpcb *)inp->inp_ppcb; 182#endif 183 if (dp->state == DCCPS_ESTAB) { 184 DCCP_DEBUG((LOG_INFO, "Why are we in connect when we already have a established connection?\n")); 185 } 186 187 dp->who = DCCP_CLIENT; 188 dp->seq_snd = (((u_int64_t)random() << 32) | random()) % 281474976710656LL; 189 190 sin6 = (struct sockaddr_in6 *)nam; 191 if (sin6->sin6_family == AF_INET6 192 && IN6_IS_ADDR_MULTICAST(&sin6->sin6_addr)) { 193 error = EAFNOSUPPORT; 194 goto bad; 195 } 196 197 dp->inp_vflag &= ~INP_IPV4; 198 dp->inp_vflag |= INP_IPV6; 199 200 error = dccp_doconnect(so, nam, l, 1); 201 202 if (error != 0) 203 goto bad; 204 205 callout_reset(&dp->retrans_timer, dp->retrans, dccp_retrans_t, dp); 206 callout_reset(&dp->connect_timer, DCCP_CONNECT_TIMER, dccp_connect_t, dp); 207 208 test[0] = dp->pref_cc; 209#if 0 210 /* FIX THIS LATER */ 211 if (dp->pref_cc == 2) { 212 test[1] = 3; 213 } else { 214 test[1] = 2; 215 } 216 dccp_add_feature(dp, DCCP_OPT_CHANGE, DCCP_FEATURE_CC, test, 2); 217 dccp_add_feature(dp, DCCP_OPT_PREFER, DCCP_FEATURE_CC, test, 2); 218#else 219 /* we only support CCID2 at this moment */ 220 dccp_add_feature(dp, DCCP_OPT_CHANGE_R, DCCP_FEATURE_CC, test, 1); 221#endif 222 223 error = dccp_output(dp, 0); 224 225bad: 226 INP_UNLOCK(inp); 227 INP_INFO_WUNLOCK(&dccpbinfo); 228 return error; 229} 230 231 232int 233dccp6_listen(struct socket *so, struct lwp *l) 234{ 235 struct inpcb *inp; 236 struct dccpcb *dp; 237 int error = 0; 238 239 DCCP_DEBUG((LOG_INFO, "Entering dccp6_listen!\n")); 240 241 INP_INFO_RLOCK(&dccpbinfo); 242 inp = sotoinpcb(so); 243 if (inp == 0) { 244 INP_INFO_RUNLOCK(&dccpbinfo); 245 return EINVAL; 246 } 247 INP_LOCK(inp); 248 INP_INFO_RUNLOCK(&dccpbinfo); 249 dp = intodccpcb(inp); 250 DCCP_DEBUG((LOG_INFO, "Checking inp->inp_lport!\n")); 251 if (inp->inp_lport == 0) { 252 error = in6pcb_bind(inp, NULL, l); 253 } 254 if (error == 0) { 255 dp->state = DCCPS_LISTEN; 256 dp->who = DCCP_LISTENER; 257 dp->seq_snd = 512; 258 } 259 INP_UNLOCK(inp); 260 return error; 261} 262 263int 264dccp6_accept(struct socket *so, struct sockaddr *nam) 265{ 266 struct inpcb *inp = NULL; 267 int error = 0; 268 269 DCCP_DEBUG((LOG_INFO, "Entering dccp6_accept!\n")); 270 if (nam == NULL) { 271 return EINVAL; 272 } 273 if (so->so_state & SS_ISDISCONNECTED) { 274 DCCP_DEBUG((LOG_INFO, "so_state && SS_ISDISCONNECTED!, so->state = %i\n", so->so_state)); 275 return ECONNABORTED; 276 } 277 278 INP_INFO_RLOCK(&dccpbinfo); 279 inp = sotoinpcb(so); 280 if (inp == 0) { 281 INP_INFO_RUNLOCK(&dccpbinfo); 282 return EINVAL; 283 } 284 INP_LOCK(inp); 285 INP_INFO_RUNLOCK(&dccpbinfo); 286 in6pcb_fetch_peeraddr(inp, (struct sockaddr_in6 *)nam); 287 288 INP_UNLOCK(inp); 289 return error; 290} 291 292static int 293dccp6_ioctl(struct socket *so, u_long cmd, void *nam, struct ifnet *ifp) 294{ 295 int error = 0; 296 int family; 297 298 family = so->so_proto->pr_domain->dom_family; 299 switch (family) { 300 case PF_INET6: 301 error = in6_control(so, cmd, nam, ifp); 302 break; 303 default: 304 error = EAFNOSUPPORT; 305 } 306 return (error); 307} 308 309static int 310dccp6_stat(struct socket *so, struct stat *ub) 311{ 312 return 0; 313} 314 315static int 316dccp6_purgeif(struct socket *so, struct ifnet *ifp) 317{ 318 int s; 319 320 s = splsoftnet(); 321 mutex_enter(softnet_lock); 322 in6pcb_purgeif0(&dccpbtable, ifp); 323#ifdef NET_MPSAFE 324 mutex_exit(softnet_lock); 325#endif 326 in6_purgeif(ifp); 327#ifdef NET_MPSAFE 328 mutex_enter(softnet_lock); 329#endif 330 in6pcb_purgeif(&dccpbtable, ifp); 331 mutex_exit(softnet_lock); 332 splx(s); 333 334 return 0; 335} 336 337static int 338dccp6_attach(struct socket *so, int proto) 339{ 340 return dccp_attach(so, proto); 341} 342 343static int 344dccp6_detach(struct socket *so) 345{ 346 return dccp_detach(so); 347} 348 349static int 350dccp6_connect2(struct socket *so, struct socket *so2) 351{ 352 KASSERT(solocked(so)); 353 354 return EOPNOTSUPP; 355} 356 357static int 358dccp6_disconnect(struct socket *so) 359{ 360 return dccp_disconnect(so); 361} 362 363static int 364dccp6_shutdown(struct socket *so) 365{ 366 return dccp_shutdown(so); 367} 368 369static int 370dccp6_abort(struct socket *so) 371{ 372 return dccp_abort(so); 373} 374 375 376static int 377dccp6_peeraddr(struct socket *so, struct sockaddr *nam) 378{ 379 KASSERT(solocked(so)); 380 KASSERT(sotoinpcb(so) != NULL); 381 KASSERT(nam != NULL); 382 383 in6pcb_fetch_peeraddr(sotoinpcb(so), (struct sockaddr_in6 *)nam); 384 return 0; 385} 386 387static int 388dccp6_sockaddr(struct socket *so, struct sockaddr *nam) 389{ 390 KASSERT(solocked(so)); 391 KASSERT(sotoinpcb(so) != NULL); 392 KASSERT(nam != NULL); 393 394 in6pcb_fetch_sockaddr(sotoinpcb(so), (struct sockaddr_in6 *)nam); 395 return 0; 396} 397 398static int 399dccp6_recvoob(struct socket *so, struct mbuf *m, int flags) 400{ 401 KASSERT(solocked(so)); 402 403 return EOPNOTSUPP; 404} 405 406static int 407dccp6_rcvd(struct socket *so, int flags, struct lwp *l) 408{ 409 KASSERT(solocked(so)); 410 411 return EOPNOTSUPP; 412} 413 414static int 415dccp6_send(struct socket *so, struct mbuf *m, struct sockaddr *nam, 416 struct mbuf *control, struct lwp *l) 417{ 418 return dccp_send(so, m, nam, control, l); 419} 420 421static int 422dccp6_sendoob(struct socket *so, struct mbuf *m, struct mbuf *control) 423{ 424 KASSERT(solocked(so)); 425 426 m_freem(m); 427 m_freem(control); 428 429 return EOPNOTSUPP; 430} 431 432 433PR_WRAP_USRREQS(dccp6) 434#define dccp6_attach dccp6_attach_wrapper 435#define dccp6_detach dccp6_detach_wrapper 436#define dccp6_accept dccp6_accept_wrapper 437#define dccp6_bind dccp6_bind_wrapper 438#define dccp6_listen dccp6_listen_wrapper 439#define dccp6_connect dccp6_connect_wrapper 440#define dccp6_connect2 dccp6_connect2_wrapper 441#define dccp6_disconnect dccp6_disconnect_wrapper 442#define dccp6_shutdown dccp6_shutdown_wrapper 443#define dccp6_abort dccp6_abort_wrapper 444#define dccp6_ioctl dccp6_ioctl_wrapper 445#define dccp6_stat dccp6_stat_wrapper 446#define dccp6_peeraddr dccp6_peeraddr_wrapper 447#define dccp6_sockaddr dccp6_sockaddr_wrapper 448#define dccp6_rcvd dccp6_rcvd_wrapper 449#define dccp6_recvoob dccp6_recvoob_wrapper 450#define dccp6_send dccp6_send_wrapper 451#define dccp6_sendoob dccp6_sendoob_wrapper 452#define dccp6_purgeif dccp6_purgeif_wrapper 453 454const struct pr_usrreqs dccp6_usrreqs = { 455 .pr_attach = dccp6_attach, 456 .pr_detach = dccp6_detach, 457 .pr_accept = dccp6_accept, 458 .pr_bind = dccp6_bind, 459 .pr_listen = dccp6_listen, 460 .pr_connect = dccp6_connect, 461 .pr_connect2 = dccp6_connect2, 462 .pr_disconnect = dccp6_disconnect, 463 .pr_shutdown = dccp6_shutdown, 464 .pr_abort = dccp6_abort, 465 .pr_ioctl = dccp6_ioctl, 466 .pr_stat = dccp6_stat, 467 .pr_peeraddr = dccp6_peeraddr, 468 .pr_sockaddr = dccp6_sockaddr, 469 .pr_rcvd = dccp6_rcvd, 470 .pr_recvoob = dccp6_recvoob, 471 .pr_send = dccp6_send, 472 .pr_sendoob = dccp6_sendoob, 473 .pr_purgeif = dccp6_purgeif, 474}; 475