netwerk/sctp/src/user_socket.c

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rwxr-xr-x

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

michael@0 1 /*-
michael@0 2 * Copyright (c) 1982, 1986, 1988, 1990, 1993
michael@0 3 * The Regents of the University of California.
michael@0 4 * Copyright (c) 2004 The FreeBSD Foundation
michael@0 5 * Copyright (c) 2004-2008 Robert N. M. Watson
michael@0 6 * Copyright (c) 2009-2010 Brad Penoff
michael@0 7 * Copyright (c) 2009-2010 Humaira Kamal
michael@0 8 * Copyright (c) 2011-2012 Irene Ruengeler
michael@0 9 * Copyright (c) 2011-2012 Michael Tuexen
michael@0 10 * All rights reserved.
michael@0 11 *
michael@0 12 * Redistribution and use in source and binary forms, with or without
michael@0 13 * modification, are permitted provided that the following conditions
michael@0 14 * are met:
michael@0 15 * 1. Redistributions of source code must retain the above copyright
michael@0 16 * notice, this list of conditions and the following disclaimer.
michael@0 17 * 2. Redistributions in binary form must reproduce the above copyright
michael@0 18 * notice, this list of conditions and the following disclaimer in the
michael@0 19 * documentation and/or other materials provided with the distribution.
michael@0 20 *
michael@0 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
michael@0 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
michael@0 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
michael@0 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
michael@0 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
michael@0 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
michael@0 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
michael@0 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
michael@0 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
michael@0 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
michael@0 31 * SUCH DAMAGE.
michael@0 32 *
michael@0 33 */
michael@0 34
michael@0 35 #include <netinet/sctp_os.h>
michael@0 36 #include <netinet/sctp_pcb.h>
michael@0 37 #include <netinet/sctputil.h>
michael@0 38 #include <netinet/sctp_var.h>
michael@0 39 #include <netinet/sctp_sysctl.h>
michael@0 40 #include <netinet/sctp_input.h>
michael@0 41 #include <netinet/sctp_peeloff.h>
michael@0 42 #ifdef INET6
michael@0 43 #include <netinet6/sctp6_var.h>
michael@0 44 #endif
michael@0 45 #if defined(__Userspace_os_Linux)
michael@0 46 #define __FAVOR_BSD /* (on Ubuntu at least) enables UDP header field names like BSD in RFC 768 */
michael@0 47 #endif
michael@0 48 #if !defined (__Userspace_os_Windows)
michael@0 49 #include <netinet/udp.h>
michael@0 50 #include <arpa/inet.h>
michael@0 51 #else
michael@0 52 #include <user_socketvar.h>
michael@0 53 #endif
michael@0 54 userland_mutex_t accept_mtx;
michael@0 55 userland_cond_t accept_cond;
michael@0 56 #ifdef _WIN32
michael@0 57 #include <time.h>
michael@0 58 #include <sys/timeb.h>
michael@0 59 #endif
michael@0 60
michael@0 61 MALLOC_DEFINE(M_PCB, "sctp_pcb", "sctp pcb");
michael@0 62 MALLOC_DEFINE(M_SONAME, "sctp_soname", "sctp soname");
michael@0 63 #define MAXLEN_MBUF_CHAIN 32
michael@0 64
michael@0 65 /* Prototypes */
michael@0 66 extern int sctp_sosend(struct socket *so, struct sockaddr *addr, struct uio *uio,
michael@0 67 struct mbuf *top, struct mbuf *control, int flags,
michael@0 68 /* proc is a dummy in __Userspace__ and will not be passed to sctp_lower_sosend */ struct proc *p);
michael@0 69
michael@0 70 extern int sctp_attach(struct socket *so, int proto, uint32_t vrf_id);
michael@0 71 extern int sctpconn_attach(struct socket *so, int proto, uint32_t vrf_id);
michael@0 72
michael@0 73 void
michael@0 74 usrsctp_init(uint16_t port,
michael@0 75 int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df),
michael@0 76 void (*debug_printf)(const char *format, ...))
michael@0 77 {
michael@0 78 sctp_init(port, conn_output, debug_printf);
michael@0 79 }
michael@0 80
michael@0 81
michael@0 82 /* Taken from usr/src/sys/kern/uipc_sockbuf.c and modified for __Userspace__*/
michael@0 83 /*
michael@0 84 * Socantsendmore indicates that no more data will be sent on the socket; it
michael@0 85 * would normally be applied to a socket when the user informs the system
michael@0 86 * that no more data is to be sent, by the protocol code (in case
michael@0 87 * PRU_SHUTDOWN). Socantrcvmore indicates that no more data will be
michael@0 88 * received, and will normally be applied to the socket by a protocol when it
michael@0 89 * detects that the peer will send no more data. Data queued for reading in
michael@0 90 * the socket may yet be read.
michael@0 91 */
michael@0 92
michael@0 93 void socantrcvmore_locked(struct socket *so)
michael@0 94 {
michael@0 95 SOCKBUF_LOCK_ASSERT(&so->so_rcv);
michael@0 96 so->so_rcv.sb_state |= SBS_CANTRCVMORE;
michael@0 97 sorwakeup_locked(so);
michael@0 98 }
michael@0 99
michael@0 100 void socantrcvmore(struct socket *so)
michael@0 101 {
michael@0 102 SOCKBUF_LOCK(&so->so_rcv);
michael@0 103 socantrcvmore_locked(so);
michael@0 104 }
michael@0 105
michael@0 106 void
michael@0 107 socantsendmore_locked(struct socket *so)
michael@0 108 {
michael@0 109 SOCKBUF_LOCK_ASSERT(&so->so_snd);
michael@0 110 so->so_snd.sb_state |= SBS_CANTSENDMORE;
michael@0 111 sowwakeup_locked(so);
michael@0 112 }
michael@0 113
michael@0 114 void
michael@0 115 socantsendmore(struct socket *so)
michael@0 116 {
michael@0 117 SOCKBUF_LOCK(&so->so_snd);
michael@0 118 socantsendmore_locked(so);
michael@0 119 }
michael@0 120
michael@0 121
michael@0 122
michael@0 123 /* Taken from usr/src/sys/kern/uipc_sockbuf.c and called within sctp_lower_sosend.
michael@0 124 */
michael@0 125 int
michael@0 126 sbwait(struct sockbuf *sb)
michael@0 127 {
michael@0 128 #if defined(__Userspace__) /* __Userspace__ */
michael@0 129
michael@0 130 SOCKBUF_LOCK_ASSERT(sb);
michael@0 131
michael@0 132 sb->sb_flags |= SB_WAIT;
michael@0 133 #if defined (__Userspace_os_Windows)
michael@0 134 if (SleepConditionVariableCS(&(sb->sb_cond), &(sb->sb_mtx), INFINITE))
michael@0 135 return 0;
michael@0 136 else
michael@0 137 return -1;
michael@0 138 #else
michael@0 139 return (pthread_cond_wait(&(sb->sb_cond), &(sb->sb_mtx)));
michael@0 140 #endif
michael@0 141
michael@0 142 #else
michael@0 143 SOCKBUF_LOCK_ASSERT(sb);
michael@0 144
michael@0 145 sb->sb_flags |= SB_WAIT;
michael@0 146 return (msleep(&sb->sb_cc, &sb->sb_mtx,
michael@0 147 (sb->sb_flags & SB_NOINTR) ? PSOCK : PSOCK | PCATCH, "sbwait",
michael@0 148 sb->sb_timeo));
michael@0 149 #endif
michael@0 150 }
michael@0 151
michael@0 152
michael@0 153
michael@0 154
michael@0 155 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 156 * and modified for __Userspace__
michael@0 157 */
michael@0 158 static struct socket *
michael@0 159 soalloc(void)
michael@0 160 {
michael@0 161 struct socket *so;
michael@0 162
michael@0 163 /*
michael@0 164 * soalloc() sets of socket layer state for a socket,
michael@0 165 * called only by socreate() and sonewconn().
michael@0 166 *
michael@0 167 * sodealloc() tears down socket layer state for a socket,
michael@0 168 * called only by sofree() and sonewconn().
michael@0 169 * __Userspace__ TODO : Make sure so is properly deallocated
michael@0 170 * when tearing down the connection.
michael@0 171 */
michael@0 172
michael@0 173 so = (struct socket *)malloc(sizeof(struct socket));
michael@0 174
michael@0 175 if (so == NULL) {
michael@0 176 return (NULL);
michael@0 177 }
michael@0 178 memset(so, 0, sizeof(struct socket));
michael@0 179
michael@0 180 /* __Userspace__ Initializing the socket locks here */
michael@0 181 SOCKBUF_LOCK_INIT(&so->so_snd, "so_snd");
michael@0 182 SOCKBUF_LOCK_INIT(&so->so_rcv, "so_rcv");
michael@0 183 SOCKBUF_COND_INIT(&so->so_snd);
michael@0 184 SOCKBUF_COND_INIT(&so->so_rcv);
michael@0 185 SOCK_COND_INIT(so); /* timeo_cond */
michael@0 186
michael@0 187 /* __Userspace__ Any ref counting required here? Will we have any use for aiojobq?
michael@0 188 What about gencnt and numopensockets?*/
michael@0 189 TAILQ_INIT(&so->so_aiojobq);
michael@0 190 return (so);
michael@0 191 }
michael@0 192
michael@0 193 static void
michael@0 194 sodealloc(struct socket *so)
michael@0 195 {
michael@0 196
michael@0 197 KASSERT(so->so_count == 0, ("sodealloc(): so_count %d", so->so_count));
michael@0 198 KASSERT(so->so_pcb == NULL, ("sodealloc(): so_pcb != NULL"));
michael@0 199
michael@0 200 SOCKBUF_COND_DESTROY(&so->so_snd);
michael@0 201 SOCKBUF_COND_DESTROY(&so->so_rcv);
michael@0 202
michael@0 203 SOCK_COND_DESTROY(so);
michael@0 204
michael@0 205 SOCKBUF_LOCK_DESTROY(&so->so_snd);
michael@0 206 SOCKBUF_LOCK_DESTROY(&so->so_rcv);
michael@0 207
michael@0 208 free(so);
michael@0 209 }
michael@0 210
michael@0 211 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 212 * and modified for __Userspace__
michael@0 213 */
michael@0 214 void
michael@0 215 sofree(struct socket *so)
michael@0 216 {
michael@0 217 struct socket *head;
michael@0 218
michael@0 219 ACCEPT_LOCK_ASSERT();
michael@0 220 SOCK_LOCK_ASSERT(so);
michael@0 221 /* SS_NOFDREF unset in accept call. this condition seems irrelevent
michael@0 222 * for __Userspace__...
michael@0 223 */
michael@0 224 if (so->so_count != 0 ||
michael@0 225 (so->so_state & SS_PROTOREF) || (so->so_qstate & SQ_COMP)) {
michael@0 226 SOCK_UNLOCK(so);
michael@0 227 ACCEPT_UNLOCK();
michael@0 228 return;
michael@0 229 }
michael@0 230 head = so->so_head;
michael@0 231 if (head != NULL) {
michael@0 232 KASSERT((so->so_qstate & SQ_COMP) != 0 ||
michael@0 233 (so->so_qstate & SQ_INCOMP) != 0,
michael@0 234 ("sofree: so_head != NULL, but neither SQ_COMP nor "
michael@0 235 "SQ_INCOMP"));
michael@0 236 KASSERT((so->so_qstate & SQ_COMP) == 0 ||
michael@0 237 (so->so_qstate & SQ_INCOMP) == 0,
michael@0 238 ("sofree: so->so_qstate is SQ_COMP and also SQ_INCOMP"));
michael@0 239 TAILQ_REMOVE(&head->so_incomp, so, so_list);
michael@0 240 head->so_incqlen--;
michael@0 241 so->so_qstate &= ~SQ_INCOMP;
michael@0 242 so->so_head = NULL;
michael@0 243 }
michael@0 244 KASSERT((so->so_qstate & SQ_COMP) == 0 &&
michael@0 245 (so->so_qstate & SQ_INCOMP) == 0,
michael@0 246 ("sofree: so_head == NULL, but still SQ_COMP(%d) or SQ_INCOMP(%d)",
michael@0 247 so->so_qstate & SQ_COMP, so->so_qstate & SQ_INCOMP));
michael@0 248 if (so->so_options & SCTP_SO_ACCEPTCONN) {
michael@0 249 KASSERT((TAILQ_EMPTY(&so->so_comp)), ("sofree: so_comp populated"));
michael@0 250 KASSERT((TAILQ_EMPTY(&so->so_incomp)), ("sofree: so_comp populated"));
michael@0 251 }
michael@0 252 SOCK_UNLOCK(so);
michael@0 253 ACCEPT_UNLOCK();
michael@0 254 sctp_close(so); /* was... sctp_detach(so); */
michael@0 255 /*
michael@0 256 * From this point on, we assume that no other references to this
michael@0 257 * socket exist anywhere else in the stack. Therefore, no locks need
michael@0 258 * to be acquired or held.
michael@0 259 *
michael@0 260 * We used to do a lot of socket buffer and socket locking here, as
michael@0 261 * well as invoke sorflush() and perform wakeups. The direct call to
michael@0 262 * dom_dispose() and sbrelease_internal() are an inlining of what was
michael@0 263 * necessary from sorflush().
michael@0 264 *
michael@0 265 * Notice that the socket buffer and kqueue state are torn down
michael@0 266 * before calling pru_detach. This means that protocols shold not
michael@0 267 * assume they can perform socket wakeups, etc, in their detach code.
michael@0 268 */
michael@0 269 sodealloc(so);
michael@0 270 }
michael@0 271
michael@0 272
michael@0 273
michael@0 274 /* Taken from /src/sys/kern/uipc_socket.c */
michael@0 275 int
michael@0 276 soabort(so)
michael@0 277 struct socket *so;
michael@0 278 {
michael@0 279 int error;
michael@0 280 #if defined(INET6)
michael@0 281 struct sctp_inpcb *inp;
michael@0 282 #endif
michael@0 283
michael@0 284 #if defined(INET6)
michael@0 285 inp = (struct sctp_inpcb *)so->so_pcb;
michael@0 286 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) {
michael@0 287 error = sctp6_abort(so);
michael@0 288 } else {
michael@0 289 #if defined(INET)
michael@0 290 error = sctp_abort(so);
michael@0 291 #else
michael@0 292 error = EAFNOSUPPORT;
michael@0 293 #endif
michael@0 294 }
michael@0 295 #elif defined(INET)
michael@0 296 error = sctp_abort(so);
michael@0 297 #else
michael@0 298 error = EAFNOSUPPORT;
michael@0 299 #endif
michael@0 300 if (error) {
michael@0 301 sofree(so);
michael@0 302 return error;
michael@0 303 }
michael@0 304 return (0);
michael@0 305 }
michael@0 306
michael@0 307
michael@0 308 /* Taken from usr/src/sys/kern/uipc_socket.c and called within sctp_connect (sctp_usrreq.c).
michael@0 309 * We use sctp_connect for send_one_init_real in ms1.
michael@0 310 */
michael@0 311 void
michael@0 312 soisconnecting(struct socket *so)
michael@0 313 {
michael@0 314
michael@0 315 SOCK_LOCK(so);
michael@0 316 so->so_state &= ~(SS_ISCONNECTED|SS_ISDISCONNECTING);
michael@0 317 so->so_state |= SS_ISCONNECTING;
michael@0 318 SOCK_UNLOCK(so);
michael@0 319 }
michael@0 320
michael@0 321 /* Taken from usr/src/sys/kern/uipc_socket.c and called within sctp_disconnect (sctp_usrreq.c).
michael@0 322 * TODO Do we use sctp_disconnect?
michael@0 323 */
michael@0 324 void
michael@0 325 soisdisconnecting(struct socket *so)
michael@0 326 {
michael@0 327
michael@0 328 /*
michael@0 329 * Note: This code assumes that SOCK_LOCK(so) and
michael@0 330 * SOCKBUF_LOCK(&so->so_rcv) are the same.
michael@0 331 */
michael@0 332 SOCKBUF_LOCK(&so->so_rcv);
michael@0 333 so->so_state &= ~SS_ISCONNECTING;
michael@0 334 so->so_state |= SS_ISDISCONNECTING;
michael@0 335 so->so_rcv.sb_state |= SBS_CANTRCVMORE;
michael@0 336 sorwakeup_locked(so);
michael@0 337 SOCKBUF_LOCK(&so->so_snd);
michael@0 338 so->so_snd.sb_state |= SBS_CANTSENDMORE;
michael@0 339 sowwakeup_locked(so);
michael@0 340 wakeup("dummy",so);
michael@0 341 /* requires 2 args but this was in orig */
michael@0 342 /* wakeup(&so->so_timeo); */
michael@0 343 }
michael@0 344
michael@0 345
michael@0 346 /* Taken from sys/kern/kern_synch.c and
michael@0 347 modified for __Userspace__
michael@0 348 */
michael@0 349
michael@0 350 /*
michael@0 351 * Make all threads sleeping on the specified identifier runnable.
michael@0 352 * Associating wakeup with so_timeo identifier and timeo_cond
michael@0 353 * condition variable. TODO. If we use iterator thread then we need to
michael@0 354 * modify wakeup so it can distinguish between iterator identifier and
michael@0 355 * timeo identifier.
michael@0 356 */
michael@0 357 void
michael@0 358 wakeup(ident, so)
michael@0 359 void *ident;
michael@0 360 struct socket *so;
michael@0 361 {
michael@0 362 SOCK_LOCK(so);
michael@0 363 #if defined (__Userspace_os_Windows)
michael@0 364 WakeAllConditionVariable(&(so)->timeo_cond);
michael@0 365 #else
michael@0 366 pthread_cond_broadcast(&(so)->timeo_cond);
michael@0 367 #endif
michael@0 368 SOCK_UNLOCK(so);
michael@0 369 }
michael@0 370
michael@0 371
michael@0 372 /*
michael@0 373 * Make a thread sleeping on the specified identifier runnable.
michael@0 374 * May wake more than one thread if a target thread is currently
michael@0 375 * swapped out.
michael@0 376 */
michael@0 377 void
michael@0 378 wakeup_one(ident)
michael@0 379 void *ident;
michael@0 380 {
michael@0 381 /* __Userspace__ Check: We are using accept_cond for wakeup_one.
michael@0 382 It seems that wakeup_one is only called within
michael@0 383 soisconnected() and sonewconn() with ident &head->so_timeo
michael@0 384 head is so->so_head, which is back pointer to listen socket
michael@0 385 This seems to indicate that the use of accept_cond is correct
michael@0 386 since socket where accepts occur is so_head in all
michael@0 387 subsidiary sockets.
michael@0 388 */
michael@0 389 ACCEPT_LOCK();
michael@0 390 #if defined (__Userspace_os_Windows)
michael@0 391 WakeAllConditionVariable(&accept_cond);
michael@0 392 #else
michael@0 393 pthread_cond_broadcast(&accept_cond);
michael@0 394 #endif
michael@0 395 ACCEPT_UNLOCK();
michael@0 396 }
michael@0 397
michael@0 398
michael@0 399 /* Called within sctp_process_cookie_[existing/new] */
michael@0 400 void
michael@0 401 soisconnected(struct socket *so)
michael@0 402 {
michael@0 403 struct socket *head;
michael@0 404
michael@0 405 ACCEPT_LOCK();
michael@0 406 SOCK_LOCK(so);
michael@0 407 so->so_state &= ~(SS_ISCONNECTING|SS_ISDISCONNECTING|SS_ISCONFIRMING);
michael@0 408 so->so_state |= SS_ISCONNECTED;
michael@0 409 head = so->so_head;
michael@0 410 if (head != NULL && (so->so_qstate & SQ_INCOMP)) {
michael@0 411 SOCK_UNLOCK(so);
michael@0 412 TAILQ_REMOVE(&head->so_incomp, so, so_list);
michael@0 413 head->so_incqlen--;
michael@0 414 so->so_qstate &= ~SQ_INCOMP;
michael@0 415 TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
michael@0 416 head->so_qlen++;
michael@0 417 so->so_qstate |= SQ_COMP;
michael@0 418 ACCEPT_UNLOCK();
michael@0 419 sorwakeup(head);
michael@0 420 wakeup_one(&head->so_timeo);
michael@0 421 return;
michael@0 422 }
michael@0 423 SOCK_UNLOCK(so);
michael@0 424 ACCEPT_UNLOCK();
michael@0 425 wakeup(&so->so_timeo, so);
michael@0 426 sorwakeup(so);
michael@0 427 sowwakeup(so);
michael@0 428
michael@0 429 }
michael@0 430
michael@0 431 /* called within sctp_handle_cookie_echo */
michael@0 432
michael@0 433 struct socket *
michael@0 434 sonewconn(struct socket *head, int connstatus)
michael@0 435 {
michael@0 436 struct socket *so;
michael@0 437 int over;
michael@0 438
michael@0 439 ACCEPT_LOCK();
michael@0 440 over = (head->so_qlen > 3 * head->so_qlimit / 2);
michael@0 441 ACCEPT_UNLOCK();
michael@0 442 #ifdef REGRESSION
michael@0 443 if (regression_sonewconn_earlytest && over)
michael@0 444 #else
michael@0 445 if (over)
michael@0 446 #endif
michael@0 447 return (NULL);
michael@0 448 so = soalloc();
michael@0 449 if (so == NULL)
michael@0 450 return (NULL);
michael@0 451 so->so_head = head;
michael@0 452 so->so_type = head->so_type;
michael@0 453 so->so_options = head->so_options &~ SCTP_SO_ACCEPTCONN;
michael@0 454 so->so_linger = head->so_linger;
michael@0 455 so->so_state = head->so_state | SS_NOFDREF;
michael@0 456 so->so_dom = head->so_dom;
michael@0 457 #ifdef MAC
michael@0 458 SOCK_LOCK(head);
michael@0 459 mac_create_socket_from_socket(head, so);
michael@0 460 SOCK_UNLOCK(head);
michael@0 461 #endif
michael@0 462 if (soreserve(so, head->so_snd.sb_hiwat, head->so_rcv.sb_hiwat)) {
michael@0 463 sodealloc(so);
michael@0 464 return (NULL);
michael@0 465 }
michael@0 466 switch (head->so_dom) {
michael@0 467 #ifdef INET
michael@0 468 case AF_INET:
michael@0 469 if (sctp_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) {
michael@0 470 sodealloc(so);
michael@0 471 return (NULL);
michael@0 472 }
michael@0 473 break;
michael@0 474 #endif
michael@0 475 #ifdef INET6
michael@0 476 case AF_INET6:
michael@0 477 if (sctp6_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) {
michael@0 478 sodealloc(so);
michael@0 479 return (NULL);
michael@0 480 }
michael@0 481 break;
michael@0 482 #endif
michael@0 483 case AF_CONN:
michael@0 484 if (sctpconn_attach(so, IPPROTO_SCTP, SCTP_DEFAULT_VRFID)) {
michael@0 485 sodealloc(so);
michael@0 486 return (NULL);
michael@0 487 }
michael@0 488 break;
michael@0 489 default:
michael@0 490 sodealloc(so);
michael@0 491 return (NULL);
michael@0 492 break;
michael@0 493 }
michael@0 494 so->so_rcv.sb_lowat = head->so_rcv.sb_lowat;
michael@0 495 so->so_snd.sb_lowat = head->so_snd.sb_lowat;
michael@0 496 so->so_rcv.sb_timeo = head->so_rcv.sb_timeo;
michael@0 497 so->so_snd.sb_timeo = head->so_snd.sb_timeo;
michael@0 498 so->so_rcv.sb_flags |= head->so_rcv.sb_flags & SB_AUTOSIZE;
michael@0 499 so->so_snd.sb_flags |= head->so_snd.sb_flags & SB_AUTOSIZE;
michael@0 500 so->so_state |= connstatus;
michael@0 501 ACCEPT_LOCK();
michael@0 502 if (connstatus) {
michael@0 503 TAILQ_INSERT_TAIL(&head->so_comp, so, so_list);
michael@0 504 so->so_qstate |= SQ_COMP;
michael@0 505 head->so_qlen++;
michael@0 506 } else {
michael@0 507 /*
michael@0 508 * Keep removing sockets from the head until there's room for
michael@0 509 * us to insert on the tail. In pre-locking revisions, this
michael@0 510 * was a simple if(), but as we could be racing with other
michael@0 511 * threads and soabort() requires dropping locks, we must
michael@0 512 * loop waiting for the condition to be true.
michael@0 513 */
michael@0 514 while (head->so_incqlen > head->so_qlimit) {
michael@0 515 struct socket *sp;
michael@0 516 sp = TAILQ_FIRST(&head->so_incomp);
michael@0 517 TAILQ_REMOVE(&head->so_incomp, sp, so_list);
michael@0 518 head->so_incqlen--;
michael@0 519 sp->so_qstate &= ~SQ_INCOMP;
michael@0 520 sp->so_head = NULL;
michael@0 521 ACCEPT_UNLOCK();
michael@0 522 soabort(sp);
michael@0 523 ACCEPT_LOCK();
michael@0 524 }
michael@0 525 TAILQ_INSERT_TAIL(&head->so_incomp, so, so_list);
michael@0 526 so->so_qstate |= SQ_INCOMP;
michael@0 527 head->so_incqlen++;
michael@0 528 }
michael@0 529 ACCEPT_UNLOCK();
michael@0 530 if (connstatus) {
michael@0 531 sorwakeup(head);
michael@0 532 wakeup_one(&head->so_timeo);
michael@0 533 }
michael@0 534 return (so);
michael@0 535
michael@0 536 }
michael@0 537
michael@0 538 /* From /src/sys/sys/sysproto.h */
michael@0 539 struct sctp_generic_sendmsg_args {
michael@0 540 int sd;
michael@0 541 caddr_t msg;
michael@0 542 int mlen;
michael@0 543 caddr_t to;
michael@0 544 socklen_t tolen; /* was __socklen_t */
michael@0 545 struct sctp_sndrcvinfo * sinfo;
michael@0 546 int flags;
michael@0 547 };
michael@0 548
michael@0 549 struct sctp_generic_recvmsg_args {
michael@0 550 int sd;
michael@0 551 struct iovec *iov;
michael@0 552 int iovlen;
michael@0 553 struct sockaddr *from;
michael@0 554 socklen_t *fromlenaddr; /* was __socklen_t */
michael@0 555 struct sctp_sndrcvinfo *sinfo;
michael@0 556 int *msg_flags;
michael@0 557 };
michael@0 558
michael@0 559
michael@0 560 /*
michael@0 561 Source: /src/sys/gnu/fs/xfs/FreeBSD/xfs_ioctl.c
michael@0 562 */
michael@0 563 static __inline__ int
michael@0 564 copy_to_user(void *dst, void *src, int len) {
michael@0 565 memcpy(dst, src, len);
michael@0 566 return 0;
michael@0 567 }
michael@0 568
michael@0 569 static __inline__ int
michael@0 570 copy_from_user(void *dst, void *src, int len) {
michael@0 571 memcpy(dst, src, len);
michael@0 572 return 0;
michael@0 573 }
michael@0 574
michael@0 575 /*
michael@0 576 References:
michael@0 577 src/sys/dev/lmc/if_lmc.h:
michael@0 578 src/sys/powerpc/powerpc/copyinout.c
michael@0 579 src/sys/sys/systm.h
michael@0 580 */
michael@0 581 # define copyin(u, k, len) copy_from_user(k, u, len)
michael@0 582
michael@0 583 /* References:
michael@0 584 src/sys/powerpc/powerpc/copyinout.c
michael@0 585 src/sys/sys/systm.h
michael@0 586 */
michael@0 587 # define copyout(k, u, len) copy_to_user(u, k, len)
michael@0 588
michael@0 589
michael@0 590 /* copyiniov definition copied/modified from src/sys/kern/kern_subr.c */
michael@0 591 int
michael@0 592 copyiniov(struct iovec *iovp, u_int iovcnt, struct iovec **iov, int error)
michael@0 593 {
michael@0 594 u_int iovlen;
michael@0 595
michael@0 596 *iov = NULL;
michael@0 597 if (iovcnt > UIO_MAXIOV)
michael@0 598 return (error);
michael@0 599 iovlen = iovcnt * sizeof (struct iovec);
michael@0 600 *iov = malloc(iovlen); /*, M_IOV, M_WAITOK); */
michael@0 601 error = copyin(iovp, *iov, iovlen);
michael@0 602 if (error) {
michael@0 603 free(*iov); /*, M_IOV); */
michael@0 604 *iov = NULL;
michael@0 605 }
michael@0 606 return (error);
michael@0 607 }
michael@0 608
michael@0 609 /* (__Userspace__) version of uiomove */
michael@0 610 int
michael@0 611 uiomove(void *cp, int n, struct uio *uio)
michael@0 612 {
michael@0 613 struct iovec *iov;
michael@0 614 int cnt;
michael@0 615 int error = 0;
michael@0 616
michael@0 617 if ((uio->uio_rw != UIO_READ) &&
michael@0 618 (uio->uio_rw != UIO_WRITE)) {
michael@0 619 return (EINVAL);
michael@0 620 }
michael@0 621
michael@0 622 while (n > 0 && uio->uio_resid) {
michael@0 623 iov = uio->uio_iov;
michael@0 624 cnt = iov->iov_len;
michael@0 625 if (cnt == 0) {
michael@0 626 uio->uio_iov++;
michael@0 627 uio->uio_iovcnt--;
michael@0 628 continue;
michael@0 629 }
michael@0 630 if (cnt > n)
michael@0 631 cnt = n;
michael@0 632
michael@0 633 switch (uio->uio_segflg) {
michael@0 634
michael@0 635 case UIO_USERSPACE:
michael@0 636 if (uio->uio_rw == UIO_READ)
michael@0 637 error = copyout(cp, iov->iov_base, cnt);
michael@0 638 else
michael@0 639 error = copyin(iov->iov_base, cp, cnt);
michael@0 640 if (error)
michael@0 641 goto out;
michael@0 642 break;
michael@0 643
michael@0 644 case UIO_SYSSPACE:
michael@0 645 if (uio->uio_rw == UIO_READ)
michael@0 646 bcopy(cp, iov->iov_base, cnt);
michael@0 647 else
michael@0 648 bcopy(iov->iov_base, cp, cnt);
michael@0 649 break;
michael@0 650 }
michael@0 651 iov->iov_base = (char *)iov->iov_base + cnt;
michael@0 652 iov->iov_len -= cnt;
michael@0 653 uio->uio_resid -= cnt;
michael@0 654 uio->uio_offset += cnt;
michael@0 655 cp = (char *)cp + cnt;
michael@0 656 n -= cnt;
michael@0 657 }
michael@0 658 out:
michael@0 659 return (error);
michael@0 660 }
michael@0 661
michael@0 662
michael@0 663 /* Source: src/sys/kern/uipc_syscalls.c */
michael@0 664 int
michael@0 665 getsockaddr(namp, uaddr, len)
michael@0 666 struct sockaddr **namp;
michael@0 667 caddr_t uaddr;
michael@0 668 size_t len;
michael@0 669 {
michael@0 670 struct sockaddr *sa;
michael@0 671 int error;
michael@0 672
michael@0 673 if (len > SOCK_MAXADDRLEN)
michael@0 674 return (ENAMETOOLONG);
michael@0 675 if (len < offsetof(struct sockaddr, sa_data))
michael@0 676 return (EINVAL);
michael@0 677 MALLOC(sa, struct sockaddr *, len, M_SONAME, M_WAITOK);
michael@0 678 error = copyin(uaddr, sa, len);
michael@0 679 if (error) {
michael@0 680 FREE(sa, M_SONAME);
michael@0 681 } else {
michael@0 682 #ifdef HAVE_SA_LEN
michael@0 683 sa->sa_len = len;
michael@0 684 #endif
michael@0 685 *namp = sa;
michael@0 686 }
michael@0 687 return (error);
michael@0 688 }
michael@0 689
michael@0 690
michael@0 691 /* Taken from /src/lib/libc/net/sctp_sys_calls.c
michael@0 692 * and modified for __Userspace__
michael@0 693 * calling sctp_generic_sendmsg from this function
michael@0 694 */
michael@0 695 ssize_t
michael@0 696 userspace_sctp_sendmsg(struct socket *so,
michael@0 697 const void *data,
michael@0 698 size_t len,
michael@0 699 struct sockaddr *to,
michael@0 700 socklen_t tolen,
michael@0 701 u_int32_t ppid,
michael@0 702 u_int32_t flags,
michael@0 703 u_int16_t stream_no,
michael@0 704 u_int32_t timetolive,
michael@0 705 u_int32_t context)
michael@0 706 {
michael@0 707 struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo;
michael@0 708 struct uio auio;
michael@0 709 struct iovec iov[1];
michael@0 710
michael@0 711 sinfo->sinfo_ppid = ppid;
michael@0 712 sinfo->sinfo_flags = flags;
michael@0 713 sinfo->sinfo_stream = stream_no;
michael@0 714 sinfo->sinfo_timetolive = timetolive;
michael@0 715 sinfo->sinfo_context = context;
michael@0 716 sinfo->sinfo_assoc_id = 0;
michael@0 717
michael@0 718
michael@0 719 /* Perform error checks on destination (to) */
michael@0 720 if (tolen > SOCK_MAXADDRLEN){
michael@0 721 errno = ENAMETOOLONG;
michael@0 722 return (-1);
michael@0 723 }
michael@0 724 if ((tolen > 0) &&
michael@0 725 ((to == NULL) || (tolen < (socklen_t)sizeof(struct sockaddr)))) {
michael@0 726 errno = EINVAL;
michael@0 727 return (-1);
michael@0 728 }
michael@0 729 /* Adding the following as part of defensive programming, in case the application
michael@0 730 does not do it when preparing the destination address.*/
michael@0 731 #ifdef HAVE_SA_LEN
michael@0 732 if (to != NULL) {
michael@0 733 to->sa_len = tolen;
michael@0 734 }
michael@0 735 #endif
michael@0 736
michael@0 737 iov[0].iov_base = (caddr_t)data;
michael@0 738 iov[0].iov_len = len;
michael@0 739
michael@0 740 auio.uio_iov = iov;
michael@0 741 auio.uio_iovcnt = 1;
michael@0 742 auio.uio_segflg = UIO_USERSPACE;
michael@0 743 auio.uio_rw = UIO_WRITE;
michael@0 744 auio.uio_offset = 0; /* XXX */
michael@0 745 auio.uio_resid = len;
michael@0 746 errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, 0, sinfo);
michael@0 747 if (errno == 0) {
michael@0 748 return (len - auio.uio_resid);
michael@0 749 } else {
michael@0 750 return (-1);
michael@0 751 }
michael@0 752 }
michael@0 753
michael@0 754
michael@0 755 ssize_t
michael@0 756 usrsctp_sendv(struct socket *so,
michael@0 757 const void *data,
michael@0 758 size_t len,
michael@0 759 struct sockaddr *to,
michael@0 760 int addrcnt,
michael@0 761 void *info,
michael@0 762 socklen_t infolen,
michael@0 763 unsigned int infotype,
michael@0 764 int flags)
michael@0 765 {
michael@0 766 struct sctp_sndrcvinfo sinfo;
michael@0 767 struct uio auio;
michael@0 768 struct iovec iov[1];
michael@0 769 int use_sinfo;
michael@0 770
michael@0 771 if (so == NULL) {
michael@0 772 errno = EBADF;
michael@0 773 return (-1);
michael@0 774 }
michael@0 775 memset(&sinfo, 0, sizeof(struct sctp_sndrcvinfo));
michael@0 776 use_sinfo = 0;
michael@0 777 switch (infotype) {
michael@0 778 case SCTP_SENDV_NOINFO:
michael@0 779 if ((infolen != 0) || (info != NULL)) {
michael@0 780 errno = EINVAL;
michael@0 781 return (-1);
michael@0 782 }
michael@0 783 break;
michael@0 784 case SCTP_SENDV_SNDINFO:
michael@0 785 if ((info == NULL) || (infolen != sizeof(struct sctp_sndinfo))) {
michael@0 786 errno = EINVAL;
michael@0 787 return (-1);
michael@0 788 }
michael@0 789 sinfo.sinfo_stream = ((struct sctp_sndinfo *)info)->snd_sid;
michael@0 790 sinfo.sinfo_flags = ((struct sctp_sndinfo *)info)->snd_flags;
michael@0 791 sinfo.sinfo_ppid = ((struct sctp_sndinfo *)info)->snd_ppid;
michael@0 792 sinfo.sinfo_context = ((struct sctp_sndinfo *)info)->snd_context;
michael@0 793 sinfo.sinfo_assoc_id = ((struct sctp_sndinfo *)info)->snd_assoc_id;
michael@0 794 use_sinfo = 1;
michael@0 795 break;
michael@0 796 case SCTP_SENDV_PRINFO:
michael@0 797 if ((info == NULL) || (infolen != sizeof(struct sctp_prinfo))) {
michael@0 798 errno = EINVAL;
michael@0 799 return (-1);
michael@0 800 }
michael@0 801 sinfo.sinfo_stream = 0;
michael@0 802 sinfo.sinfo_flags = PR_SCTP_POLICY(((struct sctp_prinfo *)info)->pr_policy);
michael@0 803 sinfo.sinfo_timetolive = ((struct sctp_prinfo *)info)->pr_value;
michael@0 804 use_sinfo = 1;
michael@0 805 break;
michael@0 806 case SCTP_SENDV_AUTHINFO:
michael@0 807 errno = EINVAL;
michael@0 808 return (-1);
michael@0 809 case SCTP_SENDV_SPA:
michael@0 810 if ((info == NULL) || (infolen != sizeof(struct sctp_sendv_spa))) {
michael@0 811 errno = EINVAL;
michael@0 812 return (-1);
michael@0 813 }
michael@0 814 if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_SNDINFO_VALID) {
michael@0 815 sinfo.sinfo_stream = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_sid;
michael@0 816 sinfo.sinfo_flags = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_flags;
michael@0 817 sinfo.sinfo_ppid = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_ppid;
michael@0 818 sinfo.sinfo_context = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_context;
michael@0 819 sinfo.sinfo_assoc_id = ((struct sctp_sendv_spa *)info)->sendv_sndinfo.snd_assoc_id;
michael@0 820 } else {
michael@0 821 sinfo.sinfo_flags = 0;
michael@0 822 sinfo.sinfo_stream = 0;
michael@0 823 }
michael@0 824 if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_PRINFO_VALID) {
michael@0 825 sinfo.sinfo_flags |= PR_SCTP_POLICY(((struct sctp_sendv_spa *)info)->sendv_prinfo.pr_policy);
michael@0 826 sinfo.sinfo_timetolive = ((struct sctp_sendv_spa *)info)->sendv_prinfo.pr_value;
michael@0 827 }
michael@0 828 if (((struct sctp_sendv_spa *)info)->sendv_flags & SCTP_SEND_AUTHINFO_VALID) {
michael@0 829 errno = EINVAL;
michael@0 830 return (-1);
michael@0 831 }
michael@0 832 use_sinfo = 1;
michael@0 833 break;
michael@0 834 default:
michael@0 835 errno = EINVAL;
michael@0 836 return (-1);
michael@0 837 }
michael@0 838
michael@0 839 /* Perform error checks on destination (to) */
michael@0 840 if (addrcnt > 1) {
michael@0 841 errno = EINVAL;
michael@0 842 return (-1);
michael@0 843 }
michael@0 844
michael@0 845 iov[0].iov_base = (caddr_t)data;
michael@0 846 iov[0].iov_len = len;
michael@0 847
michael@0 848 auio.uio_iov = iov;
michael@0 849 auio.uio_iovcnt = 1;
michael@0 850 auio.uio_segflg = UIO_USERSPACE;
michael@0 851 auio.uio_rw = UIO_WRITE;
michael@0 852 auio.uio_offset = 0; /* XXX */
michael@0 853 auio.uio_resid = len;
michael@0 854 errno = sctp_lower_sosend(so, to, &auio, NULL, NULL, flags, use_sinfo ? &sinfo : NULL);
michael@0 855 if (errno == 0) {
michael@0 856 return (len - auio.uio_resid);
michael@0 857 } else {
michael@0 858 return (-1);
michael@0 859 }
michael@0 860 }
michael@0 861
michael@0 862
michael@0 863 ssize_t
michael@0 864 userspace_sctp_sendmbuf(struct socket *so,
michael@0 865 struct mbuf* mbufdata,
michael@0 866 size_t len,
michael@0 867 struct sockaddr *to,
michael@0 868 socklen_t tolen,
michael@0 869 u_int32_t ppid,
michael@0 870 u_int32_t flags,
michael@0 871 u_int16_t stream_no,
michael@0 872 u_int32_t timetolive,
michael@0 873 u_int32_t context)
michael@0 874 {
michael@0 875
michael@0 876 struct sctp_sndrcvinfo sndrcvinfo, *sinfo = &sndrcvinfo;
michael@0 877 /* struct uio auio;
michael@0 878 struct iovec iov[1]; */
michael@0 879 int error = 0;
michael@0 880 int uflags = 0;
michael@0 881 int retvalsendmsg;
michael@0 882
michael@0 883 sinfo->sinfo_ppid = ppid;
michael@0 884 sinfo->sinfo_flags = flags;
michael@0 885 sinfo->sinfo_stream = stream_no;
michael@0 886 sinfo->sinfo_timetolive = timetolive;
michael@0 887 sinfo->sinfo_context = context;
michael@0 888 sinfo->sinfo_assoc_id = 0;
michael@0 889
michael@0 890 /* Perform error checks on destination (to) */
michael@0 891 if (tolen > SOCK_MAXADDRLEN){
michael@0 892 error = (ENAMETOOLONG);
michael@0 893 goto sendmsg_return;
michael@0 894 }
michael@0 895 if (tolen < (socklen_t)offsetof(struct sockaddr, sa_data)){
michael@0 896 error = (EINVAL);
michael@0 897 goto sendmsg_return;
michael@0 898 }
michael@0 899 /* Adding the following as part of defensive programming, in case the application
michael@0 900 does not do it when preparing the destination address.*/
michael@0 901 #ifdef HAVE_SA_LEN
michael@0 902 to->sa_len = tolen;
michael@0 903 #endif
michael@0 904
michael@0 905 error = sctp_lower_sosend(so, to, NULL/*uio*/,
michael@0 906 (struct mbuf *)mbufdata, (struct mbuf *)NULL,
michael@0 907 uflags, sinfo);
michael@0 908 sendmsg_return:
michael@0 909 /* TODO: Needs a condition for non-blocking when error is EWOULDBLOCK */
michael@0 910 if (0 == error)
michael@0 911 retvalsendmsg = len;
michael@0 912 else if(error == EWOULDBLOCK) {
michael@0 913 errno = EWOULDBLOCK;
michael@0 914 retvalsendmsg = (-1);
michael@0 915 } else {
michael@0 916 SCTP_PRINTF("%s: error = %d\n", __func__, error);
michael@0 917 errno = error;
michael@0 918 retvalsendmsg = (-1);
michael@0 919 }
michael@0 920 return retvalsendmsg;
michael@0 921
michael@0 922 }
michael@0 923
michael@0 924
michael@0 925 /* taken from usr.lib/sctp_sys_calls.c and needed here */
michael@0 926 #define SCTP_SMALL_IOVEC_SIZE 2
michael@0 927
michael@0 928 /* Taken from /src/lib/libc/net/sctp_sys_calls.c
michael@0 929 * and modified for __Userspace__
michael@0 930 * calling sctp_generic_recvmsg from this function
michael@0 931 */
michael@0 932 ssize_t
michael@0 933 userspace_sctp_recvmsg(struct socket *so,
michael@0 934 void *dbuf,
michael@0 935 size_t len,
michael@0 936 struct sockaddr *from,
michael@0 937 socklen_t *fromlenp,
michael@0 938 struct sctp_sndrcvinfo *sinfo,
michael@0 939 int *msg_flags)
michael@0 940 {
michael@0 941 struct uio auio;
michael@0 942 struct iovec iov[SCTP_SMALL_IOVEC_SIZE];
michael@0 943 struct iovec *tiov;
michael@0 944 int iovlen = 1;
michael@0 945 int error = 0;
michael@0 946 int ulen, i, retval;
michael@0 947 socklen_t fromlen;
michael@0 948
michael@0 949 iov[0].iov_base = dbuf;
michael@0 950 iov[0].iov_len = len;
michael@0 951
michael@0 952 auio.uio_iov = iov;
michael@0 953 auio.uio_iovcnt = iovlen;
michael@0 954 auio.uio_segflg = UIO_USERSPACE;
michael@0 955 auio.uio_rw = UIO_READ;
michael@0 956 auio.uio_offset = 0; /* XXX */
michael@0 957 auio.uio_resid = 0;
michael@0 958 tiov = iov;
michael@0 959 for (i = 0; i <iovlen; i++, tiov++) {
michael@0 960 if ((auio.uio_resid += tiov->iov_len) < 0) {
michael@0 961 error = EINVAL;
michael@0 962 SCTP_PRINTF("%s: error = %d\n", __func__, error);
michael@0 963 return (-1);
michael@0 964 }
michael@0 965 }
michael@0 966 ulen = auio.uio_resid;
michael@0 967 if (fromlenp != NULL) {
michael@0 968 fromlen = *fromlenp;
michael@0 969 } else {
michael@0 970 fromlen = 0;
michael@0 971 }
michael@0 972 error = sctp_sorecvmsg(so, &auio, (struct mbuf **)NULL,
michael@0 973 from, fromlen, msg_flags,
michael@0 974 (struct sctp_sndrcvinfo *)sinfo, 1);
michael@0 975
michael@0 976 if (error) {
michael@0 977 if (auio.uio_resid != (int)ulen &&
michael@0 978 (error == EINTR ||
michael@0 979 #if !defined(__Userspace_os_NetBSD)
michael@0 980 error == ERESTART ||
michael@0 981 #endif
michael@0 982 error == EWOULDBLOCK)) {
michael@0 983 error = 0;
michael@0 984 }
michael@0 985 }
michael@0 986 if ((fromlenp != NULL) && (fromlen > 0) && (from != NULL)) {
michael@0 987 switch (from->sa_family) {
michael@0 988 #if defined(INET)
michael@0 989 case AF_INET:
michael@0 990 *fromlenp = sizeof(struct sockaddr_in);
michael@0 991 break;
michael@0 992 #endif
michael@0 993 #if defined(INET6)
michael@0 994 case AF_INET6:
michael@0 995 *fromlenp = sizeof(struct sockaddr_in6);
michael@0 996 break;
michael@0 997 #endif
michael@0 998 case AF_CONN:
michael@0 999 *fromlenp = sizeof(struct sockaddr_conn);
michael@0 1000 break;
michael@0 1001 default:
michael@0 1002 *fromlenp = 0;
michael@0 1003 break;
michael@0 1004 }
michael@0 1005 if (*fromlenp > fromlen) {
michael@0 1006 *fromlenp = fromlen;
michael@0 1007 }
michael@0 1008 }
michael@0 1009 if (error == 0){
michael@0 1010 /* ready return value */
michael@0 1011 retval = (int)ulen - auio.uio_resid;
michael@0 1012 return (retval);
michael@0 1013 } else {
michael@0 1014 SCTP_PRINTF("%s: error = %d\n", __func__, error);
michael@0 1015 return (-1);
michael@0 1016 }
michael@0 1017 }
michael@0 1018
michael@0 1019 ssize_t
michael@0 1020 usrsctp_recvv(struct socket *so,
michael@0 1021 void *dbuf,
michael@0 1022 size_t len,
michael@0 1023 struct sockaddr *from,
michael@0 1024 socklen_t *fromlenp,
michael@0 1025 void *info,
michael@0 1026 socklen_t *infolen,
michael@0 1027 unsigned int *infotype,
michael@0 1028 int *msg_flags)
michael@0 1029 {
michael@0 1030 struct uio auio;
michael@0 1031 struct iovec iov[SCTP_SMALL_IOVEC_SIZE];
michael@0 1032 struct iovec *tiov;
michael@0 1033 int iovlen = 1;
michael@0 1034 int ulen, i;
michael@0 1035 socklen_t fromlen;
michael@0 1036 struct sctp_rcvinfo *rcv;
michael@0 1037 struct sctp_recvv_rn *rn;
michael@0 1038 struct sctp_extrcvinfo seinfo;
michael@0 1039
michael@0 1040 if (so == NULL) {
michael@0 1041 errno = EBADF;
michael@0 1042 return (-1);
michael@0 1043 }
michael@0 1044 iov[0].iov_base = dbuf;
michael@0 1045 iov[0].iov_len = len;
michael@0 1046
michael@0 1047 auio.uio_iov = iov;
michael@0 1048 auio.uio_iovcnt = iovlen;
michael@0 1049 auio.uio_segflg = UIO_USERSPACE;
michael@0 1050 auio.uio_rw = UIO_READ;
michael@0 1051 auio.uio_offset = 0; /* XXX */
michael@0 1052 auio.uio_resid = 0;
michael@0 1053 tiov = iov;
michael@0 1054 for (i = 0; i <iovlen; i++, tiov++) {
michael@0 1055 if ((auio.uio_resid += tiov->iov_len) < 0) {
michael@0 1056 errno = EINVAL;
michael@0 1057 return (-1);
michael@0 1058 }
michael@0 1059 }
michael@0 1060 ulen = auio.uio_resid;
michael@0 1061 if (fromlenp != NULL) {
michael@0 1062 fromlen = *fromlenp;
michael@0 1063 } else {
michael@0 1064 fromlen = 0;
michael@0 1065 }
michael@0 1066 errno = sctp_sorecvmsg(so, &auio, (struct mbuf **)NULL,
michael@0 1067 from, fromlen, msg_flags,
michael@0 1068 (struct sctp_sndrcvinfo *)&seinfo, 1);
michael@0 1069 if (errno) {
michael@0 1070 if (auio.uio_resid != (int)ulen &&
michael@0 1071 (errno == EINTR ||
michael@0 1072 #if !defined(__Userspace_os_NetBSD)
michael@0 1073 errno == ERESTART ||
michael@0 1074 #endif
michael@0 1075 errno == EWOULDBLOCK)) {
michael@0 1076 errno = 0;
michael@0 1077 }
michael@0 1078 }
michael@0 1079 if ((*msg_flags & MSG_NOTIFICATION) == 0) {
michael@0 1080 struct sctp_inpcb *inp;
michael@0 1081
michael@0 1082 inp = (struct sctp_inpcb *)so->so_pcb;
michael@0 1083 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO) &&
michael@0 1084 sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
michael@0 1085 *infolen >= (socklen_t)sizeof(struct sctp_recvv_rn) &&
michael@0 1086 seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_AVAIL) {
michael@0 1087 rn = (struct sctp_recvv_rn *)info;
michael@0 1088 rn->recvv_rcvinfo.rcv_sid = seinfo.sinfo_stream;
michael@0 1089 rn->recvv_rcvinfo.rcv_ssn = seinfo.sinfo_ssn;
michael@0 1090 rn->recvv_rcvinfo.rcv_flags = seinfo.sinfo_flags;
michael@0 1091 rn->recvv_rcvinfo.rcv_ppid = seinfo.sinfo_ppid;
michael@0 1092 rn->recvv_rcvinfo.rcv_context = seinfo.sinfo_context;
michael@0 1093 rn->recvv_rcvinfo.rcv_tsn = seinfo.sinfo_tsn;
michael@0 1094 rn->recvv_rcvinfo.rcv_cumtsn = seinfo.sinfo_cumtsn;
michael@0 1095 rn->recvv_rcvinfo.rcv_assoc_id = seinfo.sinfo_assoc_id;
michael@0 1096 rn->recvv_nxtinfo.nxt_sid = seinfo.sreinfo_next_stream;
michael@0 1097 rn->recvv_nxtinfo.nxt_flags = 0;
michael@0 1098 if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_IS_UNORDERED) {
michael@0 1099 rn->recvv_nxtinfo.nxt_flags |= SCTP_UNORDERED;
michael@0 1100 }
michael@0 1101 if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_IS_NOTIFICATION) {
michael@0 1102 rn->recvv_nxtinfo.nxt_flags |= SCTP_NOTIFICATION;
michael@0 1103 }
michael@0 1104 if (seinfo.sreinfo_next_flags & SCTP_NEXT_MSG_ISCOMPLETE) {
michael@0 1105 rn->recvv_nxtinfo.nxt_flags |= SCTP_COMPLETE;
michael@0 1106 }
michael@0 1107 rn->recvv_nxtinfo.nxt_ppid = seinfo.sreinfo_next_ppid;
michael@0 1108 rn->recvv_nxtinfo.nxt_length = seinfo.sreinfo_next_length;
michael@0 1109 rn->recvv_nxtinfo.nxt_assoc_id = seinfo.sreinfo_next_aid;
michael@0 1110 *infolen = (socklen_t)sizeof(struct sctp_recvv_rn);
michael@0 1111 *infotype = SCTP_RECVV_RN;
michael@0 1112 } else if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO) &&
michael@0 1113 *infolen >= (socklen_t)sizeof(struct sctp_rcvinfo)) {
michael@0 1114 rcv = (struct sctp_rcvinfo *)info;
michael@0 1115 rcv->rcv_sid = seinfo.sinfo_stream;
michael@0 1116 rcv->rcv_ssn = seinfo.sinfo_ssn;
michael@0 1117 rcv->rcv_flags = seinfo.sinfo_flags;
michael@0 1118 rcv->rcv_ppid = seinfo.sinfo_ppid;
michael@0 1119 rcv->rcv_context = seinfo.sinfo_context;
michael@0 1120 rcv->rcv_tsn = seinfo.sinfo_tsn;
michael@0 1121 rcv->rcv_cumtsn = seinfo.sinfo_cumtsn;
michael@0 1122 rcv->rcv_assoc_id = seinfo.sinfo_assoc_id;
michael@0 1123 *infolen = (socklen_t)sizeof(struct sctp_rcvinfo);
michael@0 1124 *infotype = SCTP_RECVV_RCVINFO;
michael@0 1125 } else {
michael@0 1126 *infotype = SCTP_RECVV_NOINFO;
michael@0 1127 *infolen = 0;
michael@0 1128 }
michael@0 1129 }
michael@0 1130 if ((fromlenp != NULL) && (fromlen > 0) && (from != NULL)) {
michael@0 1131 switch (from->sa_family) {
michael@0 1132 #if defined(INET)
michael@0 1133 case AF_INET:
michael@0 1134 *fromlenp = sizeof(struct sockaddr_in);
michael@0 1135 break;
michael@0 1136 #endif
michael@0 1137 #if defined(INET6)
michael@0 1138 case AF_INET6:
michael@0 1139 *fromlenp = sizeof(struct sockaddr_in6);
michael@0 1140 break;
michael@0 1141 #endif
michael@0 1142 case AF_CONN:
michael@0 1143 *fromlenp = sizeof(struct sockaddr_conn);
michael@0 1144 break;
michael@0 1145 default:
michael@0 1146 *fromlenp = 0;
michael@0 1147 break;
michael@0 1148 }
michael@0 1149 if (*fromlenp > fromlen) {
michael@0 1150 *fromlenp = fromlen;
michael@0 1151 }
michael@0 1152 }
michael@0 1153 if (errno == 0) {
michael@0 1154 /* ready return value */
michael@0 1155 return ((int)ulen - auio.uio_resid);
michael@0 1156 } else {
michael@0 1157 return (-1);
michael@0 1158 }
michael@0 1159 }
michael@0 1160
michael@0 1161
michael@0 1162
michael@0 1163
michael@0 1164 #if defined(__Userspace__)
michael@0 1165 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 1166 * and modified for __Userspace__
michael@0 1167 * socreate returns a socket. The socket should be
michael@0 1168 * closed with soclose().
michael@0 1169 */
michael@0 1170 int
michael@0 1171 socreate(int dom, struct socket **aso, int type, int proto)
michael@0 1172 {
michael@0 1173 struct socket *so;
michael@0 1174 int error;
michael@0 1175
michael@0 1176 if ((dom != AF_CONN) && (dom != AF_INET) && (dom != AF_INET6)) {
michael@0 1177 return (EINVAL);
michael@0 1178 }
michael@0 1179 if ((type != SOCK_STREAM) && (type != SOCK_SEQPACKET)) {
michael@0 1180 return (EINVAL);
michael@0 1181 }
michael@0 1182 if (proto != IPPROTO_SCTP) {
michael@0 1183 return (EINVAL);
michael@0 1184 }
michael@0 1185
michael@0 1186 so = soalloc();
michael@0 1187 if (so == NULL) {
michael@0 1188 return (ENOBUFS);
michael@0 1189 }
michael@0 1190
michael@0 1191 /*
michael@0 1192 * so_incomp represents a queue of connections that
michael@0 1193 * must be completed at protocol level before being
michael@0 1194 * returned. so_comp field heads a list of sockets
michael@0 1195 * that are ready to be returned to the listening process
michael@0 1196 *__Userspace__ These queues are being used at a number of places like accept etc.
michael@0 1197 */
michael@0 1198 TAILQ_INIT(&so->so_incomp);
michael@0 1199 TAILQ_INIT(&so->so_comp);
michael@0 1200 so->so_type = type;
michael@0 1201 so->so_count = 1;
michael@0 1202 so->so_dom = dom;
michael@0 1203 /*
michael@0 1204 * Auto-sizing of socket buffers is managed by the protocols and
michael@0 1205 * the appropriate flags must be set in the pru_attach function.
michael@0 1206 * For __Userspace__ The pru_attach function in this case is sctp_attach.
michael@0 1207 */
michael@0 1208 switch (dom) {
michael@0 1209 #if defined(INET)
michael@0 1210 case AF_INET:
michael@0 1211 error = sctp_attach(so, proto, SCTP_DEFAULT_VRFID);
michael@0 1212 break;
michael@0 1213 #endif
michael@0 1214 #if defined(INET6)
michael@0 1215 case AF_INET6:
michael@0 1216 error = sctp6_attach(so, proto, SCTP_DEFAULT_VRFID);
michael@0 1217 break;
michael@0 1218 #endif
michael@0 1219 case AF_CONN:
michael@0 1220 error = sctpconn_attach(so, proto, SCTP_DEFAULT_VRFID);
michael@0 1221 break;
michael@0 1222 default:
michael@0 1223 error = EAFNOSUPPORT;
michael@0 1224 break;
michael@0 1225 }
michael@0 1226 if (error) {
michael@0 1227 KASSERT(so->so_count == 1, ("socreate: so_count %d", so->so_count));
michael@0 1228 so->so_count = 0;
michael@0 1229 sodealloc(so);
michael@0 1230 return (error);
michael@0 1231 }
michael@0 1232 *aso = so;
michael@0 1233 return (0);
michael@0 1234 }
michael@0 1235 #else
michael@0 1236 /* The kernel version for reference is below. The #else
michael@0 1237 should be removed once the __Userspace__
michael@0 1238 version is tested.
michael@0 1239 * socreate returns a socket with a ref count of 1. The socket should be
michael@0 1240 * closed with soclose().
michael@0 1241 */
michael@0 1242 int
michael@0 1243 socreate(int dom, struct socket **aso, int type, int proto,
michael@0 1244 struct ucred *cred, struct thread *td)
michael@0 1245 {
michael@0 1246 struct protosw *prp;
michael@0 1247 struct socket *so;
michael@0 1248 int error;
michael@0 1249
michael@0 1250 if (proto)
michael@0 1251 prp = pffindproto(dom, proto, type);
michael@0 1252 else
michael@0 1253 prp = pffindtype(dom, type);
michael@0 1254
michael@0 1255 if (prp == NULL || prp->pr_usrreqs->pru_attach == NULL ||
michael@0 1256 prp->pr_usrreqs->pru_attach == pru_attach_notsupp)
michael@0 1257 return (EPROTONOSUPPORT);
michael@0 1258
michael@0 1259 if (jailed(cred) && jail_socket_unixiproute_only &&
michael@0 1260 prp->pr_domain->dom_family != PF_LOCAL &&
michael@0 1261 prp->pr_domain->dom_family != PF_INET &&
michael@0 1262 prp->pr_domain->dom_family != PF_ROUTE) {
michael@0 1263 return (EPROTONOSUPPORT);
michael@0 1264 }
michael@0 1265
michael@0 1266 if (prp->pr_type != type)
michael@0 1267 return (EPROTOTYPE);
michael@0 1268 so = soalloc();
michael@0 1269 if (so == NULL)
michael@0 1270 return (ENOBUFS);
michael@0 1271
michael@0 1272 TAILQ_INIT(&so->so_incomp);
michael@0 1273 TAILQ_INIT(&so->so_comp);
michael@0 1274 so->so_type = type;
michael@0 1275 so->so_cred = crhold(cred);
michael@0 1276 so->so_proto = prp;
michael@0 1277 #ifdef MAC
michael@0 1278 mac_create_socket(cred, so);
michael@0 1279 #endif
michael@0 1280 knlist_init(&so->so_rcv.sb_sel.si_note, SOCKBUF_MTX(&so->so_rcv),
michael@0 1281 NULL, NULL, NULL);
michael@0 1282 knlist_init(&so->so_snd.sb_sel.si_note, SOCKBUF_MTX(&so->so_snd),
michael@0 1283 NULL, NULL, NULL);
michael@0 1284 so->so_count = 1;
michael@0 1285 /*
michael@0 1286 * Auto-sizing of socket buffers is managed by the protocols and
michael@0 1287 * the appropriate flags must be set in the pru_attach function.
michael@0 1288 */
michael@0 1289 error = (*prp->pr_usrreqs->pru_attach)(so, proto, td);
michael@0 1290 if (error) {
michael@0 1291 KASSERT(so->so_count == 1, ("socreate: so_count %d",
michael@0 1292 so->so_count));
michael@0 1293 so->so_count = 0;
michael@0 1294 sodealloc(so);
michael@0 1295 return (error);
michael@0 1296 }
michael@0 1297 *aso = so;
michael@0 1298 return (0);
michael@0 1299 }
michael@0 1300 #endif
michael@0 1301
michael@0 1302
michael@0 1303
michael@0 1304
michael@0 1305 /* Taken from /src/sys/kern/uipc_syscalls.c
michael@0 1306 * and modified for __Userspace__
michael@0 1307 * Removing struct thread td.
michael@0 1308 */
michael@0 1309 struct socket *
michael@0 1310 userspace_socket(int domain, int type, int protocol)
michael@0 1311 {
michael@0 1312 struct socket *so = NULL;
michael@0 1313
michael@0 1314 errno = socreate(domain, &so, type, protocol);
michael@0 1315 if (errno) {
michael@0 1316 return (NULL);
michael@0 1317 }
michael@0 1318 /*
michael@0 1319 * The original socket call returns the file descriptor fd.
michael@0 1320 * td->td_retval[0] = fd.
michael@0 1321 * We are returning struct socket *so.
michael@0 1322 */
michael@0 1323 return (so);
michael@0 1324 }
michael@0 1325
michael@0 1326 struct socket *
michael@0 1327 usrsctp_socket(int domain, int type, int protocol,
michael@0 1328 int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data,
michael@0 1329 size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info),
michael@0 1330 int (*send_cb)(struct socket *sock, uint32_t sb_free),
michael@0 1331 uint32_t sb_threshold,
michael@0 1332 void *ulp_info)
michael@0 1333 {
michael@0 1334 struct socket *so;
michael@0 1335
michael@0 1336 if ((protocol = IPPROTO_SCTP) && (SCTP_BASE_VAR(sctp_pcb_initialized) == 0)) {
michael@0 1337 errno = EPROTONOSUPPORT;
michael@0 1338 return (NULL);
michael@0 1339 }
michael@0 1340 if ((receive_cb == NULL) &&
michael@0 1341 ((send_cb != NULL) || (sb_threshold != 0) || (ulp_info != NULL))) {
michael@0 1342 errno = EINVAL;
michael@0 1343 return (NULL);
michael@0 1344 }
michael@0 1345 if ((domain == AF_CONN) && (SCTP_BASE_VAR(conn_output) == NULL)) {
michael@0 1346 errno = EAFNOSUPPORT;
michael@0 1347 return (NULL);
michael@0 1348 }
michael@0 1349 errno = socreate(domain, &so, type, protocol);
michael@0 1350 if (errno) {
michael@0 1351 return (NULL);
michael@0 1352 }
michael@0 1353 /*
michael@0 1354 * The original socket call returns the file descriptor fd.
michael@0 1355 * td->td_retval[0] = fd.
michael@0 1356 * We are returning struct socket *so.
michael@0 1357 */
michael@0 1358 register_recv_cb(so, receive_cb);
michael@0 1359 register_send_cb(so, sb_threshold, send_cb);
michael@0 1360 register_ulp_info(so, ulp_info);
michael@0 1361 return (so);
michael@0 1362 }
michael@0 1363
michael@0 1364
michael@0 1365 u_long sb_max = SB_MAX;
michael@0 1366 u_long sb_max_adj =
michael@0 1367 SB_MAX * MCLBYTES / (MSIZE + MCLBYTES); /* adjusted sb_max */
michael@0 1368
michael@0 1369 static u_long sb_efficiency = 8; /* parameter for sbreserve() */
michael@0 1370
michael@0 1371 /*
michael@0 1372 * Allot mbufs to a sockbuf. Attempt to scale mbmax so that mbcnt doesn't
michael@0 1373 * become limiting if buffering efficiency is near the normal case.
michael@0 1374 */
michael@0 1375 int
michael@0 1376 sbreserve_locked(struct sockbuf *sb, u_long cc, struct socket *so)
michael@0 1377 {
michael@0 1378 SOCKBUF_LOCK_ASSERT(sb);
michael@0 1379 sb->sb_mbmax = (u_int)min(cc * sb_efficiency, sb_max);
michael@0 1380 sb->sb_hiwat = cc;
michael@0 1381 if (sb->sb_lowat > (int)sb->sb_hiwat)
michael@0 1382 sb->sb_lowat = (int)sb->sb_hiwat;
michael@0 1383 return (1);
michael@0 1384 }
michael@0 1385
michael@0 1386 static int
michael@0 1387 sbreserve(struct sockbuf *sb, u_long cc, struct socket *so)
michael@0 1388 {
michael@0 1389 int error;
michael@0 1390
michael@0 1391 SOCKBUF_LOCK(sb);
michael@0 1392 error = sbreserve_locked(sb, cc, so);
michael@0 1393 SOCKBUF_UNLOCK(sb);
michael@0 1394 return (error);
michael@0 1395 }
michael@0 1396
michael@0 1397 #if defined(__Userspace__)
michael@0 1398 int
michael@0 1399 soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
michael@0 1400 {
michael@0 1401 SOCKBUF_LOCK(&so->so_snd);
michael@0 1402 SOCKBUF_LOCK(&so->so_rcv);
michael@0 1403 so->so_snd.sb_hiwat = (uint32_t)sndcc;
michael@0 1404 so->so_rcv.sb_hiwat = (uint32_t)rcvcc;
michael@0 1405
michael@0 1406 if (sbreserve_locked(&so->so_snd, sndcc, so) == 0) {
michael@0 1407 goto bad;
michael@0 1408 }
michael@0 1409 if (sbreserve_locked(&so->so_rcv, rcvcc, so) == 0) {
michael@0 1410 goto bad;
michael@0 1411 }
michael@0 1412 if (so->so_rcv.sb_lowat == 0)
michael@0 1413 so->so_rcv.sb_lowat = 1;
michael@0 1414 if (so->so_snd.sb_lowat == 0)
michael@0 1415 so->so_snd.sb_lowat = MCLBYTES;
michael@0 1416 if (so->so_snd.sb_lowat > (int)so->so_snd.sb_hiwat)
michael@0 1417 so->so_snd.sb_lowat = (int)so->so_snd.sb_hiwat;
michael@0 1418 SOCKBUF_UNLOCK(&so->so_rcv);
michael@0 1419 SOCKBUF_UNLOCK(&so->so_snd);
michael@0 1420 return (0);
michael@0 1421
michael@0 1422 bad:
michael@0 1423 SOCKBUF_UNLOCK(&so->so_rcv);
michael@0 1424 SOCKBUF_UNLOCK(&so->so_snd);
michael@0 1425 return (ENOBUFS);
michael@0 1426 }
michael@0 1427 #else /* kernel version for reference */
michael@0 1428 int
michael@0 1429 soreserve(struct socket *so, u_long sndcc, u_long rcvcc)
michael@0 1430 {
michael@0 1431 struct thread *td = curthread;
michael@0 1432
michael@0 1433 SOCKBUF_LOCK(&so->so_snd);
michael@0 1434 SOCKBUF_LOCK(&so->so_rcv);
michael@0 1435 if (sbreserve_locked(&so->so_snd, sndcc, so, td) == 0)
michael@0 1436 goto bad;
michael@0 1437 if (sbreserve_locked(&so->so_rcv, rcvcc, so, td) == 0)
michael@0 1438 goto bad2;
michael@0 1439 if (so->so_rcv.sb_lowat == 0)
michael@0 1440 so->so_rcv.sb_lowat = 1;
michael@0 1441 if (so->so_snd.sb_lowat == 0)
michael@0 1442 so->so_snd.sb_lowat = MCLBYTES;
michael@0 1443 if (so->so_snd.sb_lowat > so->so_snd.sb_hiwat)
michael@0 1444 so->so_snd.sb_lowat = so->so_snd.sb_hiwat;
michael@0 1445 SOCKBUF_UNLOCK(&so->so_rcv);
michael@0 1446 SOCKBUF_UNLOCK(&so->so_snd);
michael@0 1447 return (0);
michael@0 1448 bad2:
michael@0 1449 sbrelease_locked(&so->so_snd, so);
michael@0 1450 bad:
michael@0 1451 SOCKBUF_UNLOCK(&so->so_rcv);
michael@0 1452 SOCKBUF_UNLOCK(&so->so_snd);
michael@0 1453 return (ENOBUFS);
michael@0 1454 }
michael@0 1455 #endif
michael@0 1456
michael@0 1457
michael@0 1458
michael@0 1459
michael@0 1460
michael@0 1461 /* Taken from /src/sys/kern/uipc_sockbuf.c
michael@0 1462 * and modified for __Userspace__
michael@0 1463 */
michael@0 1464
michael@0 1465 #if defined(__Userspace__)
michael@0 1466 void
michael@0 1467 sowakeup(struct socket *so, struct sockbuf *sb)
michael@0 1468 {
michael@0 1469
michael@0 1470 SOCKBUF_LOCK_ASSERT(sb);
michael@0 1471
michael@0 1472 sb->sb_flags &= ~SB_SEL;
michael@0 1473 if (sb->sb_flags & SB_WAIT) {
michael@0 1474 sb->sb_flags &= ~SB_WAIT;
michael@0 1475 #if defined (__Userspace_os_Windows)
michael@0 1476 WakeAllConditionVariable(&(sb)->sb_cond);
michael@0 1477 #else
michael@0 1478 pthread_cond_broadcast(&(sb)->sb_cond);
michael@0 1479 #endif
michael@0 1480 }
michael@0 1481 SOCKBUF_UNLOCK(sb);
michael@0 1482 /*__Userspace__ what todo about so_upcall?*/
michael@0 1483
michael@0 1484 }
michael@0 1485 #else /* kernel version for reference */
michael@0 1486 /*
michael@0 1487 * Wakeup processes waiting on a socket buffer. Do asynchronous notification
michael@0 1488 * via SIGIO if the socket has the SS_ASYNC flag set.
michael@0 1489 *
michael@0 1490 * Called with the socket buffer lock held; will release the lock by the end
michael@0 1491 * of the function. This allows the caller to acquire the socket buffer lock
michael@0 1492 * while testing for the need for various sorts of wakeup and hold it through
michael@0 1493 * to the point where it's no longer required. We currently hold the lock
michael@0 1494 * through calls out to other subsystems (with the exception of kqueue), and
michael@0 1495 * then release it to avoid lock order issues. It's not clear that's
michael@0 1496 * correct.
michael@0 1497 */
michael@0 1498 void
michael@0 1499 sowakeup(struct socket *so, struct sockbuf *sb)
michael@0 1500 {
michael@0 1501
michael@0 1502 SOCKBUF_LOCK_ASSERT(sb);
michael@0 1503
michael@0 1504 selwakeuppri(&sb->sb_sel, PSOCK);
michael@0 1505 sb->sb_flags &= ~SB_SEL;
michael@0 1506 if (sb->sb_flags & SB_WAIT) {
michael@0 1507 sb->sb_flags &= ~SB_WAIT;
michael@0 1508 wakeup(&sb->sb_cc);
michael@0 1509 }
michael@0 1510 KNOTE_LOCKED(&sb->sb_sel.si_note, 0);
michael@0 1511 SOCKBUF_UNLOCK(sb);
michael@0 1512 if ((so->so_state & SS_ASYNC) && so->so_sigio != NULL)
michael@0 1513 pgsigio(&so->so_sigio, SIGIO, 0);
michael@0 1514 if (sb->sb_flags & SB_UPCALL)
michael@0 1515 (*so->so_upcall)(so, so->so_upcallarg, M_NOWAIT);
michael@0 1516 if (sb->sb_flags & SB_AIO)
michael@0 1517 aio_swake(so, sb);
michael@0 1518 mtx_assert(SOCKBUF_MTX(sb), MA_NOTOWNED);
michael@0 1519 }
michael@0 1520 #endif
michael@0 1521
michael@0 1522
michael@0 1523
michael@0 1524 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 1525 * and modified for __Userspace__
michael@0 1526 */
michael@0 1527
michael@0 1528 int
michael@0 1529 sobind(struct socket *so, struct sockaddr *nam)
michael@0 1530 {
michael@0 1531 switch (nam->sa_family) {
michael@0 1532 #if defined(INET)
michael@0 1533 case AF_INET:
michael@0 1534 return (sctp_bind(so, nam));
michael@0 1535 #endif
michael@0 1536 #if defined(INET6)
michael@0 1537 case AF_INET6:
michael@0 1538 return (sctp6_bind(so, nam, NULL));
michael@0 1539 #endif
michael@0 1540 case AF_CONN:
michael@0 1541 return (sctpconn_bind(so, nam));
michael@0 1542 default:
michael@0 1543 return EAFNOSUPPORT;
michael@0 1544 }
michael@0 1545 }
michael@0 1546
michael@0 1547 /* Taken from /src/sys/kern/uipc_syscalls.c
michael@0 1548 * and modified for __Userspace__
michael@0 1549 */
michael@0 1550
michael@0 1551 int
michael@0 1552 usrsctp_bind(struct socket *so, struct sockaddr *name, int namelen)
michael@0 1553 {
michael@0 1554 struct sockaddr *sa;
michael@0 1555
michael@0 1556 if (so == NULL) {
michael@0 1557 errno = EBADF;
michael@0 1558 return (-1);
michael@0 1559 }
michael@0 1560 if ((errno = getsockaddr(&sa, (caddr_t)name, namelen)) != 0)
michael@0 1561 return (-1);
michael@0 1562
michael@0 1563 errno = sobind(so, sa);
michael@0 1564 FREE(sa, M_SONAME);
michael@0 1565 if (errno) {
michael@0 1566 return (-1);
michael@0 1567 } else {
michael@0 1568 return (0);
michael@0 1569 }
michael@0 1570 }
michael@0 1571
michael@0 1572 int
michael@0 1573 userspace_bind(struct socket *so, struct sockaddr *name, int namelen)
michael@0 1574 {
michael@0 1575 return (usrsctp_bind(so, name, namelen));
michael@0 1576 }
michael@0 1577
michael@0 1578 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 1579 * and modified for __Userspace__
michael@0 1580 */
michael@0 1581
michael@0 1582 int
michael@0 1583 solisten(struct socket *so, int backlog)
michael@0 1584 {
michael@0 1585 if (so == NULL) {
michael@0 1586 return (EBADF);
michael@0 1587 } else {
michael@0 1588 return (sctp_listen(so, backlog, NULL));
michael@0 1589 }
michael@0 1590 }
michael@0 1591
michael@0 1592
michael@0 1593 int
michael@0 1594 solisten_proto_check(struct socket *so)
michael@0 1595 {
michael@0 1596
michael@0 1597 SOCK_LOCK_ASSERT(so);
michael@0 1598
michael@0 1599 if (so->so_state & (SS_ISCONNECTED | SS_ISCONNECTING |
michael@0 1600 SS_ISDISCONNECTING))
michael@0 1601 return (EINVAL);
michael@0 1602 return (0);
michael@0 1603 }
michael@0 1604
michael@0 1605 static int somaxconn = SOMAXCONN;
michael@0 1606
michael@0 1607 void
michael@0 1608 solisten_proto(struct socket *so, int backlog)
michael@0 1609 {
michael@0 1610
michael@0 1611 SOCK_LOCK_ASSERT(so);
michael@0 1612
michael@0 1613 if (backlog < 0 || backlog > somaxconn)
michael@0 1614 backlog = somaxconn;
michael@0 1615 so->so_qlimit = backlog;
michael@0 1616 so->so_options |= SCTP_SO_ACCEPTCONN;
michael@0 1617 }
michael@0 1618
michael@0 1619
michael@0 1620
michael@0 1621
michael@0 1622 /* Taken from /src/sys/kern/uipc_syscalls.c
michael@0 1623 * and modified for __Userspace__
michael@0 1624 */
michael@0 1625
michael@0 1626 int
michael@0 1627 usrsctp_listen(struct socket *so, int backlog)
michael@0 1628 {
michael@0 1629 errno = solisten(so, backlog);
michael@0 1630 if (errno) {
michael@0 1631 return (-1);
michael@0 1632 } else {
michael@0 1633 return (0);
michael@0 1634 }
michael@0 1635 }
michael@0 1636
michael@0 1637 int
michael@0 1638 userspace_listen(struct socket *so, int backlog)
michael@0 1639 {
michael@0 1640 return (usrsctp_listen(so, backlog));
michael@0 1641 }
michael@0 1642
michael@0 1643 /* Taken from /src/sys/kern/uipc_socket.c
michael@0 1644 * and modified for __Userspace__
michael@0 1645 */
michael@0 1646
michael@0 1647 int
michael@0 1648 soaccept(struct socket *so, struct sockaddr **nam)
michael@0 1649 {
michael@0 1650 int error;
michael@0 1651
michael@0 1652 SOCK_LOCK(so);
michael@0 1653 KASSERT((so->so_state & SS_NOFDREF) != 0, ("soaccept: !NOFDREF"));
michael@0 1654 so->so_state &= ~SS_NOFDREF;
michael@0 1655 SOCK_UNLOCK(so);
michael@0 1656 error = sctp_accept(so, nam);
michael@0 1657 return (error);
michael@0 1658 }
michael@0 1659
michael@0 1660
michael@0 1661
michael@0 1662 /* Taken from /src/sys/kern/uipc_syscalls.c
michael@0 1663 * kern_accept modified for __Userspace__
michael@0 1664 */
michael@0 1665 int
michael@0 1666 user_accept(struct socket *head, struct sockaddr **name, socklen_t *namelen, struct socket **ptr_accept_ret_sock)
michael@0 1667 {
michael@0 1668 struct sockaddr *sa = NULL;
michael@0 1669 int error;
michael@0 1670 struct socket *so = NULL;
michael@0 1671
michael@0 1672
michael@0 1673 if (name) {
michael@0 1674 *name = NULL;
michael@0 1675 }
michael@0 1676
michael@0 1677 if ((head->so_options & SCTP_SO_ACCEPTCONN) == 0) {
michael@0 1678 error = EINVAL;
michael@0 1679 goto done;
michael@0 1680 }
michael@0 1681
michael@0 1682 ACCEPT_LOCK();
michael@0 1683 if ((head->so_state & SS_NBIO) && TAILQ_EMPTY(&head->so_comp)) {
michael@0 1684 ACCEPT_UNLOCK();
michael@0 1685 error = EWOULDBLOCK;
michael@0 1686 goto noconnection;
michael@0 1687 }
michael@0 1688 while (TAILQ_EMPTY(&head->so_comp) && head->so_error == 0) {
michael@0 1689 if (head->so_rcv.sb_state & SBS_CANTRCVMORE) {
michael@0 1690 head->so_error = ECONNABORTED;
michael@0 1691 break;
michael@0 1692 }
michael@0 1693 #if defined (__Userspace_os_Windows)
michael@0 1694 if (SleepConditionVariableCS(&accept_cond, &accept_mtx, INFINITE))
michael@0 1695 error = 0;
michael@0 1696 else
michael@0 1697 error = GetLastError();
michael@0 1698 #else
michael@0 1699 error = pthread_cond_wait(&accept_cond, &accept_mtx);
michael@0 1700 #endif
michael@0 1701 if (error) {
michael@0 1702 ACCEPT_UNLOCK();
michael@0 1703 goto noconnection;
michael@0 1704 }
michael@0 1705 }
michael@0 1706 if (head->so_error) {
michael@0 1707 error = head->so_error;
michael@0 1708 head->so_error = 0;
michael@0 1709 ACCEPT_UNLOCK();
michael@0 1710 goto noconnection;
michael@0 1711 }
michael@0 1712 so = TAILQ_FIRST(&head->so_comp);
michael@0 1713 KASSERT(!(so->so_qstate & SQ_INCOMP), ("accept1: so SQ_INCOMP"));
michael@0 1714 KASSERT(so->so_qstate & SQ_COMP, ("accept1: so not SQ_COMP"));
michael@0 1715
michael@0 1716 /*
michael@0 1717 * Before changing the flags on the socket, we have to bump the
michael@0 1718 * reference count. Otherwise, if the protocol calls sofree(),
michael@0 1719 * the socket will be released due to a zero refcount.
michael@0 1720 */
michael@0 1721 SOCK_LOCK(so); /* soref() and so_state update */
michael@0 1722 soref(so); /* file descriptor reference */
michael@0 1723
michael@0 1724 TAILQ_REMOVE(&head->so_comp, so, so_list);
michael@0 1725 head->so_qlen--;
michael@0 1726 so->so_state |= (head->so_state & SS_NBIO);
michael@0 1727 so->so_qstate &= ~SQ_COMP;
michael@0 1728 so->so_head = NULL;
michael@0 1729 SOCK_UNLOCK(so);
michael@0 1730 ACCEPT_UNLOCK();
michael@0 1731
michael@0 1732
michael@0 1733 /*
michael@0 1734 * The original accept returns fd value via td->td_retval[0] = fd;
michael@0 1735 * we will return the socket for accepted connection.
michael@0 1736 */
michael@0 1737
michael@0 1738 error = soaccept(so, &sa);
michael@0 1739 if (error) {
michael@0 1740 /*
michael@0 1741 * return a namelen of zero for older code which might
michael@0 1742 * ignore the return value from accept.
michael@0 1743 */
michael@0 1744 if (name)
michael@0 1745 *namelen = 0;
michael@0 1746 goto noconnection;
michael@0 1747 }
michael@0 1748 if (sa == NULL) {
michael@0 1749 if (name)
michael@0 1750 *namelen = 0;
michael@0 1751 goto done;
michael@0 1752 }
michael@0 1753 if (name) {
michael@0 1754 #ifdef HAVE_SA_LEN
michael@0 1755 /* check sa_len before it is destroyed */
michael@0 1756 if (*namelen > sa->sa_len) {
michael@0 1757 *namelen = sa->sa_len;
michael@0 1758 }
michael@0 1759 #else
michael@0 1760 socklen_t sa_len;
michael@0 1761
michael@0 1762 switch (sa->sa_family) {
michael@0 1763 #ifdef INET
michael@0 1764 case AF_INET:
michael@0 1765 sa_len = sizeof(struct sockaddr_in);
michael@0 1766 break;
michael@0 1767 #endif
michael@0 1768 #ifdef INET6
michael@0 1769 case AF_INET6:
michael@0 1770 sa_len = sizeof(struct sockaddr_in6);
michael@0 1771 break;
michael@0 1772 #endif
michael@0 1773 case AF_CONN:
michael@0 1774 sa_len = sizeof(struct sockaddr_conn);
michael@0 1775 break;
michael@0 1776 default:
michael@0 1777 sa_len = 0;
michael@0 1778 break;
michael@0 1779 }
michael@0 1780 if (*namelen > sa_len) {
michael@0 1781 *namelen = sa_len;
michael@0 1782 }
michael@0 1783 #endif
michael@0 1784 *name = sa;
michael@0 1785 sa = NULL;
michael@0 1786 }
michael@0 1787 noconnection:
michael@0 1788 if (sa) {
michael@0 1789 FREE(sa, M_SONAME);
michael@0 1790 }
michael@0 1791
michael@0 1792 done:
michael@0 1793 *ptr_accept_ret_sock = so;
michael@0 1794 return (error);
michael@0 1795 }
michael@0 1796
michael@0 1797
michael@0 1798
michael@0 1799 /* Taken from /src/sys/kern/uipc_syscalls.c
michael@0 1800 * and modified for __Userspace__
michael@0 1801 */
michael@0 1802 /*
michael@0 1803 * accept1()
michael@0 1804 */
michael@0 1805 static int
michael@0 1806 accept1(struct socket *so, struct sockaddr *aname, socklen_t *anamelen, struct socket **ptr_accept_ret_sock)
michael@0 1807 {
michael@0 1808 struct sockaddr *name;
michael@0 1809 socklen_t namelen;
michael@0 1810 int error;
michael@0 1811
michael@0 1812 if (so == NULL) {
michael@0 1813 return (EBADF);
michael@0 1814 }
michael@0 1815 if (aname == NULL) {
michael@0 1816 return (user_accept(so, NULL, NULL, ptr_accept_ret_sock));
michael@0 1817 }
michael@0 1818
michael@0 1819 error = copyin(anamelen, &namelen, sizeof (namelen));
michael@0 1820 if (error)
michael@0 1821 return (error);
michael@0 1822
michael@0 1823 error = user_accept(so, &name, &namelen, ptr_accept_ret_sock);
michael@0 1824
michael@0 1825 /*
michael@0 1826 * return a namelen of zero for older code which might
michael@0 1827 * ignore the return value from accept.
michael@0 1828 */
michael@0 1829 if (error) {
michael@0 1830 (void) copyout(&namelen,
michael@0 1831 anamelen, sizeof(*anamelen));
michael@0 1832 return (error);
michael@0 1833 }
michael@0 1834
michael@0 1835 if (error == 0 && name != NULL) {
michael@0 1836 error = copyout(name, aname, namelen);
michael@0 1837 }
michael@0 1838 if (error == 0) {
michael@0 1839 error = copyout(&namelen, anamelen, sizeof(namelen));
michael@0 1840 }
michael@0 1841
michael@0 1842 if (name) {
michael@0 1843 FREE(name, M_SONAME);
michael@0 1844 }
michael@0 1845 return (error);
michael@0 1846 }
michael@0 1847
michael@0 1848 struct socket *
michael@0 1849 usrsctp_accept(struct socket *so, struct sockaddr *aname, socklen_t *anamelen)
michael@0 1850 {
michael@0 1851 struct socket *accept_return_sock;
michael@0 1852
michael@0 1853 errno = accept1(so, aname, anamelen, &accept_return_sock);
michael@0 1854 if (errno) {
michael@0 1855 return (NULL);
michael@0 1856 } else {
michael@0 1857 return (accept_return_sock);
michael@0 1858 }
michael@0 1859 }
michael@0 1860
michael@0 1861 struct socket *
michael@0 1862 userspace_accept(struct socket *so, struct sockaddr *aname, socklen_t *anamelen)
michael@0 1863 {
michael@0 1864 return (usrsctp_accept(so, aname, anamelen));
michael@0 1865 }
michael@0 1866
michael@0 1867 struct socket *
michael@0 1868 usrsctp_peeloff(struct socket *head, sctp_assoc_t id)
michael@0 1869 {
michael@0 1870 struct socket *so;
michael@0 1871
michael@0 1872 if ((errno = sctp_can_peel_off(head, id)) != 0) {
michael@0 1873 return (NULL);
michael@0 1874 }
michael@0 1875 if ((so = sonewconn(head, SS_ISCONNECTED)) == NULL) {
michael@0 1876 return (NULL);
michael@0 1877 }
michael@0 1878 ACCEPT_LOCK();
michael@0 1879 SOCK_LOCK(so);
michael@0 1880 soref(so);
michael@0 1881 TAILQ_REMOVE(&head->so_comp, so, so_list);
michael@0 1882 head->so_qlen--;
michael@0 1883 so->so_state |= (head->so_state & SS_NBIO);
michael@0 1884 so->so_qstate &= ~SQ_COMP;
michael@0 1885 so->so_head = NULL;
michael@0 1886 SOCK_UNLOCK(so);
michael@0 1887 ACCEPT_UNLOCK();
michael@0 1888 if ((errno = sctp_do_peeloff(head, so, id)) != 0) {
michael@0 1889 so->so_count = 0;
michael@0 1890 sodealloc(so);
michael@0 1891 return (NULL);
michael@0 1892 }
michael@0 1893 return (so);
michael@0 1894 }
michael@0 1895
michael@0 1896 int
michael@0 1897 sodisconnect(struct socket *so)
michael@0 1898 {
michael@0 1899 int error;
michael@0 1900
michael@0 1901 if ((so->so_state & SS_ISCONNECTED) == 0)
michael@0 1902 return (ENOTCONN);
michael@0 1903 if (so->so_state & SS_ISDISCONNECTING)
michael@0 1904 return (EALREADY);
michael@0 1905 error = sctp_disconnect(so);
michael@0 1906 return (error);
michael@0 1907 }
michael@0 1908
michael@0 1909 int
michael@0 1910 usrsctp_set_non_blocking(struct socket *so, int onoff)
michael@0 1911 {
michael@0 1912 if (so == NULL) {
michael@0 1913 errno = EBADF;
michael@0 1914 return (-1);
michael@0 1915 }
michael@0 1916 SOCK_LOCK(so);
michael@0 1917 if (onoff != 0) {
michael@0 1918 so->so_state |= SS_NBIO;
michael@0 1919 } else {
michael@0 1920 so->so_state &= ~SS_NBIO;
michael@0 1921 }
michael@0 1922 SOCK_UNLOCK(so);
michael@0 1923 return (0);
michael@0 1924 }
michael@0 1925
michael@0 1926 int
michael@0 1927 usrsctp_get_non_blocking(struct socket *so)
michael@0 1928 {
michael@0 1929 int result;
michael@0 1930
michael@0 1931 if (so == NULL) {
michael@0 1932 errno = EBADF;
michael@0 1933 return (-1);
michael@0 1934 }
michael@0 1935 SOCK_LOCK(so);
michael@0 1936 if (so->so_state | SS_NBIO) {
michael@0 1937 result = 1;
michael@0 1938 } else {
michael@0 1939 result = 0;
michael@0 1940 }
michael@0 1941 SOCK_UNLOCK(so);
michael@0 1942 return (result);
michael@0 1943 }
michael@0 1944
michael@0 1945 int
michael@0 1946 soconnect(struct socket *so, struct sockaddr *nam)
michael@0 1947 {
michael@0 1948 int error;
michael@0 1949
michael@0 1950 if (so->so_options & SCTP_SO_ACCEPTCONN)
michael@0 1951 return (EOPNOTSUPP);
michael@0 1952 /*
michael@0 1953 * If protocol is connection-based, can only connect once.
michael@0 1954 * Otherwise, if connected, try to disconnect first. This allows
michael@0 1955 * user to disconnect by connecting to, e.g., a null address.
michael@0 1956 */
michael@0 1957 if (so->so_state & (SS_ISCONNECTED|SS_ISCONNECTING) && (error = sodisconnect(so))) {
michael@0 1958 error = EISCONN;
michael@0 1959 } else {
michael@0 1960 /*
michael@0 1961 * Prevent accumulated error from previous connection from
michael@0 1962 * biting us.
michael@0 1963 */
michael@0 1964 so->so_error = 0;
michael@0 1965 switch (nam->sa_family) {
michael@0 1966 #if defined(INET)
michael@0 1967 case AF_INET:
michael@0 1968 error = sctp_connect(so, nam);
michael@0 1969 break;
michael@0 1970 #endif
michael@0 1971 #if defined(INET6)
michael@0 1972 case AF_INET6:
michael@0 1973 error = sctp6_connect(so, nam);
michael@0 1974 break;
michael@0 1975 #endif
michael@0 1976 case AF_CONN:
michael@0 1977 error = sctpconn_connect(so, nam);
michael@0 1978 break;
michael@0 1979 default:
michael@0 1980 error = EAFNOSUPPORT;
michael@0 1981 }
michael@0 1982 }
michael@0 1983
michael@0 1984 return (error);
michael@0 1985 }
michael@0 1986
michael@0 1987
michael@0 1988
michael@0 1989 int user_connect(struct socket *so, struct sockaddr *sa)
michael@0 1990 {
michael@0 1991 int error;
michael@0 1992 int interrupted = 0;
michael@0 1993
michael@0 1994 if (so == NULL) {
michael@0 1995 error = EBADF;
michael@0 1996 goto done1;
michael@0 1997 }
michael@0 1998 if (so->so_state & SS_ISCONNECTING) {
michael@0 1999 error = EALREADY;
michael@0 2000 goto done1;
michael@0 2001 }
michael@0 2002
michael@0 2003 error = soconnect(so, sa);
michael@0 2004 if (error) {
michael@0 2005 goto bad;
michael@0 2006 }
michael@0 2007 if ((so->so_state & SS_NBIO) && (so->so_state & SS_ISCONNECTING)) {
michael@0 2008 error = EINPROGRESS;
michael@0 2009 goto done1;
michael@0 2010 }
michael@0 2011
michael@0 2012 SOCK_LOCK(so);
michael@0 2013 while ((so->so_state & SS_ISCONNECTING) && so->so_error == 0) {
michael@0 2014 #if defined (__Userspace_os_Windows)
michael@0 2015 if (SleepConditionVariableCS(SOCK_COND(so), SOCK_MTX(so), INFINITE))
michael@0 2016 error = 0;
michael@0 2017 else
michael@0 2018 error = -1;
michael@0 2019 #else
michael@0 2020 error = pthread_cond_wait(SOCK_COND(so), SOCK_MTX(so));
michael@0 2021 #endif
michael@0 2022 if (error) {
michael@0 2023 #if defined(__Userspace_os_NetBSD)
michael@0 2024 if (error == EINTR) {
michael@0 2025 #else
michael@0 2026 if (error == EINTR || error == ERESTART) {
michael@0 2027 #endif
michael@0 2028 interrupted = 1;
michael@0 2029 }
michael@0 2030 break;
michael@0 2031 }
michael@0 2032 }
michael@0 2033 if (error == 0) {
michael@0 2034 error = so->so_error;
michael@0 2035 so->so_error = 0;
michael@0 2036 }
michael@0 2037 SOCK_UNLOCK(so);
michael@0 2038
michael@0 2039 bad:
michael@0 2040 if (!interrupted) {
michael@0 2041 so->so_state &= ~SS_ISCONNECTING;
michael@0 2042 }
michael@0 2043 #if !defined(__Userspace_os_NetBSD)
michael@0 2044 if (error == ERESTART) {
michael@0 2045 error = EINTR;
michael@0 2046 }
michael@0 2047 #endif
michael@0 2048 done1:
michael@0 2049 return (error);
michael@0 2050 }
michael@0 2051
michael@0 2052 int usrsctp_connect(struct socket *so, struct sockaddr *name, int namelen)
michael@0 2053 {
michael@0 2054 struct sockaddr *sa;
michael@0 2055
michael@0 2056 errno = getsockaddr(&sa, (caddr_t)name, namelen);
michael@0 2057 if (errno)
michael@0 2058 return (-1);
michael@0 2059
michael@0 2060 errno = user_connect(so, sa);
michael@0 2061 FREE(sa, M_SONAME);
michael@0 2062 if (errno) {
michael@0 2063 return (-1);
michael@0 2064 } else {
michael@0 2065 return (0);
michael@0 2066 }
michael@0 2067 }
michael@0 2068
michael@0 2069 int userspace_connect(struct socket *so, struct sockaddr *name, int namelen)
michael@0 2070 {
michael@0 2071 return (usrsctp_connect(so, name, namelen));
michael@0 2072 }
michael@0 2073
michael@0 2074 #define SCTP_STACK_BUF_SIZE 2048
michael@0 2075
michael@0 2076 void
michael@0 2077 usrsctp_close(struct socket *so) {
michael@0 2078 if (so != NULL) {
michael@0 2079 if (so->so_options & SCTP_SO_ACCEPTCONN) {
michael@0 2080 struct socket *sp;
michael@0 2081
michael@0 2082 ACCEPT_LOCK();
michael@0 2083 while ((sp = TAILQ_FIRST(&so->so_comp)) != NULL) {
michael@0 2084 TAILQ_REMOVE(&so->so_comp, sp, so_list);
michael@0 2085 so->so_qlen--;
michael@0 2086 sp->so_qstate &= ~SQ_COMP;
michael@0 2087 sp->so_head = NULL;
michael@0 2088 ACCEPT_UNLOCK();
michael@0 2089 soabort(sp);
michael@0 2090 ACCEPT_LOCK();
michael@0 2091 }
michael@0 2092 ACCEPT_UNLOCK();
michael@0 2093 }
michael@0 2094 ACCEPT_LOCK();
michael@0 2095 SOCK_LOCK(so);
michael@0 2096 sorele(so);
michael@0 2097 }
michael@0 2098 }
michael@0 2099
michael@0 2100 void
michael@0 2101 userspace_close(struct socket *so)
michael@0 2102 {
michael@0 2103 usrsctp_close(so);
michael@0 2104 }
michael@0 2105
michael@0 2106 int
michael@0 2107 usrsctp_shutdown(struct socket *so, int how)
michael@0 2108 {
michael@0 2109 if (!(how == SHUT_RD || how == SHUT_WR || how == SHUT_RDWR)) {
michael@0 2110 errno = EINVAL;
michael@0 2111 return (-1);
michael@0 2112 }
michael@0 2113 if (so == NULL) {
michael@0 2114 errno = EBADF;
michael@0 2115 return (-1);
michael@0 2116 }
michael@0 2117 sctp_flush(so, how);
michael@0 2118 if (how != SHUT_WR)
michael@0 2119 socantrcvmore(so);
michael@0 2120 if (how != SHUT_RD) {
michael@0 2121 errno = sctp_shutdown(so);
michael@0 2122 if (errno) {
michael@0 2123 return (-1);
michael@0 2124 } else {
michael@0 2125 return (0);
michael@0 2126 }
michael@0 2127 }
michael@0 2128 return (0);
michael@0 2129 }
michael@0 2130
michael@0 2131 int
michael@0 2132 userspace_shutdown(struct socket *so, int how)
michael@0 2133 {
michael@0 2134 return (usrsctp_shutdown(so, how));
michael@0 2135 }
michael@0 2136
michael@0 2137 int
michael@0 2138 usrsctp_finish(void)
michael@0 2139 {
michael@0 2140 if (SCTP_BASE_VAR(sctp_pcb_initialized) == 0) {
michael@0 2141 return (0);
michael@0 2142 }
michael@0 2143 if (SCTP_INP_INFO_TRYLOCK()) {
michael@0 2144 if (!LIST_EMPTY(&SCTP_BASE_INFO(listhead))) {
michael@0 2145 SCTP_INP_INFO_RUNLOCK();
michael@0 2146 return (-1);
michael@0 2147 }
michael@0 2148 SCTP_INP_INFO_RUNLOCK();
michael@0 2149 } else {
michael@0 2150 return (-1);
michael@0 2151 }
michael@0 2152 sctp_finish();
michael@0 2153 return (0);
michael@0 2154 }
michael@0 2155
michael@0 2156 int
michael@0 2157 userspace_finish(void)
michael@0 2158 {
michael@0 2159 return (usrsctp_finish());
michael@0 2160 }
michael@0 2161
michael@0 2162 /* needed from sctp_usrreq.c */
michael@0 2163 int
michael@0 2164 sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, void *p);
michael@0 2165
michael@0 2166 int
michael@0 2167 usrsctp_setsockopt(struct socket *so, int level, int option_name,
michael@0 2168 const void *option_value, socklen_t option_len)
michael@0 2169 {
michael@0 2170 if (so == NULL) {
michael@0 2171 errno = EBADF;
michael@0 2172 return (-1);
michael@0 2173 }
michael@0 2174 switch (level) {
michael@0 2175 case SOL_SOCKET:
michael@0 2176 {
michael@0 2177 switch (option_name) {
michael@0 2178 case SO_RCVBUF:
michael@0 2179 if (option_len < (socklen_t)sizeof(int)) {
michael@0 2180 errno = EINVAL;
michael@0 2181 return (-1);
michael@0 2182 } else {
michael@0 2183 int *buf_size;
michael@0 2184
michael@0 2185 buf_size = (int *)option_value;
michael@0 2186 if (*buf_size < 1) {
michael@0 2187 errno = EINVAL;
michael@0 2188 return (-1);
michael@0 2189 }
michael@0 2190 sbreserve(&so->so_rcv, (u_long)*buf_size, so);
michael@0 2191 return (0);
michael@0 2192 }
michael@0 2193 break;
michael@0 2194 case SO_SNDBUF:
michael@0 2195 if (option_len < (socklen_t)sizeof(int)) {
michael@0 2196 errno = EINVAL;
michael@0 2197 return (-1);
michael@0 2198 } else {
michael@0 2199 int *buf_size;
michael@0 2200
michael@0 2201 buf_size = (int *)option_value;
michael@0 2202 if (*buf_size < 1) {
michael@0 2203 errno = EINVAL;
michael@0 2204 return (-1);
michael@0 2205 }
michael@0 2206 sbreserve(&so->so_snd, (u_long)*buf_size, so);
michael@0 2207 return (0);
michael@0 2208 }
michael@0 2209 break;
michael@0 2210 case SO_LINGER:
michael@0 2211 if (option_len < (socklen_t)sizeof(struct linger)) {
michael@0 2212 errno = EINVAL;
michael@0 2213 return (-1);
michael@0 2214 } else {
michael@0 2215 struct linger *l;
michael@0 2216
michael@0 2217 l = (struct linger *)option_value;
michael@0 2218 so->so_linger = l->l_linger;
michael@0 2219 if (l->l_onoff) {
michael@0 2220 so->so_options |= SCTP_SO_LINGER;
michael@0 2221 } else {
michael@0 2222 so->so_options &= ~SCTP_SO_LINGER;
michael@0 2223 }
michael@0 2224 return (0);
michael@0 2225 }
michael@0 2226 default:
michael@0 2227 errno = EINVAL;
michael@0 2228 return (-1);
michael@0 2229 }
michael@0 2230 }
michael@0 2231 case IPPROTO_SCTP:
michael@0 2232 errno = sctp_setopt(so, option_name, (void *) option_value, (size_t)option_len, NULL);
michael@0 2233 if (errno) {
michael@0 2234 return (-1);
michael@0 2235 } else {
michael@0 2236 return (0);
michael@0 2237 }
michael@0 2238 default:
michael@0 2239 errno = ENOPROTOOPT;
michael@0 2240 return (-1);
michael@0 2241 }
michael@0 2242 }
michael@0 2243
michael@0 2244 int
michael@0 2245 userspace_setsockopt(struct socket *so, int level, int option_name,
michael@0 2246 const void *option_value, socklen_t option_len)
michael@0 2247 {
michael@0 2248 return (usrsctp_setsockopt(so, level, option_name, option_value, option_len));
michael@0 2249 }
michael@0 2250
michael@0 2251 /* needed from sctp_usrreq.c */
michael@0 2252 int
michael@0 2253 sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize,
michael@0 2254 void *p);
michael@0 2255
michael@0 2256 int
michael@0 2257 usrsctp_getsockopt(struct socket *so, int level, int option_name,
michael@0 2258 void *option_value, socklen_t *option_len)
michael@0 2259 {
michael@0 2260 if (so == NULL) {
michael@0 2261 errno = EBADF;
michael@0 2262 return (-1);
michael@0 2263 }
michael@0 2264 if (option_len == NULL) {
michael@0 2265 errno = EFAULT;
michael@0 2266 return (-1);
michael@0 2267 }
michael@0 2268 switch (level) {
michael@0 2269 case SOL_SOCKET:
michael@0 2270 switch (option_name) {
michael@0 2271 case SO_RCVBUF:
michael@0 2272 if (*option_len < (socklen_t)sizeof(int)) {
michael@0 2273 errno = EINVAL;
michael@0 2274 return (-1);
michael@0 2275 } else {
michael@0 2276 int *buf_size;
michael@0 2277
michael@0 2278 buf_size = (int *)option_value;
michael@0 2279 *buf_size = so->so_rcv.sb_hiwat;;
michael@0 2280 *option_len = (socklen_t)sizeof(int);
michael@0 2281 return (0);
michael@0 2282 }
michael@0 2283 break;
michael@0 2284 case SO_SNDBUF:
michael@0 2285 if (*option_len < (socklen_t)sizeof(int)) {
michael@0 2286 errno = EINVAL;
michael@0 2287 return (-1);
michael@0 2288 } else {
michael@0 2289 int *buf_size;
michael@0 2290
michael@0 2291 buf_size = (int *)option_value;
michael@0 2292 *buf_size = so->so_snd.sb_hiwat;
michael@0 2293 *option_len = (socklen_t)sizeof(int);
michael@0 2294 return (0);
michael@0 2295 }
michael@0 2296 break;
michael@0 2297 case SO_LINGER:
michael@0 2298 if (*option_len < (socklen_t)sizeof(struct linger)) {
michael@0 2299 errno = EINVAL;
michael@0 2300 return (-1);
michael@0 2301 } else {
michael@0 2302 struct linger *l;
michael@0 2303
michael@0 2304 l = (struct linger *)option_value;
michael@0 2305 l->l_linger = so->so_linger;
michael@0 2306 if (so->so_options & SCTP_SO_LINGER) {
michael@0 2307 l->l_onoff = 1;
michael@0 2308 } else {
michael@0 2309 l->l_onoff = 0;
michael@0 2310 }
michael@0 2311 *option_len = (socklen_t)sizeof(struct linger);
michael@0 2312 return (0);
michael@0 2313 }
michael@0 2314 default:
michael@0 2315 errno = EINVAL;
michael@0 2316 return (-1);
michael@0 2317 }
michael@0 2318 case IPPROTO_SCTP:
michael@0 2319 {
michael@0 2320 size_t len;
michael@0 2321
michael@0 2322 len = (size_t)*option_len;
michael@0 2323 errno = sctp_getopt(so, option_name, option_value, &len, NULL);
michael@0 2324 *option_len = (socklen_t)len;
michael@0 2325 if (errno) {
michael@0 2326 return (-1);
michael@0 2327 } else {
michael@0 2328 return (0);
michael@0 2329 }
michael@0 2330 }
michael@0 2331 default:
michael@0 2332 errno = ENOPROTOOPT;
michael@0 2333 return (-1);
michael@0 2334 }
michael@0 2335 }
michael@0 2336
michael@0 2337 int
michael@0 2338 userspace_getsockopt(struct socket *so, int level, int option_name,
michael@0 2339 void *option_value, socklen_t *option_len)
michael@0 2340 {
michael@0 2341 return (usrsctp_getsockopt(so, level, option_name, option_value, option_len));
michael@0 2342 }
michael@0 2343
michael@0 2344 int
michael@0 2345 usrsctp_bindx(struct socket *so, struct sockaddr *addrs, int addrcnt, int flags)
michael@0 2346 {
michael@0 2347 struct sctp_getaddresses *gaddrs;
michael@0 2348 struct sockaddr *sa;
michael@0 2349 #ifdef INET
michael@0 2350 struct sockaddr_in *sin;
michael@0 2351 #endif
michael@0 2352 #ifdef INET6
michael@0 2353 struct sockaddr_in6 *sin6;
michael@0 2354 #endif
michael@0 2355 int i;
michael@0 2356 size_t argsz;
michael@0 2357 #if defined(INET) || defined(INET6)
michael@0 2358 uint16_t sport = 0;
michael@0 2359 #endif
michael@0 2360
michael@0 2361 /* validate the flags */
michael@0 2362 if ((flags != SCTP_BINDX_ADD_ADDR) &&
michael@0 2363 (flags != SCTP_BINDX_REM_ADDR)) {
michael@0 2364 errno = EFAULT;
michael@0 2365 return (-1);
michael@0 2366 }
michael@0 2367 /* validate the address count and list */
michael@0 2368 if ((addrcnt <= 0) || (addrs == NULL)) {
michael@0 2369 errno = EINVAL;
michael@0 2370 return (-1);
michael@0 2371 }
michael@0 2372 /* First pre-screen the addresses */
michael@0 2373 sa = addrs;
michael@0 2374 for (i = 0; i < addrcnt; i++) {
michael@0 2375 switch (sa->sa_family) {
michael@0 2376 #ifdef INET
michael@0 2377 case AF_INET:
michael@0 2378 #ifdef HAVE_SA_LEN
michael@0 2379 if (sa->sa_len != sizeof(struct sockaddr_in)) {
michael@0 2380 errno = EINVAL;
michael@0 2381 return (-1);
michael@0 2382 }
michael@0 2383 #endif
michael@0 2384 sin = (struct sockaddr_in *)sa;
michael@0 2385 if (sin->sin_port) {
michael@0 2386 /* non-zero port, check or save */
michael@0 2387 if (sport) {
michael@0 2388 /* Check against our port */
michael@0 2389 if (sport != sin->sin_port) {
michael@0 2390 errno = EINVAL;
michael@0 2391 return (-1);
michael@0 2392 }
michael@0 2393 } else {
michael@0 2394 /* save off the port */
michael@0 2395 sport = sin->sin_port;
michael@0 2396 }
michael@0 2397 }
michael@0 2398 #ifndef HAVE_SA_LEN
michael@0 2399 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
michael@0 2400 #endif
michael@0 2401 break;
michael@0 2402 #endif
michael@0 2403 #ifdef INET6
michael@0 2404 case AF_INET6:
michael@0 2405 #ifdef HAVE_SA_LEN
michael@0 2406 if (sa->sa_len != sizeof(struct sockaddr_in6)) {
michael@0 2407 errno = EINVAL;
michael@0 2408 return (-1);
michael@0 2409 }
michael@0 2410 #endif
michael@0 2411 sin6 = (struct sockaddr_in6 *)sa;
michael@0 2412 if (sin6->sin6_port) {
michael@0 2413 /* non-zero port, check or save */
michael@0 2414 if (sport) {
michael@0 2415 /* Check against our port */
michael@0 2416 if (sport != sin6->sin6_port) {
michael@0 2417 errno = EINVAL;
michael@0 2418 return (-1);
michael@0 2419 }
michael@0 2420 } else {
michael@0 2421 /* save off the port */
michael@0 2422 sport = sin6->sin6_port;
michael@0 2423 }
michael@0 2424 }
michael@0 2425 #ifndef HAVE_SA_LEN
michael@0 2426 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
michael@0 2427 #endif
michael@0 2428 break;
michael@0 2429 #endif
michael@0 2430 default:
michael@0 2431 /* Invalid address family specified. */
michael@0 2432 errno = EAFNOSUPPORT;
michael@0 2433 return (-1);
michael@0 2434 }
michael@0 2435 #ifdef HAVE_SA_LEN
michael@0 2436 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
michael@0 2437 #endif
michael@0 2438 }
michael@0 2439 argsz = sizeof(struct sctp_getaddresses) +
michael@0 2440 sizeof(struct sockaddr_storage);
michael@0 2441 if ((gaddrs = (struct sctp_getaddresses *)malloc(argsz)) == NULL) {
michael@0 2442 errno = ENOMEM;
michael@0 2443 return (-1);
michael@0 2444 }
michael@0 2445 sa = addrs;
michael@0 2446 for (i = 0; i < addrcnt; i++) {
michael@0 2447 #ifndef HAVE_SA_LEN
michael@0 2448 size_t sa_len;
michael@0 2449 #endif
michael@0 2450 memset(gaddrs, 0, argsz);
michael@0 2451 gaddrs->sget_assoc_id = 0;
michael@0 2452 #ifdef HAVE_SA_LEN
michael@0 2453 memcpy(gaddrs->addr, sa, sa->sa_len);
michael@0 2454 if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, gaddrs, (socklen_t)argsz) != 0) {
michael@0 2455 free(gaddrs);
michael@0 2456 return (-1);
michael@0 2457 }
michael@0 2458 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
michael@0 2459 #else
michael@0 2460 switch (sa->sa_family) {
michael@0 2461 #ifdef INET
michael@0 2462 case AF_INET:
michael@0 2463 sa_len = sizeof(struct sockaddr_in);
michael@0 2464 break;
michael@0 2465 #endif
michael@0 2466 #ifdef INET6
michael@0 2467 case AF_INET6:
michael@0 2468 sa_len = sizeof(struct sockaddr_in6);
michael@0 2469 break;
michael@0 2470 #endif
michael@0 2471 default:
michael@0 2472 sa_len = 0;
michael@0 2473 break;
michael@0 2474 }
michael@0 2475 memcpy(gaddrs->addr, sa, sa_len);
michael@0 2476 /*
michael@0 2477 * Now, if there was a port mentioned, assure that the
michael@0 2478 * first address has that port to make sure it fails or
michael@0 2479 * succeeds correctly.
michael@0 2480 */
michael@0 2481 if ((i == 0) && (sport != 0)) {
michael@0 2482 switch (gaddrs->addr->sa_family) {
michael@0 2483 #ifdef INET
michael@0 2484 case AF_INET:
michael@0 2485 sin = (struct sockaddr_in *)gaddrs->addr;
michael@0 2486 sin->sin_port = sport;
michael@0 2487 break;
michael@0 2488 #endif
michael@0 2489 #ifdef INET6
michael@0 2490 case AF_INET6:
michael@0 2491 sin6 = (struct sockaddr_in6 *)gaddrs->addr;
michael@0 2492 sin6->sin6_port = sport;
michael@0 2493 break;
michael@0 2494 #endif
michael@0 2495 }
michael@0 2496 }
michael@0 2497 if (usrsctp_setsockopt(so, IPPROTO_SCTP, flags, gaddrs, (socklen_t)argsz) != 0) {
michael@0 2498 free(gaddrs);
michael@0 2499 return (-1);
michael@0 2500 }
michael@0 2501 sa = (struct sockaddr *)((caddr_t)sa + sa_len);
michael@0 2502 #endif
michael@0 2503 }
michael@0 2504 free(gaddrs);
michael@0 2505 return (0);
michael@0 2506 }
michael@0 2507
michael@0 2508 int
michael@0 2509 usrsctp_connectx(struct socket *so,
michael@0 2510 const struct sockaddr *addrs, int addrcnt,
michael@0 2511 sctp_assoc_t *id)
michael@0 2512 {
michael@0 2513 #if defined(INET) || defined(INET6)
michael@0 2514 char buf[SCTP_STACK_BUF_SIZE];
michael@0 2515 int i, ret, cnt, *aa;
michael@0 2516 char *cpto;
michael@0 2517 const struct sockaddr *at;
michael@0 2518 sctp_assoc_t *p_id;
michael@0 2519 size_t len = sizeof(int);
michael@0 2520
michael@0 2521 /* validate the address count and list */
michael@0 2522 if ((addrs == NULL) || (addrcnt <= 0)) {
michael@0 2523 errno = EINVAL;
michael@0 2524 return (-1);
michael@0 2525 }
michael@0 2526 at = addrs;
michael@0 2527 cnt = 0;
michael@0 2528 cpto = ((caddr_t)buf + sizeof(int));
michael@0 2529 /* validate all the addresses and get the size */
michael@0 2530 for (i = 0; i < addrcnt; i++) {
michael@0 2531 switch (at->sa_family) {
michael@0 2532 #ifdef INET
michael@0 2533 case AF_INET:
michael@0 2534 #ifdef HAVE_SA_LEN
michael@0 2535 if (at->sa_len != sizeof(struct sockaddr_in)) {
michael@0 2536 errno = EINVAL;
michael@0 2537 return (-1);
michael@0 2538 }
michael@0 2539 #endif
michael@0 2540 memcpy(cpto, at, sizeof(struct sockaddr_in));
michael@0 2541 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
michael@0 2542 len += sizeof(struct sockaddr_in);
michael@0 2543 at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in));
michael@0 2544 break;
michael@0 2545 #endif
michael@0 2546 #ifdef INET6
michael@0 2547 case AF_INET6:
michael@0 2548 #ifdef HAVE_SA_LEN
michael@0 2549 if (at->sa_len != sizeof(struct sockaddr_in6)) {
michael@0 2550 errno = EINVAL;
michael@0 2551 return (-1);
michael@0 2552 }
michael@0 2553 #endif
michael@0 2554 if (IN6_IS_ADDR_V4MAPPED(&((struct sockaddr_in6 *)at)->sin6_addr)) {
michael@0 2555 in6_sin6_2_sin((struct sockaddr_in *)cpto, (struct sockaddr_in6 *)at);
michael@0 2556 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in));
michael@0 2557 len += sizeof(struct sockaddr_in);
michael@0 2558 } else {
michael@0 2559 memcpy(cpto, at, sizeof(struct sockaddr_in6));
michael@0 2560 cpto = ((caddr_t)cpto + sizeof(struct sockaddr_in6));
michael@0 2561 len += sizeof(struct sockaddr_in6);
michael@0 2562 }
michael@0 2563 at = (struct sockaddr *)((caddr_t)at + sizeof(struct sockaddr_in6));
michael@0 2564 break;
michael@0 2565 #endif
michael@0 2566 default:
michael@0 2567 errno = EINVAL;
michael@0 2568 return (-1);
michael@0 2569 }
michael@0 2570 if (len > (sizeof(buf) - sizeof(int))) {
michael@0 2571 /* Never enough memory */
michael@0 2572 errno = E2BIG;
michael@0 2573 return (-1);
michael@0 2574 }
michael@0 2575 cnt++;
michael@0 2576 }
michael@0 2577 /* do we have any? */
michael@0 2578 if (cnt == 0) {
michael@0 2579 errno = EINVAL;
michael@0 2580 return (-1);
michael@0 2581 }
michael@0 2582 aa = (int *)buf;
michael@0 2583 *aa = cnt;
michael@0 2584 ret = usrsctp_setsockopt(so, IPPROTO_SCTP, SCTP_CONNECT_X, (void *)buf, (socklen_t)len);
michael@0 2585 if ((ret == 0) && id) {
michael@0 2586 p_id = (sctp_assoc_t *)buf;
michael@0 2587 *id = *p_id;
michael@0 2588 }
michael@0 2589 return (ret);
michael@0 2590 #else
michael@0 2591 errno = EINVAL;
michael@0 2592 return (-1);
michael@0 2593 #endif
michael@0 2594 }
michael@0 2595
michael@0 2596 int
michael@0 2597 usrsctp_getpaddrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs)
michael@0 2598 {
michael@0 2599 struct sctp_getaddresses *addrs;
michael@0 2600 struct sockaddr *sa;
michael@0 2601 sctp_assoc_t asoc;
michael@0 2602 caddr_t lim;
michael@0 2603 socklen_t opt_len;
michael@0 2604 int cnt;
michael@0 2605
michael@0 2606 if (raddrs == NULL) {
michael@0 2607 errno = EFAULT;
michael@0 2608 return (-1);
michael@0 2609 }
michael@0 2610 asoc = id;
michael@0 2611 opt_len = (socklen_t)sizeof(sctp_assoc_t);
michael@0 2612 if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_REMOTE_ADDR_SIZE, &asoc, &opt_len) != 0) {
michael@0 2613 return (-1);
michael@0 2614 }
michael@0 2615 /* size required is returned in 'asoc' */
michael@0 2616 opt_len = (socklen_t)((size_t)asoc + sizeof(struct sctp_getaddresses));
michael@0 2617 addrs = calloc(1, (size_t)opt_len);
michael@0 2618 if (addrs == NULL) {
michael@0 2619 errno = ENOMEM;
michael@0 2620 return (-1);
michael@0 2621 }
michael@0 2622 addrs->sget_assoc_id = id;
michael@0 2623 /* Now lets get the array of addresses */
michael@0 2624 if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_PEER_ADDRESSES, addrs, &opt_len) != 0) {
michael@0 2625 free(addrs);
michael@0 2626 return (-1);
michael@0 2627 }
michael@0 2628 *raddrs = (struct sockaddr *)&addrs->addr[0];
michael@0 2629 cnt = 0;
michael@0 2630 sa = (struct sockaddr *)&addrs->addr[0];
michael@0 2631 lim = (caddr_t)addrs + opt_len;
michael@0 2632 #ifdef HAVE_SA_LEN
michael@0 2633 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
michael@0 2634 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
michael@0 2635 #else
michael@0 2636 while ((caddr_t)sa < lim) {
michael@0 2637 switch (sa->sa_family) {
michael@0 2638 #ifdef INET
michael@0 2639 case AF_INET:
michael@0 2640 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
michael@0 2641 break;
michael@0 2642 #endif
michael@0 2643 #ifdef INET6
michael@0 2644 case AF_INET6:
michael@0 2645 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
michael@0 2646 break;
michael@0 2647 #endif
michael@0 2648 case AF_CONN:
michael@0 2649 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_conn));
michael@0 2650 break;
michael@0 2651 default:
michael@0 2652 return (cnt);
michael@0 2653 break;
michael@0 2654 }
michael@0 2655 #endif
michael@0 2656 cnt++;
michael@0 2657 }
michael@0 2658 return (cnt);
michael@0 2659 }
michael@0 2660
michael@0 2661 void
michael@0 2662 usrsctp_freepaddrs(struct sockaddr *addrs)
michael@0 2663 {
michael@0 2664 /* Take away the hidden association id */
michael@0 2665 void *fr_addr;
michael@0 2666
michael@0 2667 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
michael@0 2668 /* Now free it */
michael@0 2669 free(fr_addr);
michael@0 2670 }
michael@0 2671
michael@0 2672 int
michael@0 2673 usrsctp_getladdrs(struct socket *so, sctp_assoc_t id, struct sockaddr **raddrs)
michael@0 2674 {
michael@0 2675 struct sctp_getaddresses *addrs;
michael@0 2676 caddr_t lim;
michael@0 2677 struct sockaddr *sa;
michael@0 2678 size_t size_of_addresses;
michael@0 2679 socklen_t opt_len;
michael@0 2680 int cnt;
michael@0 2681
michael@0 2682 if (raddrs == NULL) {
michael@0 2683 errno = EFAULT;
michael@0 2684 return (-1);
michael@0 2685 }
michael@0 2686 size_of_addresses = 0;
michael@0 2687 opt_len = (socklen_t)sizeof(int);
michael@0 2688 if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDR_SIZE, &size_of_addresses, &opt_len) != 0) {
michael@0 2689 errno = ENOMEM;
michael@0 2690 return (-1);
michael@0 2691 }
michael@0 2692 if (size_of_addresses == 0) {
michael@0 2693 errno = ENOTCONN;
michael@0 2694 return (-1);
michael@0 2695 }
michael@0 2696 opt_len = (socklen_t)(size_of_addresses +
michael@0 2697 sizeof(struct sockaddr_storage) +
michael@0 2698 sizeof(struct sctp_getaddresses));
michael@0 2699 addrs = calloc(1, (size_t)opt_len);
michael@0 2700 if (addrs == NULL) {
michael@0 2701 errno = ENOMEM;
michael@0 2702 return (-1);
michael@0 2703 }
michael@0 2704 addrs->sget_assoc_id = id;
michael@0 2705 /* Now lets get the array of addresses */
michael@0 2706 if (usrsctp_getsockopt(so, IPPROTO_SCTP, SCTP_GET_LOCAL_ADDRESSES, addrs, &opt_len) != 0) {
michael@0 2707 free(addrs);
michael@0 2708 errno = ENOMEM;
michael@0 2709 return (-1);
michael@0 2710 }
michael@0 2711 *raddrs = (struct sockaddr *)&addrs->addr[0];
michael@0 2712 cnt = 0;
michael@0 2713 sa = (struct sockaddr *)&addrs->addr[0];
michael@0 2714 lim = (caddr_t)addrs + opt_len;
michael@0 2715 #ifdef HAVE_SA_LEN
michael@0 2716 while (((caddr_t)sa < lim) && (sa->sa_len > 0)) {
michael@0 2717 sa = (struct sockaddr *)((caddr_t)sa + sa->sa_len);
michael@0 2718 #else
michael@0 2719 while ((caddr_t)sa < lim) {
michael@0 2720 switch (sa->sa_family) {
michael@0 2721 #ifdef INET
michael@0 2722 case AF_INET:
michael@0 2723 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in));
michael@0 2724 break;
michael@0 2725 #endif
michael@0 2726 #ifdef INET6
michael@0 2727 case AF_INET6:
michael@0 2728 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6));
michael@0 2729 break;
michael@0 2730 #endif
michael@0 2731 case AF_CONN:
michael@0 2732 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_conn));
michael@0 2733 break;
michael@0 2734 default:
michael@0 2735 return (cnt);
michael@0 2736 break;
michael@0 2737 }
michael@0 2738 #endif
michael@0 2739 cnt++;
michael@0 2740 }
michael@0 2741 return (cnt);
michael@0 2742 }
michael@0 2743
michael@0 2744 void
michael@0 2745 usrsctp_freeladdrs(struct sockaddr *addrs)
michael@0 2746 {
michael@0 2747 /* Take away the hidden association id */
michael@0 2748 void *fr_addr;
michael@0 2749
michael@0 2750 fr_addr = (void *)((caddr_t)addrs - sizeof(sctp_assoc_t));
michael@0 2751 /* Now free it */
michael@0 2752 free(fr_addr);
michael@0 2753 }
michael@0 2754
michael@0 2755 #ifdef INET
michael@0 2756 void
michael@0 2757 sctp_userspace_ip_output(int *result, struct mbuf *o_pak,
michael@0 2758 sctp_route_t *ro, void *stcb,
michael@0 2759 uint32_t vrf_id)
michael@0 2760 {
michael@0 2761 struct mbuf *m;
michael@0 2762 struct mbuf *m_orig;
michael@0 2763 int iovcnt;
michael@0 2764 int send_len;
michael@0 2765 int len;
michael@0 2766 int send_count;
michael@0 2767 struct ip *ip;
michael@0 2768 struct udphdr *udp;
michael@0 2769 #if !defined (__Userspace_os_Windows)
michael@0 2770 int res;
michael@0 2771 #endif
michael@0 2772 struct sockaddr_in dst;
michael@0 2773 #if defined (__Userspace_os_Windows)
michael@0 2774 WSAMSG win_msg_hdr;
michael@0 2775 int win_sent_len;
michael@0 2776 WSABUF send_iovec[MAXLEN_MBUF_CHAIN];
michael@0 2777 WSABUF winbuf;
michael@0 2778 #else
michael@0 2779 struct iovec send_iovec[MAXLEN_MBUF_CHAIN];
michael@0 2780 struct msghdr msg_hdr;
michael@0 2781 #endif
michael@0 2782 int use_udp_tunneling;
michael@0 2783
michael@0 2784 *result = 0;
michael@0 2785 send_count = 0;
michael@0 2786
michael@0 2787 m = SCTP_HEADER_TO_CHAIN(o_pak);
michael@0 2788 m_orig = m;
michael@0 2789
michael@0 2790 len = sizeof(struct ip);
michael@0 2791 if (SCTP_BUF_LEN(m) < len) {
michael@0 2792 if ((m = m_pullup(m, len)) == 0) {
michael@0 2793 SCTP_PRINTF("Can not get the IP header in the first mbuf.\n");
michael@0 2794 return;
michael@0 2795 }
michael@0 2796 }
michael@0 2797 ip = mtod(m, struct ip *);
michael@0 2798 use_udp_tunneling = (ip->ip_p == IPPROTO_UDP);
michael@0 2799
michael@0 2800 if (use_udp_tunneling) {
michael@0 2801 len = sizeof(struct ip) + sizeof(struct udphdr);
michael@0 2802 if (SCTP_BUF_LEN(m) < len) {
michael@0 2803 if ((m = m_pullup(m, len)) == 0) {
michael@0 2804 SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n");
michael@0 2805 return;
michael@0 2806 }
michael@0 2807 ip = mtod(m, struct ip *);
michael@0 2808 }
michael@0 2809 udp = (struct udphdr *)(ip + 1);
michael@0 2810 } else {
michael@0 2811 udp = NULL;
michael@0 2812 }
michael@0 2813
michael@0 2814 if (!use_udp_tunneling) {
michael@0 2815 if (ip->ip_src.s_addr == INADDR_ANY) {
michael@0 2816 /* TODO get addr of outgoing interface */
michael@0 2817 SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n");
michael@0 2818 }
michael@0 2819 /* TODO need to worry about ro->ro_dst as in ip_output? */
michael@0 2820 #if defined(__Userspace_os_Linux) || defined (__Userspace_os_Windows)
michael@0 2821 /* need to put certain fields into network order for Linux */
michael@0 2822 ip->ip_len = htons(ip->ip_len);
michael@0 2823 ip->ip_off = 0;
michael@0 2824 #endif
michael@0 2825 }
michael@0 2826
michael@0 2827 memset((void *)&dst, 0, sizeof(struct sockaddr_in));
michael@0 2828 dst.sin_family = AF_INET;
michael@0 2829 dst.sin_addr.s_addr = ip->ip_dst.s_addr;
michael@0 2830 #ifdef HAVE_SIN_LEN
michael@0 2831 dst.sin_len = sizeof(struct sockaddr_in);
michael@0 2832 #endif
michael@0 2833 if (use_udp_tunneling) {
michael@0 2834 dst.sin_port = udp->uh_dport;
michael@0 2835 } else {
michael@0 2836 dst.sin_port = 0;
michael@0 2837 }
michael@0 2838
michael@0 2839 /* tweak the mbuf chain */
michael@0 2840 if (use_udp_tunneling) {
michael@0 2841 m_adj(m, sizeof(struct ip) + sizeof(struct udphdr));
michael@0 2842 }
michael@0 2843
michael@0 2844 send_len = SCTP_HEADER_LEN(m); /* length of entire packet */
michael@0 2845 send_count = 0;
michael@0 2846 for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) {
michael@0 2847 #if !defined (__Userspace_os_Windows)
michael@0 2848 send_iovec[iovcnt].iov_base = (caddr_t)m->m_data;
michael@0 2849 send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m);
michael@0 2850 send_count += send_iovec[iovcnt].iov_len;
michael@0 2851 #else
michael@0 2852 send_iovec[iovcnt].buf = (caddr_t)m->m_data;
michael@0 2853 send_iovec[iovcnt].len = SCTP_BUF_LEN(m);
michael@0 2854 send_count += send_iovec[iovcnt].len;
michael@0 2855 #endif
michael@0 2856 }
michael@0 2857
michael@0 2858 if (m != NULL) {
michael@0 2859 SCTP_PRINTF("mbuf chain couldn't be copied completely\n");
michael@0 2860 goto free_mbuf;
michael@0 2861 }
michael@0 2862
michael@0 2863 #if !defined (__Userspace_os_Windows)
michael@0 2864 msg_hdr.msg_name = (struct sockaddr *) &dst;
michael@0 2865 msg_hdr.msg_namelen = sizeof(struct sockaddr_in);
michael@0 2866 msg_hdr.msg_iov = send_iovec;
michael@0 2867 msg_hdr.msg_iovlen = iovcnt;
michael@0 2868 msg_hdr.msg_control = NULL;
michael@0 2869 msg_hdr.msg_controllen = 0;
michael@0 2870 msg_hdr.msg_flags = 0;
michael@0 2871
michael@0 2872 if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) {
michael@0 2873 if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) {
michael@0 2874 *result = errno;
michael@0 2875 }
michael@0 2876 }
michael@0 2877 if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) {
michael@0 2878 if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp), &msg_hdr, MSG_DONTWAIT)) != send_len) {
michael@0 2879 *result = errno;
michael@0 2880 }
michael@0 2881 }
michael@0 2882 #else
michael@0 2883 win_msg_hdr.name = (struct sockaddr *) &dst;
michael@0 2884 win_msg_hdr.namelen = sizeof(struct sockaddr_in);
michael@0 2885 win_msg_hdr.lpBuffers = (LPWSABUF)send_iovec;
michael@0 2886 win_msg_hdr.dwBufferCount = iovcnt;
michael@0 2887 winbuf.len = 0;
michael@0 2888 winbuf.buf = NULL;
michael@0 2889 win_msg_hdr.Control = winbuf;
michael@0 2890 win_msg_hdr.dwFlags = 0;
michael@0 2891
michael@0 2892 if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp) > -1)) {
michael@0 2893 if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
michael@0 2894 *result = WSAGetLastError();
michael@0 2895 } else if (win_sent_len != send_len) {
michael@0 2896 *result = WSAGetLastError();
michael@0 2897 }
michael@0 2898 }
michael@0 2899 if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp) > -1)) {
michael@0 2900 if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
michael@0 2901 *result = WSAGetLastError();
michael@0 2902 } else if (win_sent_len != send_len) {
michael@0 2903 *result = WSAGetLastError();
michael@0 2904 }
michael@0 2905 }
michael@0 2906 #endif
michael@0 2907 free_mbuf:
michael@0 2908 sctp_m_freem(m_orig);
michael@0 2909 }
michael@0 2910 #endif
michael@0 2911
michael@0 2912 #if defined (INET6)
michael@0 2913 void sctp_userspace_ip6_output(int *result, struct mbuf *o_pak,
michael@0 2914 struct route_in6 *ro, void *stcb,
michael@0 2915 uint32_t vrf_id)
michael@0 2916 {
michael@0 2917 struct mbuf *m;
michael@0 2918 struct mbuf *m_orig;
michael@0 2919 int iovcnt;
michael@0 2920 int send_len;
michael@0 2921 int len;
michael@0 2922 int send_count;
michael@0 2923 struct ip6_hdr *ip6;
michael@0 2924 struct udphdr *udp;
michael@0 2925 #if !defined (__Userspace_os_Windows)
michael@0 2926 int res;
michael@0 2927 #endif
michael@0 2928 struct sockaddr_in6 dst;
michael@0 2929 #if defined (__Userspace_os_Windows)
michael@0 2930 WSAMSG win_msg_hdr;
michael@0 2931 int win_sent_len;
michael@0 2932 WSABUF send_iovec[MAXLEN_MBUF_CHAIN];
michael@0 2933 WSABUF winbuf;
michael@0 2934 #else
michael@0 2935 struct iovec send_iovec[MAXLEN_MBUF_CHAIN];
michael@0 2936 struct msghdr msg_hdr;
michael@0 2937 #endif
michael@0 2938 int use_udp_tunneling;
michael@0 2939
michael@0 2940 *result = 0;
michael@0 2941 send_count = 0;
michael@0 2942
michael@0 2943 m = SCTP_HEADER_TO_CHAIN(o_pak);
michael@0 2944 m_orig = m;
michael@0 2945
michael@0 2946 len = sizeof(struct ip6_hdr);
michael@0 2947
michael@0 2948 if (SCTP_BUF_LEN(m) < len) {
michael@0 2949 if ((m = m_pullup(m, len)) == 0) {
michael@0 2950 SCTP_PRINTF("Can not get the IP header in the first mbuf.\n");
michael@0 2951 return;
michael@0 2952 }
michael@0 2953 }
michael@0 2954
michael@0 2955 ip6 = mtod(m, struct ip6_hdr *);
michael@0 2956 use_udp_tunneling = (ip6->ip6_nxt == IPPROTO_UDP);
michael@0 2957
michael@0 2958 if (use_udp_tunneling) {
michael@0 2959 len = sizeof(struct ip6_hdr) + sizeof(struct udphdr);
michael@0 2960 if (SCTP_BUF_LEN(m) < len) {
michael@0 2961 if ((m = m_pullup(m, len)) == 0) {
michael@0 2962 SCTP_PRINTF("Can not get the UDP/IP header in the first mbuf.\n");
michael@0 2963 return;
michael@0 2964 }
michael@0 2965 ip6 = mtod(m, struct ip6_hdr *);
michael@0 2966 }
michael@0 2967 udp = (struct udphdr *)(ip6 + 1);
michael@0 2968 } else {
michael@0 2969 udp = NULL;
michael@0 2970 }
michael@0 2971
michael@0 2972 if (!use_udp_tunneling) {
michael@0 2973 if (ip6->ip6_src.s6_addr == in6addr_any.s6_addr) {
michael@0 2974 /* TODO get addr of outgoing interface */
michael@0 2975 SCTP_PRINTF("Why did the SCTP implementation did not choose a source address?\n");
michael@0 2976 }
michael@0 2977 /* TODO need to worry about ro->ro_dst as in ip_output? */
michael@0 2978 #if defined(__Userspace_os_Linux) || defined (__Userspace_os_Windows)
michael@0 2979 /* need to put certain fields into network order for Linux */
michael@0 2980 ip6->ip6_plen = htons(ip6->ip6_plen);
michael@0 2981 #endif
michael@0 2982 }
michael@0 2983
michael@0 2984 memset((void *)&dst, 0, sizeof(struct sockaddr_in6));
michael@0 2985 dst.sin6_family = AF_INET6;
michael@0 2986 dst.sin6_addr = ip6->ip6_dst;
michael@0 2987 #ifdef HAVE_SIN6_LEN
michael@0 2988 dst.sin6_len = sizeof(struct sockaddr_in6);
michael@0 2989 #endif
michael@0 2990
michael@0 2991 if (use_udp_tunneling) {
michael@0 2992 dst.sin6_port = udp->uh_dport;
michael@0 2993 } else {
michael@0 2994 dst.sin6_port = 0;
michael@0 2995 }
michael@0 2996
michael@0 2997 /* tweak the mbuf chain */
michael@0 2998 if (use_udp_tunneling) {
michael@0 2999 m_adj(m, sizeof(struct ip6_hdr) + sizeof(struct udphdr));
michael@0 3000 } else {
michael@0 3001 m_adj(m, sizeof(struct ip6_hdr));
michael@0 3002 }
michael@0 3003
michael@0 3004 send_len = SCTP_HEADER_LEN(m); /* length of entire packet */
michael@0 3005 send_count = 0;
michael@0 3006 for (iovcnt = 0; m != NULL && iovcnt < MAXLEN_MBUF_CHAIN; m = m->m_next, iovcnt++) {
michael@0 3007 #if !defined (__Userspace_os_Windows)
michael@0 3008 send_iovec[iovcnt].iov_base = (caddr_t)m->m_data;
michael@0 3009 send_iovec[iovcnt].iov_len = SCTP_BUF_LEN(m);
michael@0 3010 send_count += send_iovec[iovcnt].iov_len;
michael@0 3011 #else
michael@0 3012 send_iovec[iovcnt].buf = (caddr_t)m->m_data;
michael@0 3013 send_iovec[iovcnt].len = SCTP_BUF_LEN(m);
michael@0 3014 send_count += send_iovec[iovcnt].len;
michael@0 3015 #endif
michael@0 3016 }
michael@0 3017 if (m != NULL) {
michael@0 3018 SCTP_PRINTF("mbuf chain couldn't be copied completely\n");
michael@0 3019 goto free_mbuf;
michael@0 3020 }
michael@0 3021
michael@0 3022 #if !defined (__Userspace_os_Windows)
michael@0 3023 msg_hdr.msg_name = (struct sockaddr *) &dst;
michael@0 3024 msg_hdr.msg_namelen = sizeof(struct sockaddr_in6);
michael@0 3025 msg_hdr.msg_iov = send_iovec;
michael@0 3026 msg_hdr.msg_iovlen = iovcnt;
michael@0 3027 msg_hdr.msg_control = NULL;
michael@0 3028 msg_hdr.msg_controllen = 0;
michael@0 3029 msg_hdr.msg_flags = 0;
michael@0 3030
michael@0 3031 if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) {
michael@0 3032 if ((res = sendmsg(SCTP_BASE_VAR(userspace_rawsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) {
michael@0 3033 *result = errno;
michael@0 3034 }
michael@0 3035 }
michael@0 3036 if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) {
michael@0 3037 if ((res = sendmsg(SCTP_BASE_VAR(userspace_udpsctp6), &msg_hdr, MSG_DONTWAIT)) != send_len) {
michael@0 3038 *result = errno;
michael@0 3039 }
michael@0 3040 }
michael@0 3041 #else
michael@0 3042 win_msg_hdr.name = (struct sockaddr *) &dst;
michael@0 3043 win_msg_hdr.namelen = sizeof(struct sockaddr_in6);
michael@0 3044 win_msg_hdr.lpBuffers = (LPWSABUF)send_iovec;
michael@0 3045 win_msg_hdr.dwBufferCount = iovcnt;
michael@0 3046 winbuf.len = 0;
michael@0 3047 winbuf.buf = NULL;
michael@0 3048 win_msg_hdr.Control = winbuf;
michael@0 3049 win_msg_hdr.dwFlags = 0;
michael@0 3050
michael@0 3051 if ((!use_udp_tunneling) && (SCTP_BASE_VAR(userspace_rawsctp6) > -1)) {
michael@0 3052 if (WSASendTo(SCTP_BASE_VAR(userspace_rawsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
michael@0 3053 *result = WSAGetLastError();
michael@0 3054 } else if (win_sent_len != send_len) {
michael@0 3055 *result = WSAGetLastError();
michael@0 3056 }
michael@0 3057 }
michael@0 3058 if ((use_udp_tunneling) && (SCTP_BASE_VAR(userspace_udpsctp6) > -1)) {
michael@0 3059 if (WSASendTo(SCTP_BASE_VAR(userspace_udpsctp6), (LPWSABUF) send_iovec, iovcnt, &win_sent_len, win_msg_hdr.dwFlags, win_msg_hdr.name, (int) win_msg_hdr.namelen, NULL, NULL) != 0) {
michael@0 3060 *result = WSAGetLastError();
michael@0 3061 } else if (win_sent_len != send_len) {
michael@0 3062 *result = WSAGetLastError();
michael@0 3063 }
michael@0 3064 }
michael@0 3065 #endif
michael@0 3066 free_mbuf:
michael@0 3067 sctp_m_freem(m_orig);
michael@0 3068 }
michael@0 3069 #endif
michael@0 3070
michael@0 3071 void
michael@0 3072 usrsctp_register_address(void *addr)
michael@0 3073 {
michael@0 3074 struct sockaddr_conn sconn;
michael@0 3075
michael@0 3076 memset(&sconn, 0, sizeof(struct sockaddr_conn));
michael@0 3077 sconn.sconn_family = AF_CONN;
michael@0 3078 #ifdef HAVE_SCONN_LEN
michael@0 3079 sconn.sconn_len = sizeof(struct sockaddr_conn);
michael@0 3080 #endif
michael@0 3081 sconn.sconn_port = 0;
michael@0 3082 sconn.sconn_addr = addr;
michael@0 3083 sctp_add_addr_to_vrf(SCTP_DEFAULT_VRFID,
michael@0 3084 NULL,
michael@0 3085 0xffffffff,
michael@0 3086 0,
michael@0 3087 "conn",
michael@0 3088 NULL,
michael@0 3089 (struct sockaddr *)&sconn,
michael@0 3090 0,
michael@0 3091 0);
michael@0 3092 }
michael@0 3093
michael@0 3094 void
michael@0 3095 usrsctp_deregister_address(void *addr)
michael@0 3096 {
michael@0 3097 struct sockaddr_conn sconn;
michael@0 3098
michael@0 3099 memset(&sconn, 0, sizeof(struct sockaddr_conn));
michael@0 3100 sconn.sconn_family = AF_CONN;
michael@0 3101 #ifdef HAVE_SCONN_LEN
michael@0 3102 sconn.sconn_len = sizeof(struct sockaddr_conn);
michael@0 3103 #endif
michael@0 3104 sconn.sconn_port = 0;
michael@0 3105 sconn.sconn_addr = addr;
michael@0 3106 sctp_del_addr_from_vrf(SCTP_DEFAULT_VRFID,
michael@0 3107 (struct sockaddr *)&sconn,
michael@0 3108 0xffffffff,
michael@0 3109 "conn");
michael@0 3110 }
michael@0 3111
michael@0 3112 #define PREAMBLE_FORMAT "\n%c %02d:%02d:%02d.%06ld "
michael@0 3113 #define PREAMBLE_LENGTH 19
michael@0 3114 #define HEADER "0000 "
michael@0 3115 #define TRAILER "# SCTP_PACKET\n"
michael@0 3116
michael@0 3117 char *
michael@0 3118 usrsctp_dumppacket(void *buf, size_t len, int outbound)
michael@0 3119 {
michael@0 3120 size_t i, pos;
michael@0 3121 char *dump_buf, *packet;
michael@0 3122 #ifdef _WIN32
michael@0 3123 struct timeb tb;
michael@0 3124 struct tm t;
michael@0 3125 #else
michael@0 3126 struct timeval tv;
michael@0 3127 struct tm *t;
michael@0 3128 time_t sec;
michael@0 3129 #endif
michael@0 3130
michael@0 3131 if ((len == 0) || (buf == NULL)) {
michael@0 3132 return (NULL);
michael@0 3133 }
michael@0 3134 if ((dump_buf = malloc(PREAMBLE_LENGTH + strlen(HEADER) + 3 * len + strlen(TRAILER) + 1)) == NULL) {
michael@0 3135 return (NULL);
michael@0 3136 }
michael@0 3137 pos = 0;
michael@0 3138 #ifdef _WIN32
michael@0 3139 ftime(&tb);
michael@0 3140 localtime_s(&t, &tb.time);
michael@0 3141 _snprintf_s(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_LENGTH, PREAMBLE_FORMAT,
michael@0 3142 outbound ? 'O' : 'I',
michael@0 3143 t.tm_hour, t.tm_min, t.tm_sec, (long)(1000 * tb.millitm));
michael@0 3144 #else
michael@0 3145 gettimeofday(&tv, NULL);
michael@0 3146 sec = (time_t)tv.tv_sec;
michael@0 3147 t = localtime((const time_t *)&sec);
michael@0 3148 snprintf(dump_buf, PREAMBLE_LENGTH + 1, PREAMBLE_FORMAT,
michael@0 3149 outbound ? 'O' : 'I',
michael@0 3150 t->tm_hour, t->tm_min, t->tm_sec, (long)tv.tv_usec);
michael@0 3151 #endif
michael@0 3152 pos += PREAMBLE_LENGTH;
michael@0 3153 #ifdef _WIN32
michael@0 3154 strncpy_s(dump_buf + pos, strlen(HEADER) + 1, HEADER, strlen(HEADER));
michael@0 3155 #else
michael@0 3156 strcpy(dump_buf + pos, HEADER);
michael@0 3157 #endif
michael@0 3158 pos += strlen(HEADER);
michael@0 3159 packet = (char *)buf;
michael@0 3160 for (i = 0; i < len; i++) {
michael@0 3161 uint8_t byte, low, high;
michael@0 3162
michael@0 3163 byte = (uint8_t)packet[i];
michael@0 3164 high = byte / 16;
michael@0 3165 low = byte % 16;
michael@0 3166 dump_buf[pos++] = high < 10 ? '0' + high : 'a' + (high - 10);
michael@0 3167 dump_buf[pos++] = low < 10 ? '0' + low : 'a' + (low - 10);
michael@0 3168 dump_buf[pos++] = ' ';
michael@0 3169 }
michael@0 3170 #ifdef _WIN32
michael@0 3171 strncpy_s(dump_buf + pos, strlen(TRAILER) + 1, TRAILER, strlen(TRAILER));
michael@0 3172 #else
michael@0 3173 strcpy(dump_buf + pos, TRAILER);
michael@0 3174 #endif
michael@0 3175 pos += strlen(TRAILER);
michael@0 3176 dump_buf[pos++] = '\0';
michael@0 3177 return (dump_buf);
michael@0 3178 }
michael@0 3179
michael@0 3180 void
michael@0 3181 usrsctp_freedumpbuffer(char *buf)
michael@0 3182 {
michael@0 3183 free(buf);
michael@0 3184 }
michael@0 3185
michael@0 3186 void
michael@0 3187 usrsctp_conninput(void *addr, const void *buffer, size_t length, uint8_t ecn_bits)
michael@0 3188 {
michael@0 3189 struct sockaddr_conn src, dst;
michael@0 3190 struct mbuf *m;
michael@0 3191 struct sctphdr *sh;
michael@0 3192 struct sctp_chunkhdr *ch;
michael@0 3193
michael@0 3194 SCTP_STAT_INCR(sctps_recvpackets);
michael@0 3195 SCTP_STAT_INCR_COUNTER64(sctps_inpackets);
michael@0 3196 memset(&src, 0, sizeof(struct sockaddr_conn));
michael@0 3197 src.sconn_family = AF_CONN;
michael@0 3198 #ifdef HAVE_SCONN_LEN
michael@0 3199 src.sconn_len = sizeof(struct sockaddr_conn);
michael@0 3200 #endif
michael@0 3201 src.sconn_addr = addr;
michael@0 3202 memset(&dst, 0, sizeof(struct sockaddr_conn));
michael@0 3203 dst.sconn_family = AF_CONN;
michael@0 3204 #ifdef HAVE_SCONN_LEN
michael@0 3205 dst.sconn_len = sizeof(struct sockaddr_conn);
michael@0 3206 #endif
michael@0 3207 dst.sconn_addr = addr;
michael@0 3208 if ((m = sctp_get_mbuf_for_msg(length, 1, M_NOWAIT, 0, MT_DATA)) == NULL) {
michael@0 3209 return;
michael@0 3210 }
michael@0 3211 m_copyback(m, 0, length, (caddr_t)buffer);
michael@0 3212 if (SCTP_BUF_LEN(m) < (int)(sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) {
michael@0 3213 if ((m = m_pullup(m, sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr))) == NULL) {
michael@0 3214 SCTP_STAT_INCR(sctps_hdrops);
michael@0 3215 return;
michael@0 3216 }
michael@0 3217 }
michael@0 3218 sh = mtod(m, struct sctphdr *);;
michael@0 3219 ch = (struct sctp_chunkhdr *)((caddr_t)sh + sizeof(struct sctphdr));
michael@0 3220 src.sconn_port = sh->src_port;
michael@0 3221 dst.sconn_port = sh->dest_port;
michael@0 3222 sctp_common_input_processing(&m, 0, sizeof(struct sctphdr), length,
michael@0 3223 (struct sockaddr *)&src,
michael@0 3224 (struct sockaddr *)&dst,
michael@0 3225 sh, ch,
michael@0 3226 #if !defined(SCTP_WITH_NO_CSUM)
michael@0 3227 1,
michael@0 3228 #endif
michael@0 3229 ecn_bits,
michael@0 3230 SCTP_DEFAULT_VRFID, 0);
michael@0 3231 if (m) {
michael@0 3232 sctp_m_freem(m);
michael@0 3233 }
michael@0 3234 return;
michael@0 3235 }
michael@0 3236
michael@0 3237
michael@0 3238 #define USRSCTP_SYSCTL_SET_DEF(__field) \
michael@0 3239 void usrsctp_sysctl_set_ ## __field(uint32_t value) { \
michael@0 3240 SCTP_BASE_SYSCTL(__field) = value; \
michael@0 3241 }
michael@0 3242
michael@0 3243 USRSCTP_SYSCTL_SET_DEF(sctp_sendspace)
michael@0 3244 USRSCTP_SYSCTL_SET_DEF(sctp_recvspace)
michael@0 3245 USRSCTP_SYSCTL_SET_DEF(sctp_auto_asconf)
michael@0 3246 USRSCTP_SYSCTL_SET_DEF(sctp_multiple_asconfs)
michael@0 3247 USRSCTP_SYSCTL_SET_DEF(sctp_ecn_enable)
michael@0 3248 USRSCTP_SYSCTL_SET_DEF(sctp_strict_sacks)
michael@0 3249 #if !defined(SCTP_WITH_NO_CSUM)
michael@0 3250 USRSCTP_SYSCTL_SET_DEF(sctp_no_csum_on_loopback)
michael@0 3251 #endif
michael@0 3252 USRSCTP_SYSCTL_SET_DEF(sctp_peer_chunk_oh)
michael@0 3253 USRSCTP_SYSCTL_SET_DEF(sctp_max_burst_default)
michael@0 3254 USRSCTP_SYSCTL_SET_DEF(sctp_max_chunks_on_queue)
michael@0 3255 USRSCTP_SYSCTL_SET_DEF(sctp_hashtblsize)
michael@0 3256 USRSCTP_SYSCTL_SET_DEF(sctp_pcbtblsize)
michael@0 3257 USRSCTP_SYSCTL_SET_DEF(sctp_min_split_point)
michael@0 3258 USRSCTP_SYSCTL_SET_DEF(sctp_chunkscale)
michael@0 3259 USRSCTP_SYSCTL_SET_DEF(sctp_delayed_sack_time_default)
michael@0 3260 USRSCTP_SYSCTL_SET_DEF(sctp_sack_freq_default)
michael@0 3261 USRSCTP_SYSCTL_SET_DEF(sctp_system_free_resc_limit)
michael@0 3262 USRSCTP_SYSCTL_SET_DEF(sctp_asoc_free_resc_limit)
michael@0 3263 USRSCTP_SYSCTL_SET_DEF(sctp_heartbeat_interval_default)
michael@0 3264 USRSCTP_SYSCTL_SET_DEF(sctp_pmtu_raise_time_default)
michael@0 3265 USRSCTP_SYSCTL_SET_DEF(sctp_shutdown_guard_time_default)
michael@0 3266 USRSCTP_SYSCTL_SET_DEF(sctp_secret_lifetime_default)
michael@0 3267 USRSCTP_SYSCTL_SET_DEF(sctp_rto_max_default)
michael@0 3268 USRSCTP_SYSCTL_SET_DEF(sctp_rto_min_default)
michael@0 3269 USRSCTP_SYSCTL_SET_DEF(sctp_rto_initial_default)
michael@0 3270 USRSCTP_SYSCTL_SET_DEF(sctp_init_rto_max_default)
michael@0 3271 USRSCTP_SYSCTL_SET_DEF(sctp_valid_cookie_life_default)
michael@0 3272 USRSCTP_SYSCTL_SET_DEF(sctp_init_rtx_max_default)
michael@0 3273 USRSCTP_SYSCTL_SET_DEF(sctp_assoc_rtx_max_default)
michael@0 3274 USRSCTP_SYSCTL_SET_DEF(sctp_path_rtx_max_default)
michael@0 3275 USRSCTP_SYSCTL_SET_DEF(sctp_add_more_threshold)
michael@0 3276 USRSCTP_SYSCTL_SET_DEF(sctp_nr_outgoing_streams_default)
michael@0 3277 USRSCTP_SYSCTL_SET_DEF(sctp_cmt_on_off)
michael@0 3278 USRSCTP_SYSCTL_SET_DEF(sctp_cmt_use_dac)
michael@0 3279 USRSCTP_SYSCTL_SET_DEF(sctp_nr_sack_on_off)
michael@0 3280 USRSCTP_SYSCTL_SET_DEF(sctp_use_cwnd_based_maxburst)
michael@0 3281 USRSCTP_SYSCTL_SET_DEF(sctp_asconf_auth_nochk)
michael@0 3282 USRSCTP_SYSCTL_SET_DEF(sctp_auth_disable)
michael@0 3283 USRSCTP_SYSCTL_SET_DEF(sctp_nat_friendly)
michael@0 3284 USRSCTP_SYSCTL_SET_DEF(sctp_L2_abc_variable)
michael@0 3285 USRSCTP_SYSCTL_SET_DEF(sctp_mbuf_threshold_count)
michael@0 3286 USRSCTP_SYSCTL_SET_DEF(sctp_do_drain)
michael@0 3287 USRSCTP_SYSCTL_SET_DEF(sctp_hb_maxburst)
michael@0 3288 USRSCTP_SYSCTL_SET_DEF(sctp_abort_if_one_2_one_hits_limit)
michael@0 3289 USRSCTP_SYSCTL_SET_DEF(sctp_strict_data_order)
michael@0 3290 USRSCTP_SYSCTL_SET_DEF(sctp_min_residual)
michael@0 3291 USRSCTP_SYSCTL_SET_DEF(sctp_max_retran_chunk)
michael@0 3292 USRSCTP_SYSCTL_SET_DEF(sctp_logging_level)
michael@0 3293 USRSCTP_SYSCTL_SET_DEF(sctp_default_cc_module)
michael@0 3294 USRSCTP_SYSCTL_SET_DEF(sctp_default_frag_interleave)
michael@0 3295 USRSCTP_SYSCTL_SET_DEF(sctp_mobility_base)
michael@0 3296 USRSCTP_SYSCTL_SET_DEF(sctp_mobility_fasthandoff)
michael@0 3297 USRSCTP_SYSCTL_SET_DEF(sctp_inits_include_nat_friendly)
michael@0 3298 USRSCTP_SYSCTL_SET_DEF(sctp_udp_tunneling_port)
michael@0 3299 USRSCTP_SYSCTL_SET_DEF(sctp_enable_sack_immediately)
michael@0 3300 USRSCTP_SYSCTL_SET_DEF(sctp_vtag_time_wait)
michael@0 3301 USRSCTP_SYSCTL_SET_DEF(sctp_blackhole)
michael@0 3302 USRSCTP_SYSCTL_SET_DEF(sctp_fr_max_burst_default)
michael@0 3303 USRSCTP_SYSCTL_SET_DEF(sctp_path_pf_threshold)
michael@0 3304 USRSCTP_SYSCTL_SET_DEF(sctp_default_ss_module)
michael@0 3305 USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_bw)
michael@0 3306 USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_rtt)
michael@0 3307 USRSCTP_SYSCTL_SET_DEF(sctp_rttvar_eqret)
michael@0 3308 USRSCTP_SYSCTL_SET_DEF(sctp_steady_step)
michael@0 3309 USRSCTP_SYSCTL_SET_DEF(sctp_use_dccc_ecn)
michael@0 3310 USRSCTP_SYSCTL_SET_DEF(sctp_buffer_splitting)
michael@0 3311 USRSCTP_SYSCTL_SET_DEF(sctp_initial_cwnd)
michael@0 3312 #ifdef SCTP_DEBUG
michael@0 3313 USRSCTP_SYSCTL_SET_DEF(sctp_debug_on)
michael@0 3314 #endif
michael@0 3315
michael@0 3316 #define USRSCTP_SYSCTL_GET_DEF(__field) \
michael@0 3317 uint32_t usrsctp_sysctl_get_ ## __field(void) { \
michael@0 3318 return SCTP_BASE_SYSCTL(__field); \
michael@0 3319 }
michael@0 3320
michael@0 3321 USRSCTP_SYSCTL_GET_DEF(sctp_sendspace)
michael@0 3322 USRSCTP_SYSCTL_GET_DEF(sctp_recvspace)
michael@0 3323 USRSCTP_SYSCTL_GET_DEF(sctp_auto_asconf)
michael@0 3324 USRSCTP_SYSCTL_GET_DEF(sctp_multiple_asconfs)
michael@0 3325 USRSCTP_SYSCTL_GET_DEF(sctp_ecn_enable)
michael@0 3326 USRSCTP_SYSCTL_GET_DEF(sctp_strict_sacks)
michael@0 3327 #if !defined(SCTP_WITH_NO_CSUM)
michael@0 3328 USRSCTP_SYSCTL_GET_DEF(sctp_no_csum_on_loopback)
michael@0 3329 #endif
michael@0 3330 USRSCTP_SYSCTL_GET_DEF(sctp_peer_chunk_oh)
michael@0 3331 USRSCTP_SYSCTL_GET_DEF(sctp_max_burst_default)
michael@0 3332 USRSCTP_SYSCTL_GET_DEF(sctp_max_chunks_on_queue)
michael@0 3333 USRSCTP_SYSCTL_GET_DEF(sctp_hashtblsize)
michael@0 3334 USRSCTP_SYSCTL_GET_DEF(sctp_pcbtblsize)
michael@0 3335 USRSCTP_SYSCTL_GET_DEF(sctp_min_split_point)
michael@0 3336 USRSCTP_SYSCTL_GET_DEF(sctp_chunkscale)
michael@0 3337 USRSCTP_SYSCTL_GET_DEF(sctp_delayed_sack_time_default)
michael@0 3338 USRSCTP_SYSCTL_GET_DEF(sctp_sack_freq_default)
michael@0 3339 USRSCTP_SYSCTL_GET_DEF(sctp_system_free_resc_limit)
michael@0 3340 USRSCTP_SYSCTL_GET_DEF(sctp_asoc_free_resc_limit)
michael@0 3341 USRSCTP_SYSCTL_GET_DEF(sctp_heartbeat_interval_default)
michael@0 3342 USRSCTP_SYSCTL_GET_DEF(sctp_pmtu_raise_time_default)
michael@0 3343 USRSCTP_SYSCTL_GET_DEF(sctp_shutdown_guard_time_default)
michael@0 3344 USRSCTP_SYSCTL_GET_DEF(sctp_secret_lifetime_default)
michael@0 3345 USRSCTP_SYSCTL_GET_DEF(sctp_rto_max_default)
michael@0 3346 USRSCTP_SYSCTL_GET_DEF(sctp_rto_min_default)
michael@0 3347 USRSCTP_SYSCTL_GET_DEF(sctp_rto_initial_default)
michael@0 3348 USRSCTP_SYSCTL_GET_DEF(sctp_init_rto_max_default)
michael@0 3349 USRSCTP_SYSCTL_GET_DEF(sctp_valid_cookie_life_default)
michael@0 3350 USRSCTP_SYSCTL_GET_DEF(sctp_init_rtx_max_default)
michael@0 3351 USRSCTP_SYSCTL_GET_DEF(sctp_assoc_rtx_max_default)
michael@0 3352 USRSCTP_SYSCTL_GET_DEF(sctp_path_rtx_max_default)
michael@0 3353 USRSCTP_SYSCTL_GET_DEF(sctp_add_more_threshold)
michael@0 3354 USRSCTP_SYSCTL_GET_DEF(sctp_nr_outgoing_streams_default)
michael@0 3355 USRSCTP_SYSCTL_GET_DEF(sctp_cmt_on_off)
michael@0 3356 USRSCTP_SYSCTL_GET_DEF(sctp_cmt_use_dac)
michael@0 3357 USRSCTP_SYSCTL_GET_DEF(sctp_nr_sack_on_off)
michael@0 3358 USRSCTP_SYSCTL_GET_DEF(sctp_use_cwnd_based_maxburst)
michael@0 3359 USRSCTP_SYSCTL_GET_DEF(sctp_asconf_auth_nochk)
michael@0 3360 USRSCTP_SYSCTL_GET_DEF(sctp_auth_disable)
michael@0 3361 USRSCTP_SYSCTL_GET_DEF(sctp_nat_friendly)
michael@0 3362 USRSCTP_SYSCTL_GET_DEF(sctp_L2_abc_variable)
michael@0 3363 USRSCTP_SYSCTL_GET_DEF(sctp_mbuf_threshold_count)
michael@0 3364 USRSCTP_SYSCTL_GET_DEF(sctp_do_drain)
michael@0 3365 USRSCTP_SYSCTL_GET_DEF(sctp_hb_maxburst)
michael@0 3366 USRSCTP_SYSCTL_GET_DEF(sctp_abort_if_one_2_one_hits_limit)
michael@0 3367 USRSCTP_SYSCTL_GET_DEF(sctp_strict_data_order)
michael@0 3368 USRSCTP_SYSCTL_GET_DEF(sctp_min_residual)
michael@0 3369 USRSCTP_SYSCTL_GET_DEF(sctp_max_retran_chunk)
michael@0 3370 USRSCTP_SYSCTL_GET_DEF(sctp_logging_level)
michael@0 3371 USRSCTP_SYSCTL_GET_DEF(sctp_default_cc_module)
michael@0 3372 USRSCTP_SYSCTL_GET_DEF(sctp_default_frag_interleave)
michael@0 3373 USRSCTP_SYSCTL_GET_DEF(sctp_mobility_base)
michael@0 3374 USRSCTP_SYSCTL_GET_DEF(sctp_mobility_fasthandoff)
michael@0 3375 USRSCTP_SYSCTL_GET_DEF(sctp_inits_include_nat_friendly)
michael@0 3376 USRSCTP_SYSCTL_GET_DEF(sctp_udp_tunneling_port)
michael@0 3377 USRSCTP_SYSCTL_GET_DEF(sctp_enable_sack_immediately)
michael@0 3378 USRSCTP_SYSCTL_GET_DEF(sctp_vtag_time_wait)
michael@0 3379 USRSCTP_SYSCTL_GET_DEF(sctp_blackhole)
michael@0 3380 USRSCTP_SYSCTL_GET_DEF(sctp_fr_max_burst_default)
michael@0 3381 USRSCTP_SYSCTL_GET_DEF(sctp_path_pf_threshold)
michael@0 3382 USRSCTP_SYSCTL_GET_DEF(sctp_default_ss_module)
michael@0 3383 USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_bw)
michael@0 3384 USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_rtt)
michael@0 3385 USRSCTP_SYSCTL_GET_DEF(sctp_rttvar_eqret)
michael@0 3386 USRSCTP_SYSCTL_GET_DEF(sctp_steady_step)
michael@0 3387 USRSCTP_SYSCTL_GET_DEF(sctp_use_dccc_ecn)
michael@0 3388 USRSCTP_SYSCTL_GET_DEF(sctp_buffer_splitting)
michael@0 3389 USRSCTP_SYSCTL_GET_DEF(sctp_initial_cwnd)
michael@0 3390 #ifdef SCTP_DEBUG
michael@0 3391 USRSCTP_SYSCTL_GET_DEF(sctp_debug_on)
michael@0 3392 #endif
michael@0 3393
michael@0 3394 void usrsctp_get_stat(struct sctpstat *stat)
michael@0 3395 {
michael@0 3396 *stat = SCTP_BASE_STATS;
michael@0 3397 }

mercurial