|
1 /*- |
|
2 * Copyright (c) 2001-2008, by Cisco Systems, Inc. All rights reserved. |
|
3 * Copyright (c) 2008-2012, by Randall Stewart. All rights reserved. |
|
4 * Copyright (c) 2008-2012, by Michael Tuexen. All rights reserved. |
|
5 * |
|
6 * Redistribution and use in source and binary forms, with or without |
|
7 * modification, are permitted provided that the following conditions are met: |
|
8 * |
|
9 * a) Redistributions of source code must retain the above copyright notice, |
|
10 * this list of conditions and the following disclaimer. |
|
11 * |
|
12 * b) Redistributions in binary form must reproduce the above copyright |
|
13 * notice, this list of conditions and the following disclaimer in |
|
14 * the documentation and/or other materials provided with the distribution. |
|
15 * |
|
16 * c) Neither the name of Cisco Systems, Inc. nor the names of its |
|
17 * contributors may be used to endorse or promote products derived |
|
18 * from this software without specific prior written permission. |
|
19 * |
|
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
|
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, |
|
22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE |
|
24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
|
25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
|
26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
|
27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
|
28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
|
29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF |
|
30 * THE POSSIBILITY OF SUCH DAMAGE. |
|
31 */ |
|
32 |
|
33 #ifdef __FreeBSD__ |
|
34 #include <sys/cdefs.h> |
|
35 __FBSDID("$FreeBSD: head/sys/netinet/sctp_usrreq.c 259943 2013-12-27 13:07:00Z tuexen $"); |
|
36 #endif |
|
37 |
|
38 #include <netinet/sctp_os.h> |
|
39 #ifdef __FreeBSD__ |
|
40 #include <sys/proc.h> |
|
41 #endif |
|
42 #include <netinet/sctp_pcb.h> |
|
43 #include <netinet/sctp_header.h> |
|
44 #include <netinet/sctp_var.h> |
|
45 #ifdef INET6 |
|
46 #if defined(__Userspace_os_FreeBSD) |
|
47 #include <netinet6/sctp6_var.h> |
|
48 #endif |
|
49 #endif |
|
50 #include <netinet/sctp_sysctl.h> |
|
51 #include <netinet/sctp_output.h> |
|
52 #include <netinet/sctp_uio.h> |
|
53 #include <netinet/sctp_asconf.h> |
|
54 #include <netinet/sctputil.h> |
|
55 #include <netinet/sctp_indata.h> |
|
56 #include <netinet/sctp_timer.h> |
|
57 #include <netinet/sctp_auth.h> |
|
58 #include <netinet/sctp_bsd_addr.h> |
|
59 #if defined(__Userspace__) |
|
60 #include <netinet/sctp_callout.h> |
|
61 #endif |
|
62 #if !defined(__Userspace_os_Windows) |
|
63 #include <netinet/udp.h> |
|
64 #endif |
|
65 |
|
66 #if defined(HAVE_SCTP_PEELOFF_SOCKOPT) |
|
67 #include <netinet/sctp_peeloff.h> |
|
68 #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ |
|
69 |
|
70 #if defined(__APPLE__) |
|
71 #define APPLE_FILE_NO 7 |
|
72 #endif |
|
73 |
|
74 extern struct sctp_cc_functions sctp_cc_functions[]; |
|
75 extern struct sctp_ss_functions sctp_ss_functions[]; |
|
76 |
|
77 void |
|
78 #if defined(__Userspace__) |
|
79 sctp_init(uint16_t port, |
|
80 int (*conn_output)(void *addr, void *buffer, size_t length, uint8_t tos, uint8_t set_df), |
|
81 void (*debug_printf)(const char *format, ...)) |
|
82 #elif defined(__APPLE__) && (!defined(APPLE_LEOPARD) && !defined(APPLE_SNOWLEOPARD) &&!defined(APPLE_LION) && !defined(APPLE_MOUNTAINLION)) |
|
83 sctp_init(struct protosw *pp SCTP_UNUSED, struct domain *dp SCTP_UNUSED) |
|
84 #else |
|
85 sctp_init(void) |
|
86 #endif |
|
87 { |
|
88 #if !defined(__Panda__) && !defined(__Userspace__) |
|
89 u_long sb_max_adj; |
|
90 |
|
91 #endif |
|
92 #if defined(__Userspace__) |
|
93 #if defined(__Userspace_os_Windows) |
|
94 #if defined(INET) || defined(INET6) |
|
95 WSADATA wsaData; |
|
96 |
|
97 if (WSAStartup(MAKEWORD(2,2), &wsaData) != 0) { |
|
98 SCTP_PRINTF("WSAStartup failed\n"); |
|
99 exit (-1); |
|
100 } |
|
101 #endif |
|
102 InitializeConditionVariable(&accept_cond); |
|
103 InitializeCriticalSection(&accept_mtx); |
|
104 #else |
|
105 pthread_cond_init(&accept_cond, NULL); |
|
106 pthread_mutex_init(&accept_mtx, NULL); |
|
107 #endif |
|
108 #endif |
|
109 /* Initialize and modify the sysctled variables */ |
|
110 sctp_init_sysctls(); |
|
111 #if defined(__Userspace__) |
|
112 #if defined(__Userspace_os_Windows) |
|
113 srand((unsigned int)time(NULL)); |
|
114 #else |
|
115 srandom(getpid()); /* so inp->sctp_ep.random_numbers are truly random... */ |
|
116 #endif |
|
117 #endif |
|
118 #if defined(__Panda__) |
|
119 sctp_sendspace = SB_MAX; |
|
120 sctp_recvspace = SB_MAX; |
|
121 |
|
122 #elif defined(__Userspace__) |
|
123 SCTP_BASE_SYSCTL(sctp_sendspace) = SB_MAX; |
|
124 SCTP_BASE_SYSCTL(sctp_recvspace) = SB_RAW; |
|
125 SCTP_BASE_SYSCTL(sctp_udp_tunneling_port) = port; |
|
126 #else |
|
127 #if !defined(__APPLE__) |
|
128 if ((nmbclusters / 8) > SCTP_ASOC_MAX_CHUNKS_ON_QUEUE) |
|
129 SCTP_BASE_SYSCTL(sctp_max_chunks_on_queue) = (nmbclusters / 8); |
|
130 #endif |
|
131 /* |
|
132 * Allow a user to take no more than 1/2 the number of clusters or |
|
133 * the SB_MAX whichever is smaller for the send window. |
|
134 */ |
|
135 #if defined(__APPLE__) |
|
136 sb_max_adj = (u_long)((u_quad_t) (sb_max) * MCLBYTES / (MSIZE + MCLBYTES)); |
|
137 #else |
|
138 sb_max_adj = (u_long)((u_quad_t) (SB_MAX) * MCLBYTES / (MSIZE + MCLBYTES)); |
|
139 #endif |
|
140 #if defined(__APPLE__) |
|
141 SCTP_BASE_SYSCTL(sctp_sendspace) = sb_max_adj; |
|
142 #else |
|
143 SCTP_BASE_SYSCTL(sctp_sendspace) = min(sb_max_adj, |
|
144 (((uint32_t)nmbclusters / 2) * SCTP_DEFAULT_MAXSEGMENT)); |
|
145 #endif |
|
146 /* |
|
147 * Now for the recv window, should we take the same amount? or |
|
148 * should I do 1/2 the SB_MAX instead in the SB_MAX min above. For |
|
149 * now I will just copy. |
|
150 */ |
|
151 SCTP_BASE_SYSCTL(sctp_recvspace) = SCTP_BASE_SYSCTL(sctp_sendspace); |
|
152 #endif |
|
153 SCTP_BASE_VAR(first_time) = 0; |
|
154 SCTP_BASE_VAR(sctp_pcb_initialized) = 0; |
|
155 #if defined(__Userspace__) |
|
156 #if !defined(__Userspace_os_Windows) |
|
157 #if defined(INET) || defined(INET6) |
|
158 SCTP_BASE_VAR(userspace_route) = -1; |
|
159 #endif |
|
160 #endif |
|
161 #ifdef INET |
|
162 SCTP_BASE_VAR(userspace_rawsctp) = -1; |
|
163 SCTP_BASE_VAR(userspace_udpsctp) = -1; |
|
164 #endif |
|
165 #ifdef INET6 |
|
166 SCTP_BASE_VAR(userspace_rawsctp6) = -1; |
|
167 SCTP_BASE_VAR(userspace_udpsctp6) = -1; |
|
168 #endif |
|
169 SCTP_BASE_VAR(timer_thread_should_exit) = 0; |
|
170 SCTP_BASE_VAR(conn_output) = conn_output; |
|
171 SCTP_BASE_VAR(debug_printf) = debug_printf; |
|
172 #endif |
|
173 sctp_pcb_init(); |
|
174 #if defined(__Userspace__) |
|
175 sctp_start_timer(); |
|
176 #endif |
|
177 #if defined(SCTP_PACKET_LOGGING) |
|
178 SCTP_BASE_VAR(packet_log_writers) = 0; |
|
179 SCTP_BASE_VAR(packet_log_end) = 0; |
|
180 bzero(&SCTP_BASE_VAR(packet_log_buffer), SCTP_PACKET_LOG_SIZE); |
|
181 #endif |
|
182 #if defined(__APPLE__) |
|
183 SCTP_BASE_VAR(sctp_main_timer_ticks) = 0; |
|
184 sctp_start_main_timer(); |
|
185 timeout(sctp_delayed_startup, NULL, 1); |
|
186 #endif |
|
187 } |
|
188 |
|
189 void |
|
190 sctp_finish(void) |
|
191 { |
|
192 #if defined(__APPLE__) |
|
193 untimeout(sctp_delayed_startup, NULL); |
|
194 sctp_over_udp_stop(); |
|
195 sctp_address_monitor_stop(); |
|
196 sctp_stop_main_timer(); |
|
197 #endif |
|
198 #if defined(__Userspace__) |
|
199 #if defined(INET) || defined(INET6) |
|
200 recv_thread_destroy(); |
|
201 #endif |
|
202 #if !defined(__Userspace_os_Windows) |
|
203 #if defined(INET) || defined(INET6) |
|
204 if (SCTP_BASE_VAR(userspace_route) != -1) { |
|
205 pthread_join(SCTP_BASE_VAR(recvthreadroute), NULL); |
|
206 } |
|
207 #endif |
|
208 #endif |
|
209 #ifdef INET |
|
210 if (SCTP_BASE_VAR(userspace_rawsctp) != -1) { |
|
211 #if defined(__Userspace_os_Windows) |
|
212 WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw), INFINITE); |
|
213 CloseHandle(SCTP_BASE_VAR(recvthreadraw)); |
|
214 #else |
|
215 pthread_join(SCTP_BASE_VAR(recvthreadraw), NULL); |
|
216 #endif |
|
217 } |
|
218 if (SCTP_BASE_VAR(userspace_udpsctp) != -1) { |
|
219 #if defined(__Userspace_os_Windows) |
|
220 WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp), INFINITE); |
|
221 CloseHandle(SCTP_BASE_VAR(recvthreadudp)); |
|
222 #else |
|
223 pthread_join(SCTP_BASE_VAR(recvthreadudp), NULL); |
|
224 #endif |
|
225 } |
|
226 #endif |
|
227 #ifdef INET6 |
|
228 if (SCTP_BASE_VAR(userspace_rawsctp6) != -1) { |
|
229 #if defined(__Userspace_os_Windows) |
|
230 WaitForSingleObject(SCTP_BASE_VAR(recvthreadraw6), INFINITE); |
|
231 CloseHandle(SCTP_BASE_VAR(recvthreadraw6)); |
|
232 #else |
|
233 pthread_join(SCTP_BASE_VAR(recvthreadraw6), NULL); |
|
234 #endif |
|
235 } |
|
236 if (SCTP_BASE_VAR(userspace_udpsctp6) != -1) { |
|
237 #if defined(__Userspace_os_Windows) |
|
238 WaitForSingleObject(SCTP_BASE_VAR(recvthreadudp6), INFINITE); |
|
239 CloseHandle(SCTP_BASE_VAR(recvthreadudp6)); |
|
240 #else |
|
241 pthread_join(SCTP_BASE_VAR(recvthreadudp6), NULL); |
|
242 #endif |
|
243 } |
|
244 #endif |
|
245 SCTP_BASE_VAR(timer_thread_should_exit) = 1; |
|
246 #if defined(__Userspace_os_Windows) |
|
247 WaitForSingleObject(SCTP_BASE_VAR(timer_thread), INFINITE); |
|
248 CloseHandle(SCTP_BASE_VAR(timer_thread)); |
|
249 #else |
|
250 pthread_join(SCTP_BASE_VAR(timer_thread), NULL); |
|
251 #endif |
|
252 #endif |
|
253 sctp_pcb_finish(); |
|
254 #if defined(__Userspace__) |
|
255 #if defined(__Userspace_os_Windows) |
|
256 DeleteConditionVariable(&accept_cond); |
|
257 DeleteCriticalSection(&accept_mtx); |
|
258 #else |
|
259 pthread_cond_destroy(&accept_cond); |
|
260 pthread_mutex_destroy(&accept_mtx); |
|
261 #endif |
|
262 #endif |
|
263 #if defined(__Windows__) |
|
264 sctp_finish_sysctls(); |
|
265 #if defined(INET) || defined(INET6) |
|
266 WSACleanup(); |
|
267 #endif |
|
268 #endif |
|
269 } |
|
270 |
|
271 |
|
272 |
|
273 void |
|
274 sctp_pathmtu_adjustment(struct sctp_tcb *stcb, uint16_t nxtsz) |
|
275 { |
|
276 struct sctp_tmit_chunk *chk; |
|
277 uint16_t overhead; |
|
278 |
|
279 /* Adjust that too */ |
|
280 stcb->asoc.smallest_mtu = nxtsz; |
|
281 /* now off to subtract IP_DF flag if needed */ |
|
282 overhead = IP_HDR_SIZE; |
|
283 if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) { |
|
284 overhead += sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); |
|
285 } |
|
286 TAILQ_FOREACH(chk, &stcb->asoc.send_queue, sctp_next) { |
|
287 if ((chk->send_size + overhead) > nxtsz) { |
|
288 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; |
|
289 } |
|
290 } |
|
291 TAILQ_FOREACH(chk, &stcb->asoc.sent_queue, sctp_next) { |
|
292 if ((chk->send_size + overhead) > nxtsz) { |
|
293 /* |
|
294 * For this guy we also mark for immediate resend |
|
295 * since we sent to big of chunk |
|
296 */ |
|
297 chk->flags |= CHUNK_FLAGS_FRAGMENT_OK; |
|
298 if (chk->sent < SCTP_DATAGRAM_RESEND) { |
|
299 sctp_flight_size_decrease(chk); |
|
300 sctp_total_flight_decrease(stcb, chk); |
|
301 } |
|
302 if (chk->sent != SCTP_DATAGRAM_RESEND) { |
|
303 sctp_ucount_incr(stcb->asoc.sent_queue_retran_cnt); |
|
304 } |
|
305 chk->sent = SCTP_DATAGRAM_RESEND; |
|
306 chk->rec.data.doing_fast_retransmit = 0; |
|
307 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_FLIGHT_LOGGING_ENABLE) { |
|
308 sctp_misc_ints(SCTP_FLIGHT_LOG_DOWN_PMTU, |
|
309 chk->whoTo->flight_size, |
|
310 chk->book_size, |
|
311 (uintptr_t)chk->whoTo, |
|
312 chk->rec.data.TSN_seq); |
|
313 } |
|
314 /* Clear any time so NO RTT is being done */ |
|
315 chk->do_rtt = 0; |
|
316 } |
|
317 } |
|
318 } |
|
319 |
|
320 #ifdef INET |
|
321 #if !defined(__Userspace__) |
|
322 #if defined(__Panda__) || defined(__Windows__) |
|
323 void |
|
324 #else |
|
325 static void |
|
326 #endif |
|
327 sctp_notify_mbuf(struct sctp_inpcb *inp, |
|
328 struct sctp_tcb *stcb, |
|
329 struct sctp_nets *net, |
|
330 struct ip *ip, |
|
331 struct sctphdr *sh) |
|
332 { |
|
333 struct icmp *icmph; |
|
334 int totsz, tmr_stopped = 0; |
|
335 uint16_t nxtsz; |
|
336 |
|
337 /* protection */ |
|
338 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || |
|
339 (ip == NULL) || (sh == NULL)) { |
|
340 if (stcb != NULL) { |
|
341 SCTP_TCB_UNLOCK(stcb); |
|
342 } |
|
343 return; |
|
344 } |
|
345 /* First job is to verify the vtag matches what I would send */ |
|
346 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { |
|
347 SCTP_TCB_UNLOCK(stcb); |
|
348 return; |
|
349 } |
|
350 icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - |
|
351 sizeof(struct ip))); |
|
352 if (icmph->icmp_type != ICMP_UNREACH) { |
|
353 /* We only care about unreachable */ |
|
354 SCTP_TCB_UNLOCK(stcb); |
|
355 return; |
|
356 } |
|
357 if (icmph->icmp_code != ICMP_UNREACH_NEEDFRAG) { |
|
358 /* not a unreachable message due to frag. */ |
|
359 SCTP_TCB_UNLOCK(stcb); |
|
360 return; |
|
361 } |
|
362 #if defined(__FreeBSD__) && __FreeBSD_version >= 1000000 |
|
363 totsz = ntohs(ip->ip_len); |
|
364 #else |
|
365 totsz = ip->ip_len; |
|
366 #endif |
|
367 |
|
368 nxtsz = ntohs(icmph->icmp_nextmtu); |
|
369 if (nxtsz == 0) { |
|
370 /* |
|
371 * old type router that does not tell us what the next size |
|
372 * mtu is. Rats we will have to guess (in a educated fashion |
|
373 * of course) |
|
374 */ |
|
375 nxtsz = sctp_get_prev_mtu(totsz); |
|
376 } |
|
377 /* Stop any PMTU timer */ |
|
378 if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { |
|
379 tmr_stopped = 1; |
|
380 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, |
|
381 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_1); |
|
382 } |
|
383 /* Adjust destination size limit */ |
|
384 if (net->mtu > nxtsz) { |
|
385 net->mtu = nxtsz; |
|
386 if (net->port) { |
|
387 net->mtu -= sizeof(struct udphdr); |
|
388 } |
|
389 } |
|
390 /* now what about the ep? */ |
|
391 if (stcb->asoc.smallest_mtu > nxtsz) { |
|
392 sctp_pathmtu_adjustment(stcb, nxtsz); |
|
393 } |
|
394 if (tmr_stopped) |
|
395 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); |
|
396 |
|
397 SCTP_TCB_UNLOCK(stcb); |
|
398 } |
|
399 #endif |
|
400 #endif |
|
401 |
|
402 void |
|
403 sctp_notify(struct sctp_inpcb *inp, |
|
404 struct ip *ip, |
|
405 struct sctphdr *sh, |
|
406 struct sockaddr *to, |
|
407 struct sctp_tcb *stcb, |
|
408 struct sctp_nets *net) |
|
409 { |
|
410 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
411 struct socket *so; |
|
412 |
|
413 #endif |
|
414 struct icmp *icmph; |
|
415 |
|
416 /* protection */ |
|
417 if ((inp == NULL) || (stcb == NULL) || (net == NULL) || |
|
418 (sh == NULL) || (to == NULL)) { |
|
419 if (stcb) |
|
420 SCTP_TCB_UNLOCK(stcb); |
|
421 return; |
|
422 } |
|
423 /* First job is to verify the vtag matches what I would send */ |
|
424 if (ntohl(sh->v_tag) != (stcb->asoc.peer_vtag)) { |
|
425 SCTP_TCB_UNLOCK(stcb); |
|
426 return; |
|
427 } |
|
428 |
|
429 icmph = (struct icmp *)((caddr_t)ip - (sizeof(struct icmp) - |
|
430 sizeof(struct ip))); |
|
431 if (icmph->icmp_type != ICMP_UNREACH) { |
|
432 /* We only care about unreachable */ |
|
433 SCTP_TCB_UNLOCK(stcb); |
|
434 return; |
|
435 } |
|
436 if ((icmph->icmp_code == ICMP_UNREACH_NET) || |
|
437 (icmph->icmp_code == ICMP_UNREACH_HOST) || |
|
438 (icmph->icmp_code == ICMP_UNREACH_NET_UNKNOWN) || |
|
439 (icmph->icmp_code == ICMP_UNREACH_HOST_UNKNOWN) || |
|
440 (icmph->icmp_code == ICMP_UNREACH_ISOLATED) || |
|
441 (icmph->icmp_code == ICMP_UNREACH_NET_PROHIB) || |
|
442 (icmph->icmp_code == ICMP_UNREACH_HOST_PROHIB) || |
|
443 #if defined(__Panda__) |
|
444 (icmph->icmp_code == ICMP_UNREACH_ADMIN)) { |
|
445 #elif defined(__Userspace_os_NetBSD) |
|
446 (icmph->icmp_code == ICMP_UNREACH_ADMIN_PROHIBIT)) { |
|
447 #else |
|
448 (icmph->icmp_code == ICMP_UNREACH_FILTER_PROHIB)) { |
|
449 #endif |
|
450 |
|
451 /* |
|
452 * Hmm reachablity problems we must examine closely. If its |
|
453 * not reachable, we may have lost a network. Or if there is |
|
454 * NO protocol at the other end named SCTP. well we consider |
|
455 * it a OOTB abort. |
|
456 */ |
|
457 if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
458 /* Ok that destination is NOT reachable */ |
|
459 net->dest_state &= ~SCTP_ADDR_REACHABLE; |
|
460 net->dest_state &= ~SCTP_ADDR_PF; |
|
461 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, |
|
462 stcb, 0, |
|
463 (void *)net, SCTP_SO_NOT_LOCKED); |
|
464 } |
|
465 SCTP_TCB_UNLOCK(stcb); |
|
466 } else if ((icmph->icmp_code == ICMP_UNREACH_PROTOCOL) || |
|
467 (icmph->icmp_code == ICMP_UNREACH_PORT)) { |
|
468 /* |
|
469 * Here the peer is either playing tricks on us, |
|
470 * including an address that belongs to someone who |
|
471 * does not support SCTP OR was a userland |
|
472 * implementation that shutdown and now is dead. In |
|
473 * either case treat it like a OOTB abort with no |
|
474 * TCB |
|
475 */ |
|
476 sctp_abort_notification(stcb, 1, 0, NULL, SCTP_SO_NOT_LOCKED); |
|
477 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
478 so = SCTP_INP_SO(inp); |
|
479 atomic_add_int(&stcb->asoc.refcnt, 1); |
|
480 SCTP_TCB_UNLOCK(stcb); |
|
481 SCTP_SOCKET_LOCK(so, 1); |
|
482 SCTP_TCB_LOCK(stcb); |
|
483 atomic_subtract_int(&stcb->asoc.refcnt, 1); |
|
484 #endif |
|
485 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_2); |
|
486 #if defined(__APPLE__) || defined(SCTP_SO_LOCK_TESTING) |
|
487 SCTP_SOCKET_UNLOCK(so, 1); |
|
488 /* SCTP_TCB_UNLOCK(stcb); MT: I think this is not needed.*/ |
|
489 #endif |
|
490 /* no need to unlock here, since the TCB is gone */ |
|
491 } else { |
|
492 SCTP_TCB_UNLOCK(stcb); |
|
493 } |
|
494 } |
|
495 |
|
496 #ifdef INET |
|
497 #if !defined(__Panda__) && !defined(__Userspace__) |
|
498 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
499 void |
|
500 #else |
|
501 void * |
|
502 #endif |
|
503 sctp_ctlinput(cmd, sa, vip) |
|
504 int cmd; |
|
505 struct sockaddr *sa; |
|
506 void *vip; |
|
507 { |
|
508 struct ip *ip = vip; |
|
509 struct sctphdr *sh; |
|
510 uint32_t vrf_id; |
|
511 /* FIX, for non-bsd is this right? */ |
|
512 vrf_id = SCTP_DEFAULT_VRFID; |
|
513 if (sa->sa_family != AF_INET || |
|
514 ((struct sockaddr_in *)sa)->sin_addr.s_addr == INADDR_ANY) { |
|
515 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
516 return; |
|
517 #else |
|
518 return (NULL); |
|
519 #endif |
|
520 } |
|
521 if (PRC_IS_REDIRECT(cmd)) { |
|
522 ip = 0; |
|
523 } else if ((unsigned)cmd >= PRC_NCMDS || inetctlerrmap[cmd] == 0) { |
|
524 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
525 return; |
|
526 #else |
|
527 return (NULL); |
|
528 #endif |
|
529 } |
|
530 if (ip) { |
|
531 struct sctp_inpcb *inp = NULL; |
|
532 struct sctp_tcb *stcb = NULL; |
|
533 struct sctp_nets *net = NULL; |
|
534 struct sockaddr_in to, from; |
|
535 |
|
536 sh = (struct sctphdr *)((caddr_t)ip + (ip->ip_hl << 2)); |
|
537 bzero(&to, sizeof(to)); |
|
538 bzero(&from, sizeof(from)); |
|
539 from.sin_family = to.sin_family = AF_INET; |
|
540 #ifdef HAVE_SIN_LEN |
|
541 from.sin_len = to.sin_len = sizeof(to); |
|
542 #endif |
|
543 from.sin_port = sh->src_port; |
|
544 from.sin_addr = ip->ip_src; |
|
545 to.sin_port = sh->dest_port; |
|
546 to.sin_addr = ip->ip_dst; |
|
547 |
|
548 /* |
|
549 * 'to' holds the dest of the packet that failed to be sent. |
|
550 * 'from' holds our local endpoint address. Thus we reverse |
|
551 * the to and the from in the lookup. |
|
552 */ |
|
553 stcb = sctp_findassociation_addr_sa((struct sockaddr *)&to, |
|
554 (struct sockaddr *)&from, |
|
555 &inp, &net, 1, vrf_id); |
|
556 if (stcb != NULL && inp && (inp->sctp_socket != NULL)) { |
|
557 if (cmd != PRC_MSGSIZE) { |
|
558 sctp_notify(inp, ip, sh, |
|
559 (struct sockaddr *)&to, stcb, |
|
560 net); |
|
561 } else { |
|
562 /* handle possible ICMP size messages */ |
|
563 sctp_notify_mbuf(inp, stcb, net, ip, sh); |
|
564 } |
|
565 } else { |
|
566 #if defined(__FreeBSD__) && __FreeBSD_version < 500000 |
|
567 /* |
|
568 * XXX must be fixed for 5.x and higher, leave for |
|
569 * 4.x |
|
570 */ |
|
571 if (PRC_IS_REDIRECT(cmd) && inp) { |
|
572 in_rtchange((struct inpcb *)inp, |
|
573 inetctlerrmap[cmd]); |
|
574 } |
|
575 #endif |
|
576 if ((stcb == NULL) && (inp != NULL)) { |
|
577 /* reduce ref-count */ |
|
578 SCTP_INP_WLOCK(inp); |
|
579 SCTP_INP_DECR_REF(inp); |
|
580 SCTP_INP_WUNLOCK(inp); |
|
581 } |
|
582 if (stcb) { |
|
583 SCTP_TCB_UNLOCK(stcb); |
|
584 } |
|
585 } |
|
586 } |
|
587 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
588 return; |
|
589 #else |
|
590 return (NULL); |
|
591 #endif |
|
592 } |
|
593 #endif |
|
594 #endif |
|
595 |
|
596 #if defined(__FreeBSD__) |
|
597 static int |
|
598 sctp_getcred(SYSCTL_HANDLER_ARGS) |
|
599 { |
|
600 struct xucred xuc; |
|
601 struct sockaddr_in addrs[2]; |
|
602 struct sctp_inpcb *inp; |
|
603 struct sctp_nets *net; |
|
604 struct sctp_tcb *stcb; |
|
605 int error; |
|
606 uint32_t vrf_id; |
|
607 |
|
608 /* FIX, for non-bsd is this right? */ |
|
609 vrf_id = SCTP_DEFAULT_VRFID; |
|
610 |
|
611 #if __FreeBSD_version > 602000 |
|
612 error = priv_check(req->td, PRIV_NETINET_GETCRED); |
|
613 |
|
614 #elif __FreeBSD_version >= 500000 |
|
615 error = suser(req->td); |
|
616 #else |
|
617 error = suser(req->p); |
|
618 #endif |
|
619 if (error) |
|
620 return (error); |
|
621 |
|
622 error = SYSCTL_IN(req, addrs, sizeof(addrs)); |
|
623 if (error) |
|
624 return (error); |
|
625 |
|
626 stcb = sctp_findassociation_addr_sa(sintosa(&addrs[1]), |
|
627 sintosa(&addrs[0]), |
|
628 &inp, &net, 1, vrf_id); |
|
629 if (stcb == NULL || inp == NULL || inp->sctp_socket == NULL) { |
|
630 if ((inp != NULL) && (stcb == NULL)) { |
|
631 /* reduce ref-count */ |
|
632 SCTP_INP_WLOCK(inp); |
|
633 SCTP_INP_DECR_REF(inp); |
|
634 goto cred_can_cont; |
|
635 } |
|
636 |
|
637 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
638 error = ENOENT; |
|
639 goto out; |
|
640 } |
|
641 SCTP_TCB_UNLOCK(stcb); |
|
642 /* We use the write lock here, only |
|
643 * since in the error leg we need it. |
|
644 * If we used RLOCK, then we would have |
|
645 * to wlock/decr/unlock/rlock. Which |
|
646 * in theory could create a hole. Better |
|
647 * to use higher wlock. |
|
648 */ |
|
649 SCTP_INP_WLOCK(inp); |
|
650 cred_can_cont: |
|
651 error = cr_canseesocket(req->td->td_ucred, inp->sctp_socket); |
|
652 if (error) { |
|
653 SCTP_INP_WUNLOCK(inp); |
|
654 goto out; |
|
655 } |
|
656 cru2x(inp->sctp_socket->so_cred, &xuc); |
|
657 SCTP_INP_WUNLOCK(inp); |
|
658 error = SYSCTL_OUT(req, &xuc, sizeof(struct xucred)); |
|
659 out: |
|
660 return (error); |
|
661 } |
|
662 |
|
663 SYSCTL_PROC(_net_inet_sctp, OID_AUTO, getcred, CTLTYPE_OPAQUE | CTLFLAG_RW, |
|
664 0, 0, sctp_getcred, "S,ucred", "Get the ucred of a SCTP connection"); |
|
665 #endif /* #if defined(__FreeBSD__) */ |
|
666 |
|
667 |
|
668 #ifdef INET |
|
669 #if defined(__Panda__) || defined(__Windows__) || defined(__Userspace__) |
|
670 int |
|
671 #elif defined(__FreeBSD__) && __FreeBSD_version > 690000 |
|
672 static void |
|
673 #else |
|
674 static int |
|
675 #endif |
|
676 sctp_abort(struct socket *so) |
|
677 { |
|
678 struct sctp_inpcb *inp; |
|
679 uint32_t flags; |
|
680 |
|
681 inp = (struct sctp_inpcb *)so->so_pcb; |
|
682 if (inp == NULL) { |
|
683 #if defined(__FreeBSD__) && __FreeBSD_version > 690000 |
|
684 return; |
|
685 #else |
|
686 SCTP_LTRACE_ERR_RET(NULL, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
687 return (EINVAL); |
|
688 #endif |
|
689 } |
|
690 |
|
691 sctp_must_try_again: |
|
692 flags = inp->sctp_flags; |
|
693 #ifdef SCTP_LOG_CLOSING |
|
694 sctp_log_closing(inp, NULL, 17); |
|
695 #endif |
|
696 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
697 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { |
|
698 #ifdef SCTP_LOG_CLOSING |
|
699 sctp_log_closing(inp, NULL, 16); |
|
700 #endif |
|
701 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, |
|
702 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
703 SOCK_LOCK(so); |
|
704 SCTP_SB_CLEAR(so->so_snd); |
|
705 /* same for the rcv ones, they are only |
|
706 * here for the accounting/select. |
|
707 */ |
|
708 SCTP_SB_CLEAR(so->so_rcv); |
|
709 |
|
710 #if defined(__APPLE__) |
|
711 so->so_usecount--; |
|
712 #else |
|
713 /* Now null out the reference, we are completely detached. */ |
|
714 so->so_pcb = NULL; |
|
715 #endif |
|
716 SOCK_UNLOCK(so); |
|
717 } else { |
|
718 flags = inp->sctp_flags; |
|
719 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { |
|
720 goto sctp_must_try_again; |
|
721 } |
|
722 } |
|
723 #if defined(__FreeBSD__) && __FreeBSD_version > 690000 |
|
724 return; |
|
725 #else |
|
726 return (0); |
|
727 #endif |
|
728 } |
|
729 |
|
730 #if defined(__Panda__) || defined(__Userspace__) |
|
731 int |
|
732 #else |
|
733 static int |
|
734 #endif |
|
735 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
736 sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct thread *p SCTP_UNUSED) |
|
737 #elif defined(__Panda__) || defined(__Userspace__) |
|
738 sctp_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) |
|
739 #elif defined(__Windows__) |
|
740 sctp_attach(struct socket *so, int proto SCTP_UNUSED, PKTHREAD p SCTP_UNUSED) |
|
741 #else |
|
742 sctp_attach(struct socket *so, int proto SCTP_UNUSED, struct proc *p SCTP_UNUSED) |
|
743 #endif |
|
744 { |
|
745 struct sctp_inpcb *inp; |
|
746 struct inpcb *ip_inp; |
|
747 int error; |
|
748 #if !defined(__Panda__) && !defined(__Userspace__) |
|
749 uint32_t vrf_id = SCTP_DEFAULT_VRFID; |
|
750 #endif |
|
751 #ifdef IPSEC |
|
752 uint32_t flags; |
|
753 #endif |
|
754 |
|
755 inp = (struct sctp_inpcb *)so->so_pcb; |
|
756 if (inp != 0) { |
|
757 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
758 return (EINVAL); |
|
759 } |
|
760 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { |
|
761 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); |
|
762 if (error) { |
|
763 return (error); |
|
764 } |
|
765 } |
|
766 error = sctp_inpcb_alloc(so, vrf_id); |
|
767 if (error) { |
|
768 return (error); |
|
769 } |
|
770 inp = (struct sctp_inpcb *)so->so_pcb; |
|
771 SCTP_INP_WLOCK(inp); |
|
772 inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; /* I'm not v6! */ |
|
773 ip_inp = &inp->ip_inp.inp; |
|
774 ip_inp->inp_vflag |= INP_IPV4; |
|
775 ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); |
|
776 #ifdef IPSEC |
|
777 #if !(defined(__APPLE__)) |
|
778 error = ipsec_init_policy(so, &ip_inp->inp_sp); |
|
779 #ifdef SCTP_LOG_CLOSING |
|
780 sctp_log_closing(inp, NULL, 17); |
|
781 #endif |
|
782 if (error != 0) { |
|
783 try_again: |
|
784 flags = inp->sctp_flags; |
|
785 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
786 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { |
|
787 #ifdef SCTP_LOG_CLOSING |
|
788 sctp_log_closing(inp, NULL, 15); |
|
789 #endif |
|
790 SCTP_INP_WUNLOCK(inp); |
|
791 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, |
|
792 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
793 } else { |
|
794 flags = inp->sctp_flags; |
|
795 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { |
|
796 goto try_again; |
|
797 } else { |
|
798 SCTP_INP_WUNLOCK(inp); |
|
799 } |
|
800 } |
|
801 return (error); |
|
802 } |
|
803 #endif |
|
804 #endif /* IPSEC */ |
|
805 SCTP_INP_WUNLOCK(inp); |
|
806 return (0); |
|
807 } |
|
808 |
|
809 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
810 static int |
|
811 sctp_bind(struct socket *so, struct sockaddr *addr, struct thread *p) |
|
812 { |
|
813 #elif defined(__FreeBSD__) || defined(__APPLE__) |
|
814 static int |
|
815 sctp_bind(struct socket *so, struct sockaddr *addr, struct proc *p) { |
|
816 #elif defined(__Panda__) || defined(__Userspace__) |
|
817 int |
|
818 sctp_bind(struct socket *so, struct sockaddr *addr) { |
|
819 void *p = NULL; |
|
820 #elif defined(__Windows__) |
|
821 static int |
|
822 sctp_bind(struct socket *so, struct sockaddr *addr, PKTHREAD p) { |
|
823 #else |
|
824 static int |
|
825 sctp_bind(struct socket *so, struct mbuf *nam, struct proc *p) |
|
826 { |
|
827 struct sockaddr *addr = nam ? mtod(nam, struct sockaddr *): NULL; |
|
828 |
|
829 #endif |
|
830 struct sctp_inpcb *inp; |
|
831 |
|
832 inp = (struct sctp_inpcb *)so->so_pcb; |
|
833 if (inp == NULL) { |
|
834 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
835 return (EINVAL); |
|
836 } |
|
837 if (addr != NULL) { |
|
838 #ifdef HAVE_SA_LEN |
|
839 if ((addr->sa_family != AF_INET) || |
|
840 (addr->sa_len != sizeof(struct sockaddr_in))) { |
|
841 #else |
|
842 if (addr->sa_family != AF_INET) { |
|
843 #endif |
|
844 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
845 return (EINVAL); |
|
846 } |
|
847 } |
|
848 return (sctp_inpcb_bind(so, addr, NULL, p)); |
|
849 } |
|
850 |
|
851 #endif |
|
852 #if defined(__Userspace__) |
|
853 |
|
854 int |
|
855 sctpconn_attach(struct socket *so, int proto SCTP_UNUSED, uint32_t vrf_id) |
|
856 { |
|
857 struct sctp_inpcb *inp; |
|
858 struct inpcb *ip_inp; |
|
859 int error; |
|
860 |
|
861 inp = (struct sctp_inpcb *)so->so_pcb; |
|
862 if (inp != NULL) { |
|
863 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
864 return (EINVAL); |
|
865 } |
|
866 if (so->so_snd.sb_hiwat == 0 || so->so_rcv.sb_hiwat == 0) { |
|
867 error = SCTP_SORESERVE(so, SCTP_BASE_SYSCTL(sctp_sendspace), SCTP_BASE_SYSCTL(sctp_recvspace)); |
|
868 if (error) { |
|
869 return (error); |
|
870 } |
|
871 } |
|
872 error = sctp_inpcb_alloc(so, vrf_id); |
|
873 if (error) { |
|
874 return (error); |
|
875 } |
|
876 inp = (struct sctp_inpcb *)so->so_pcb; |
|
877 SCTP_INP_WLOCK(inp); |
|
878 inp->sctp_flags &= ~SCTP_PCB_FLAGS_BOUND_V6; |
|
879 inp->sctp_flags |= SCTP_PCB_FLAGS_BOUND_CONN; |
|
880 ip_inp = &inp->ip_inp.inp; |
|
881 ip_inp->inp_vflag |= INP_CONN; |
|
882 ip_inp->inp_ip_ttl = MODULE_GLOBAL(ip_defttl); |
|
883 SCTP_INP_WUNLOCK(inp); |
|
884 return (0); |
|
885 } |
|
886 |
|
887 int |
|
888 sctpconn_bind(struct socket *so, struct sockaddr *addr) |
|
889 { |
|
890 struct sctp_inpcb *inp; |
|
891 |
|
892 inp = (struct sctp_inpcb *)so->so_pcb; |
|
893 if (inp == NULL) { |
|
894 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
895 return (EINVAL); |
|
896 } |
|
897 if (addr != NULL) { |
|
898 #ifdef HAVE_SA_LEN |
|
899 if ((addr->sa_family != AF_CONN) || |
|
900 (addr->sa_len != sizeof(struct sockaddr_conn))) { |
|
901 #else |
|
902 if (addr->sa_family != AF_CONN) { |
|
903 #endif |
|
904 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
905 return (EINVAL); |
|
906 } |
|
907 } |
|
908 return (sctp_inpcb_bind(so, addr, NULL, NULL)); |
|
909 } |
|
910 |
|
911 #endif |
|
912 #if (defined(__FreeBSD__) && __FreeBSD_version > 690000) || defined(__Windows__) || defined(__Userspace__) |
|
913 void |
|
914 sctp_close(struct socket *so) |
|
915 { |
|
916 struct sctp_inpcb *inp; |
|
917 uint32_t flags; |
|
918 |
|
919 inp = (struct sctp_inpcb *)so->so_pcb; |
|
920 if (inp == NULL) |
|
921 return; |
|
922 |
|
923 /* Inform all the lower layer assoc that we |
|
924 * are done. |
|
925 */ |
|
926 sctp_must_try_again: |
|
927 flags = inp->sctp_flags; |
|
928 #ifdef SCTP_LOG_CLOSING |
|
929 sctp_log_closing(inp, NULL, 17); |
|
930 #endif |
|
931 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
932 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { |
|
933 #if defined(__Userspace__) |
|
934 if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || |
|
935 (so->so_rcv.sb_cc > 0)) { |
|
936 #else |
|
937 if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || |
|
938 (so->so_rcv.sb_cc > 0)) { |
|
939 #endif |
|
940 #ifdef SCTP_LOG_CLOSING |
|
941 sctp_log_closing(inp, NULL, 13); |
|
942 #endif |
|
943 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, |
|
944 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
945 } else { |
|
946 #ifdef SCTP_LOG_CLOSING |
|
947 sctp_log_closing(inp, NULL, 14); |
|
948 #endif |
|
949 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, |
|
950 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
951 } |
|
952 /* The socket is now detached, no matter what |
|
953 * the state of the SCTP association. |
|
954 */ |
|
955 SOCK_LOCK(so); |
|
956 SCTP_SB_CLEAR(so->so_snd); |
|
957 /* same for the rcv ones, they are only |
|
958 * here for the accounting/select. |
|
959 */ |
|
960 SCTP_SB_CLEAR(so->so_rcv); |
|
961 |
|
962 #if !defined(__APPLE__) |
|
963 /* Now null out the reference, we are completely detached. */ |
|
964 so->so_pcb = NULL; |
|
965 #endif |
|
966 SOCK_UNLOCK(so); |
|
967 } else { |
|
968 flags = inp->sctp_flags; |
|
969 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { |
|
970 goto sctp_must_try_again; |
|
971 } |
|
972 } |
|
973 return; |
|
974 } |
|
975 |
|
976 #else |
|
977 |
|
978 |
|
979 int |
|
980 sctp_detach(struct socket *so) |
|
981 { |
|
982 struct sctp_inpcb *inp; |
|
983 uint32_t flags; |
|
984 |
|
985 inp = (struct sctp_inpcb *)so->so_pcb; |
|
986 if (inp == NULL) { |
|
987 #if defined(__FreeBSD__) && __FreeBSD_version > 690000 |
|
988 return; |
|
989 #else |
|
990 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
991 return (EINVAL); |
|
992 #endif |
|
993 } |
|
994 sctp_must_try_again: |
|
995 flags = inp->sctp_flags; |
|
996 #ifdef SCTP_LOG_CLOSING |
|
997 sctp_log_closing(inp, NULL, 17); |
|
998 #endif |
|
999 if (((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
1000 (atomic_cmpset_int(&inp->sctp_flags, flags, (flags | SCTP_PCB_FLAGS_SOCKET_GONE | SCTP_PCB_FLAGS_CLOSE_IP)))) { |
|
1001 #if defined(__Userspace__) |
|
1002 if (((so->so_options & SCTP_SO_LINGER) && (so->so_linger == 0)) || |
|
1003 (so->so_rcv.sb_cc > 0)) { |
|
1004 #else |
|
1005 if (((so->so_options & SO_LINGER) && (so->so_linger == 0)) || |
|
1006 (so->so_rcv.sb_cc > 0)) { |
|
1007 #endif |
|
1008 #ifdef SCTP_LOG_CLOSING |
|
1009 sctp_log_closing(inp, NULL, 13); |
|
1010 #endif |
|
1011 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_ABORT, |
|
1012 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
1013 } else { |
|
1014 #ifdef SCTP_LOG_CLOSING |
|
1015 sctp_log_closing(inp, NULL, 13); |
|
1016 #endif |
|
1017 sctp_inpcb_free(inp, SCTP_FREE_SHOULD_USE_GRACEFUL_CLOSE, |
|
1018 SCTP_CALLED_AFTER_CMPSET_OFCLOSE); |
|
1019 } |
|
1020 /* The socket is now detached, no matter what |
|
1021 * the state of the SCTP association. |
|
1022 */ |
|
1023 SCTP_SB_CLEAR(so->so_snd); |
|
1024 /* same for the rcv ones, they are only |
|
1025 * here for the accounting/select. |
|
1026 */ |
|
1027 SCTP_SB_CLEAR(so->so_rcv); |
|
1028 #if !defined(__APPLE__) |
|
1029 /* Now disconnect */ |
|
1030 so->so_pcb = NULL; |
|
1031 #endif |
|
1032 } else { |
|
1033 flags = inp->sctp_flags; |
|
1034 if ((flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) { |
|
1035 goto sctp_must_try_again; |
|
1036 } |
|
1037 } |
|
1038 #if defined(__FreeBSD__) && __FreeBSD_version > 690000 |
|
1039 return; |
|
1040 #else |
|
1041 return (0); |
|
1042 #endif |
|
1043 } |
|
1044 #endif |
|
1045 |
|
1046 #if defined(__Userspace__) |
|
1047 /* __Userspace__ is not calling sctp_sendm */ |
|
1048 #endif |
|
1049 #if !(defined(__Panda__) || defined(__Windows__)) |
|
1050 int |
|
1051 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
1052 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, |
|
1053 struct mbuf *control, struct thread *p); |
|
1054 |
|
1055 #else |
|
1056 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, |
|
1057 struct mbuf *control, struct proc *p); |
|
1058 |
|
1059 #endif |
|
1060 |
|
1061 int |
|
1062 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
1063 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, |
|
1064 struct mbuf *control, struct thread *p) |
|
1065 { |
|
1066 #else |
|
1067 sctp_sendm(struct socket *so, int flags, struct mbuf *m, struct sockaddr *addr, |
|
1068 struct mbuf *control, struct proc *p) |
|
1069 { |
|
1070 #endif |
|
1071 struct sctp_inpcb *inp; |
|
1072 int error; |
|
1073 |
|
1074 inp = (struct sctp_inpcb *)so->so_pcb; |
|
1075 if (inp == NULL) { |
|
1076 if (control) { |
|
1077 sctp_m_freem(control); |
|
1078 control = NULL; |
|
1079 } |
|
1080 SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
1081 sctp_m_freem(m); |
|
1082 return (EINVAL); |
|
1083 } |
|
1084 /* Got to have an to address if we are NOT a connected socket */ |
|
1085 if ((addr == NULL) && |
|
1086 ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) || |
|
1087 (inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE))) { |
|
1088 goto connected_type; |
|
1089 } else if (addr == NULL) { |
|
1090 SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); |
|
1091 error = EDESTADDRREQ; |
|
1092 sctp_m_freem(m); |
|
1093 if (control) { |
|
1094 sctp_m_freem(control); |
|
1095 control = NULL; |
|
1096 } |
|
1097 return (error); |
|
1098 } |
|
1099 #ifdef INET6 |
|
1100 if (addr->sa_family != AF_INET) { |
|
1101 /* must be a v4 address! */ |
|
1102 SCTP_LTRACE_ERR_RET_PKT(m, inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EDESTADDRREQ); |
|
1103 sctp_m_freem(m); |
|
1104 if (control) { |
|
1105 sctp_m_freem(control); |
|
1106 control = NULL; |
|
1107 } |
|
1108 error = EDESTADDRREQ; |
|
1109 return (error); |
|
1110 } |
|
1111 #endif /* INET6 */ |
|
1112 connected_type: |
|
1113 /* now what about control */ |
|
1114 if (control) { |
|
1115 if (inp->control) { |
|
1116 SCTP_PRINTF("huh? control set?\n"); |
|
1117 sctp_m_freem(inp->control); |
|
1118 inp->control = NULL; |
|
1119 } |
|
1120 inp->control = control; |
|
1121 } |
|
1122 /* Place the data */ |
|
1123 if (inp->pkt) { |
|
1124 SCTP_BUF_NEXT(inp->pkt_last) = m; |
|
1125 inp->pkt_last = m; |
|
1126 } else { |
|
1127 inp->pkt_last = inp->pkt = m; |
|
1128 } |
|
1129 if ( |
|
1130 #if defined(__FreeBSD__) || defined(__APPLE__) |
|
1131 /* FreeBSD uses a flag passed */ |
|
1132 ((flags & PRUS_MORETOCOME) == 0) |
|
1133 #else |
|
1134 1 /* Open BSD does not have any "more to come" |
|
1135 * indication */ |
|
1136 #endif |
|
1137 ) { |
|
1138 /* |
|
1139 * note with the current version this code will only be used |
|
1140 * by OpenBSD-- NetBSD, FreeBSD, and MacOS have methods for |
|
1141 * re-defining sosend to use the sctp_sosend. One can |
|
1142 * optionally switch back to this code (by changing back the |
|
1143 * definitions) but this is not advisable. This code is used |
|
1144 * by FreeBSD when sending a file with sendfile() though. |
|
1145 */ |
|
1146 int ret; |
|
1147 |
|
1148 ret = sctp_output(inp, inp->pkt, addr, inp->control, p, flags); |
|
1149 inp->pkt = NULL; |
|
1150 inp->control = NULL; |
|
1151 return (ret); |
|
1152 } else { |
|
1153 return (0); |
|
1154 } |
|
1155 } |
|
1156 #endif |
|
1157 |
|
1158 int |
|
1159 sctp_disconnect(struct socket *so) |
|
1160 { |
|
1161 struct sctp_inpcb *inp; |
|
1162 |
|
1163 inp = (struct sctp_inpcb *)so->so_pcb; |
|
1164 if (inp == NULL) { |
|
1165 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); |
|
1166 return (ENOTCONN); |
|
1167 } |
|
1168 SCTP_INP_RLOCK(inp); |
|
1169 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
1170 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
1171 if (LIST_EMPTY(&inp->sctp_asoc_list)) { |
|
1172 /* No connection */ |
|
1173 SCTP_INP_RUNLOCK(inp); |
|
1174 return (0); |
|
1175 } else { |
|
1176 struct sctp_association *asoc; |
|
1177 struct sctp_tcb *stcb; |
|
1178 |
|
1179 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
1180 if (stcb == NULL) { |
|
1181 SCTP_INP_RUNLOCK(inp); |
|
1182 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
1183 return (EINVAL); |
|
1184 } |
|
1185 SCTP_TCB_LOCK(stcb); |
|
1186 asoc = &stcb->asoc; |
|
1187 if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { |
|
1188 /* We are about to be freed, out of here */ |
|
1189 SCTP_TCB_UNLOCK(stcb); |
|
1190 SCTP_INP_RUNLOCK(inp); |
|
1191 return (0); |
|
1192 } |
|
1193 #if defined(__Userspace__) |
|
1194 if (((so->so_options & SCTP_SO_LINGER) && |
|
1195 (so->so_linger == 0)) || |
|
1196 (so->so_rcv.sb_cc > 0)) { |
|
1197 #else |
|
1198 if (((so->so_options & SO_LINGER) && |
|
1199 (so->so_linger == 0)) || |
|
1200 (so->so_rcv.sb_cc > 0)) { |
|
1201 #endif |
|
1202 if (SCTP_GET_STATE(asoc) != |
|
1203 SCTP_STATE_COOKIE_WAIT) { |
|
1204 /* Left with Data unread */ |
|
1205 struct mbuf *err; |
|
1206 |
|
1207 err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), 0, M_NOWAIT, 1, MT_DATA); |
|
1208 if (err) { |
|
1209 /* |
|
1210 * Fill in the user |
|
1211 * initiated abort |
|
1212 */ |
|
1213 struct sctp_paramhdr *ph; |
|
1214 |
|
1215 ph = mtod(err, struct sctp_paramhdr *); |
|
1216 SCTP_BUF_LEN(err) = sizeof(struct sctp_paramhdr); |
|
1217 ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); |
|
1218 ph->param_length = htons(SCTP_BUF_LEN(err)); |
|
1219 } |
|
1220 sctp_send_abort_tcb(stcb, err, SCTP_SO_LOCKED); |
|
1221 SCTP_STAT_INCR_COUNTER32(sctps_aborted); |
|
1222 } |
|
1223 SCTP_INP_RUNLOCK(inp); |
|
1224 if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || |
|
1225 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
1226 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
1227 } |
|
1228 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_3); |
|
1229 /* No unlock tcb assoc is gone */ |
|
1230 return (0); |
|
1231 } |
|
1232 if (TAILQ_EMPTY(&asoc->send_queue) && |
|
1233 TAILQ_EMPTY(&asoc->sent_queue) && |
|
1234 (asoc->stream_queue_cnt == 0)) { |
|
1235 /* there is nothing queued to send, so done */ |
|
1236 if (asoc->locked_on_sending) { |
|
1237 goto abort_anyway; |
|
1238 } |
|
1239 if ((SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) && |
|
1240 (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_ACK_SENT)) { |
|
1241 /* only send SHUTDOWN 1st time thru */ |
|
1242 struct sctp_nets *netp; |
|
1243 |
|
1244 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || |
|
1245 (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
1246 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
1247 } |
|
1248 SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); |
|
1249 SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); |
|
1250 sctp_stop_timers_for_shutdown(stcb); |
|
1251 if (stcb->asoc.alternate) { |
|
1252 netp = stcb->asoc.alternate; |
|
1253 } else { |
|
1254 netp = stcb->asoc.primary_destination; |
|
1255 } |
|
1256 sctp_send_shutdown(stcb,netp); |
|
1257 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, |
|
1258 stcb->sctp_ep, stcb, netp); |
|
1259 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
1260 stcb->sctp_ep, stcb, netp); |
|
1261 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); |
|
1262 } |
|
1263 } else { |
|
1264 /* |
|
1265 * we still got (or just got) data to send, |
|
1266 * so set SHUTDOWN_PENDING |
|
1267 */ |
|
1268 /* |
|
1269 * XXX sockets draft says that SCTP_EOF |
|
1270 * should be sent with no data. currently, |
|
1271 * we will allow user data to be sent first |
|
1272 * and move to SHUTDOWN-PENDING |
|
1273 */ |
|
1274 struct sctp_nets *netp; |
|
1275 if (stcb->asoc.alternate) { |
|
1276 netp = stcb->asoc.alternate; |
|
1277 } else { |
|
1278 netp = stcb->asoc.primary_destination; |
|
1279 } |
|
1280 |
|
1281 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; |
|
1282 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, |
|
1283 netp); |
|
1284 if (asoc->locked_on_sending) { |
|
1285 /* Locked to send out the data */ |
|
1286 struct sctp_stream_queue_pending *sp; |
|
1287 sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); |
|
1288 if (sp == NULL) { |
|
1289 SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", |
|
1290 asoc->locked_on_sending->stream_no); |
|
1291 } else { |
|
1292 if ((sp->length == 0) && (sp->msg_is_complete == 0)) |
|
1293 asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; |
|
1294 } |
|
1295 } |
|
1296 if (TAILQ_EMPTY(&asoc->send_queue) && |
|
1297 TAILQ_EMPTY(&asoc->sent_queue) && |
|
1298 (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { |
|
1299 struct mbuf *op_err; |
|
1300 abort_anyway: |
|
1301 op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
|
1302 0, M_NOWAIT, 1, MT_DATA); |
|
1303 if (op_err) { |
|
1304 /* Fill in the user initiated abort */ |
|
1305 struct sctp_paramhdr *ph; |
|
1306 |
|
1307 SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); |
|
1308 ph = mtod(op_err, struct sctp_paramhdr *); |
|
1309 ph->param_type = htons(SCTP_CAUSE_USER_INITIATED_ABT); |
|
1310 ph->param_length = htons(SCTP_BUF_LEN(op_err)); |
|
1311 } |
|
1312 stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_4; |
|
1313 sctp_send_abort_tcb(stcb, op_err, SCTP_SO_LOCKED); |
|
1314 SCTP_STAT_INCR_COUNTER32(sctps_aborted); |
|
1315 if ((SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_OPEN) || |
|
1316 (SCTP_GET_STATE(&stcb->asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
1317 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
1318 } |
|
1319 SCTP_INP_RUNLOCK(inp); |
|
1320 (void)sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_5); |
|
1321 return (0); |
|
1322 } else { |
|
1323 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); |
|
1324 } |
|
1325 } |
|
1326 soisdisconnecting(so); |
|
1327 SCTP_TCB_UNLOCK(stcb); |
|
1328 SCTP_INP_RUNLOCK(inp); |
|
1329 return (0); |
|
1330 } |
|
1331 /* not reached */ |
|
1332 } else { |
|
1333 /* UDP model does not support this */ |
|
1334 SCTP_INP_RUNLOCK(inp); |
|
1335 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
1336 return (EOPNOTSUPP); |
|
1337 } |
|
1338 } |
|
1339 |
|
1340 #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__) |
|
1341 int |
|
1342 sctp_flush(struct socket *so, int how) |
|
1343 { |
|
1344 /* |
|
1345 * We will just clear out the values and let |
|
1346 * subsequent close clear out the data, if any. |
|
1347 * Note if the user did a shutdown(SHUT_RD) they |
|
1348 * will not be able to read the data, the socket |
|
1349 * will block that from happening. |
|
1350 */ |
|
1351 struct sctp_inpcb *inp; |
|
1352 |
|
1353 inp = (struct sctp_inpcb *)so->so_pcb; |
|
1354 if (inp == NULL) { |
|
1355 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
1356 return (EINVAL); |
|
1357 } |
|
1358 SCTP_INP_RLOCK(inp); |
|
1359 /* For the 1 to many model this does nothing */ |
|
1360 if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { |
|
1361 SCTP_INP_RUNLOCK(inp); |
|
1362 return (0); |
|
1363 } |
|
1364 SCTP_INP_RUNLOCK(inp); |
|
1365 if ((how == PRU_FLUSH_RD) || (how == PRU_FLUSH_RDWR)) { |
|
1366 /* First make sure the sb will be happy, we don't |
|
1367 * use these except maybe the count |
|
1368 */ |
|
1369 SCTP_INP_WLOCK(inp); |
|
1370 SCTP_INP_READ_LOCK(inp); |
|
1371 inp->sctp_flags |= SCTP_PCB_FLAGS_SOCKET_CANT_READ; |
|
1372 SCTP_INP_READ_UNLOCK(inp); |
|
1373 SCTP_INP_WUNLOCK(inp); |
|
1374 so->so_rcv.sb_cc = 0; |
|
1375 so->so_rcv.sb_mbcnt = 0; |
|
1376 so->so_rcv.sb_mb = NULL; |
|
1377 } |
|
1378 if ((how == PRU_FLUSH_WR) || (how == PRU_FLUSH_RDWR)) { |
|
1379 /* First make sure the sb will be happy, we don't |
|
1380 * use these except maybe the count |
|
1381 */ |
|
1382 so->so_snd.sb_cc = 0; |
|
1383 so->so_snd.sb_mbcnt = 0; |
|
1384 so->so_snd.sb_mb = NULL; |
|
1385 |
|
1386 } |
|
1387 return (0); |
|
1388 } |
|
1389 #endif |
|
1390 |
|
1391 int |
|
1392 sctp_shutdown(struct socket *so) |
|
1393 { |
|
1394 struct sctp_inpcb *inp; |
|
1395 |
|
1396 inp = (struct sctp_inpcb *)so->so_pcb; |
|
1397 if (inp == NULL) { |
|
1398 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
1399 return (EINVAL); |
|
1400 } |
|
1401 SCTP_INP_RLOCK(inp); |
|
1402 /* For UDP model this is a invalid call */ |
|
1403 if (!((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
1404 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL))) { |
|
1405 /* Restore the flags that the soshutdown took away. */ |
|
1406 #if (defined(__FreeBSD__) && __FreeBSD_version >= 502115) || defined(__Windows__) |
|
1407 SOCKBUF_LOCK(&so->so_rcv); |
|
1408 so->so_rcv.sb_state &= ~SBS_CANTRCVMORE; |
|
1409 SOCKBUF_UNLOCK(&so->so_rcv); |
|
1410 #else |
|
1411 so->so_state &= ~SS_CANTRCVMORE; |
|
1412 #endif |
|
1413 /* This proc will wakeup for read and do nothing (I hope) */ |
|
1414 SCTP_INP_RUNLOCK(inp); |
|
1415 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
1416 return (EOPNOTSUPP); |
|
1417 } |
|
1418 /* |
|
1419 * Ok if we reach here its the TCP model and it is either a SHUT_WR |
|
1420 * or SHUT_RDWR. This means we put the shutdown flag against it. |
|
1421 */ |
|
1422 { |
|
1423 struct sctp_tcb *stcb; |
|
1424 struct sctp_association *asoc; |
|
1425 |
|
1426 if ((so->so_state & |
|
1427 (SS_ISCONNECTED|SS_ISCONNECTING|SS_ISDISCONNECTING)) == 0) { |
|
1428 SCTP_INP_RUNLOCK(inp); |
|
1429 return (ENOTCONN); |
|
1430 } |
|
1431 socantsendmore(so); |
|
1432 |
|
1433 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
1434 if (stcb == NULL) { |
|
1435 /* |
|
1436 * Ok we hit the case that the shutdown call was |
|
1437 * made after an abort or something. Nothing to do |
|
1438 * now. |
|
1439 */ |
|
1440 SCTP_INP_RUNLOCK(inp); |
|
1441 return (0); |
|
1442 } |
|
1443 SCTP_TCB_LOCK(stcb); |
|
1444 asoc = &stcb->asoc; |
|
1445 if (TAILQ_EMPTY(&asoc->send_queue) && |
|
1446 TAILQ_EMPTY(&asoc->sent_queue) && |
|
1447 (asoc->stream_queue_cnt == 0)) { |
|
1448 if (asoc->locked_on_sending) { |
|
1449 goto abort_anyway; |
|
1450 } |
|
1451 /* there is nothing queued to send, so I'm done... */ |
|
1452 if (SCTP_GET_STATE(asoc) != SCTP_STATE_SHUTDOWN_SENT) { |
|
1453 /* only send SHUTDOWN the first time through */ |
|
1454 struct sctp_nets *netp; |
|
1455 |
|
1456 if ((SCTP_GET_STATE(asoc) == SCTP_STATE_OPEN) || |
|
1457 (SCTP_GET_STATE(asoc) == SCTP_STATE_SHUTDOWN_RECEIVED)) { |
|
1458 SCTP_STAT_DECR_GAUGE32(sctps_currestab); |
|
1459 } |
|
1460 SCTP_SET_STATE(asoc, SCTP_STATE_SHUTDOWN_SENT); |
|
1461 SCTP_CLEAR_SUBSTATE(asoc, SCTP_STATE_SHUTDOWN_PENDING); |
|
1462 sctp_stop_timers_for_shutdown(stcb); |
|
1463 if (stcb->asoc.alternate) { |
|
1464 netp = stcb->asoc.alternate; |
|
1465 } else { |
|
1466 netp = stcb->asoc.primary_destination; |
|
1467 } |
|
1468 sctp_send_shutdown(stcb, netp); |
|
1469 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWN, |
|
1470 stcb->sctp_ep, stcb, netp); |
|
1471 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, |
|
1472 stcb->sctp_ep, stcb, netp); |
|
1473 sctp_chunk_output(stcb->sctp_ep, stcb, SCTP_OUTPUT_FROM_T3, SCTP_SO_LOCKED); |
|
1474 } |
|
1475 } else { |
|
1476 /* |
|
1477 * we still got (or just got) data to send, so set |
|
1478 * SHUTDOWN_PENDING |
|
1479 */ |
|
1480 struct sctp_nets *netp; |
|
1481 if (stcb->asoc.alternate) { |
|
1482 netp = stcb->asoc.alternate; |
|
1483 } else { |
|
1484 netp = stcb->asoc.primary_destination; |
|
1485 } |
|
1486 |
|
1487 asoc->state |= SCTP_STATE_SHUTDOWN_PENDING; |
|
1488 sctp_timer_start(SCTP_TIMER_TYPE_SHUTDOWNGUARD, stcb->sctp_ep, stcb, |
|
1489 netp); |
|
1490 |
|
1491 if (asoc->locked_on_sending) { |
|
1492 /* Locked to send out the data */ |
|
1493 struct sctp_stream_queue_pending *sp; |
|
1494 sp = TAILQ_LAST(&asoc->locked_on_sending->outqueue, sctp_streamhead); |
|
1495 if (sp == NULL) { |
|
1496 SCTP_PRINTF("Error, sp is NULL, locked on sending is non-null strm:%d\n", |
|
1497 asoc->locked_on_sending->stream_no); |
|
1498 } else { |
|
1499 if ((sp->length == 0) && (sp-> msg_is_complete == 0)) { |
|
1500 asoc->state |= SCTP_STATE_PARTIAL_MSG_LEFT; |
|
1501 } |
|
1502 } |
|
1503 } |
|
1504 if (TAILQ_EMPTY(&asoc->send_queue) && |
|
1505 TAILQ_EMPTY(&asoc->sent_queue) && |
|
1506 (asoc->state & SCTP_STATE_PARTIAL_MSG_LEFT)) { |
|
1507 struct mbuf *op_err; |
|
1508 abort_anyway: |
|
1509 op_err = sctp_get_mbuf_for_msg(sizeof(struct sctp_paramhdr), |
|
1510 0, M_NOWAIT, 1, MT_DATA); |
|
1511 if (op_err) { |
|
1512 /* Fill in the user initiated abort */ |
|
1513 struct sctp_paramhdr *ph; |
|
1514 |
|
1515 SCTP_BUF_LEN(op_err) = sizeof(struct sctp_paramhdr); |
|
1516 ph = mtod(op_err, struct sctp_paramhdr *); |
|
1517 ph->param_type = htons( SCTP_CAUSE_USER_INITIATED_ABT); |
|
1518 ph->param_length = htons(SCTP_BUF_LEN(op_err)); |
|
1519 } |
|
1520 stcb->sctp_ep->last_abort_code = SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6; |
|
1521 sctp_abort_an_association(stcb->sctp_ep, stcb, |
|
1522 op_err, SCTP_SO_LOCKED); |
|
1523 goto skip_unlock; |
|
1524 } else { |
|
1525 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_CLOSING, SCTP_SO_LOCKED); |
|
1526 } |
|
1527 } |
|
1528 SCTP_TCB_UNLOCK(stcb); |
|
1529 } |
|
1530 skip_unlock: |
|
1531 SCTP_INP_RUNLOCK(inp); |
|
1532 return (0); |
|
1533 } |
|
1534 |
|
1535 /* |
|
1536 * copies a "user" presentable address and removes embedded scope, etc. |
|
1537 * returns 0 on success, 1 on error |
|
1538 */ |
|
1539 static uint32_t |
|
1540 sctp_fill_user_address(struct sockaddr_storage *ss, struct sockaddr *sa) |
|
1541 { |
|
1542 #ifdef INET6 |
|
1543 #if defined(SCTP_EMBEDDED_V6_SCOPE) |
|
1544 struct sockaddr_in6 lsa6; |
|
1545 |
|
1546 sa = (struct sockaddr *)sctp_recover_scope((struct sockaddr_in6 *)sa, |
|
1547 &lsa6); |
|
1548 #endif |
|
1549 #endif |
|
1550 #ifdef HAVE_SA_LEN |
|
1551 memcpy(ss, sa, sa->sa_len); |
|
1552 #else |
|
1553 switch (sa->sa_family) { |
|
1554 #ifdef INET |
|
1555 case AF_INET: |
|
1556 memcpy(ss, sa, sizeof(struct sockaddr_in)); |
|
1557 break; |
|
1558 #endif |
|
1559 #ifdef INET6 |
|
1560 case AF_INET6: |
|
1561 memcpy(ss, sa, sizeof(struct sockaddr_in6)); |
|
1562 break; |
|
1563 #endif |
|
1564 #if defined(__Userspace__) |
|
1565 case AF_CONN: |
|
1566 memcpy(ss, sa, sizeof(struct sockaddr_conn)); |
|
1567 break; |
|
1568 #endif |
|
1569 default: |
|
1570 /* TSNH */ |
|
1571 break; |
|
1572 } |
|
1573 #endif |
|
1574 return (0); |
|
1575 } |
|
1576 |
|
1577 |
|
1578 |
|
1579 /* |
|
1580 * NOTE: assumes addr lock is held |
|
1581 */ |
|
1582 static size_t |
|
1583 sctp_fill_up_addresses_vrf(struct sctp_inpcb *inp, |
|
1584 struct sctp_tcb *stcb, |
|
1585 size_t limit, |
|
1586 struct sockaddr_storage *sas, |
|
1587 uint32_t vrf_id) |
|
1588 { |
|
1589 struct sctp_ifn *sctp_ifn; |
|
1590 struct sctp_ifa *sctp_ifa; |
|
1591 size_t actual; |
|
1592 int loopback_scope; |
|
1593 #if defined(INET) |
|
1594 int ipv4_local_scope, ipv4_addr_legal; |
|
1595 #endif |
|
1596 #if defined(INET6) |
|
1597 int local_scope, site_scope, ipv6_addr_legal; |
|
1598 #endif |
|
1599 #if defined(__Userspace__) |
|
1600 int conn_addr_legal; |
|
1601 #endif |
|
1602 struct sctp_vrf *vrf; |
|
1603 |
|
1604 actual = 0; |
|
1605 if (limit <= 0) |
|
1606 return (actual); |
|
1607 |
|
1608 if (stcb) { |
|
1609 /* Turn on all the appropriate scope */ |
|
1610 loopback_scope = stcb->asoc.scope.loopback_scope; |
|
1611 #if defined(INET) |
|
1612 ipv4_local_scope = stcb->asoc.scope.ipv4_local_scope; |
|
1613 ipv4_addr_legal = stcb->asoc.scope.ipv4_addr_legal; |
|
1614 #endif |
|
1615 #if defined(INET6) |
|
1616 local_scope = stcb->asoc.scope.local_scope; |
|
1617 site_scope = stcb->asoc.scope.site_scope; |
|
1618 ipv6_addr_legal = stcb->asoc.scope.ipv6_addr_legal; |
|
1619 #endif |
|
1620 #if defined(__Userspace__) |
|
1621 conn_addr_legal = stcb->asoc.scope.conn_addr_legal; |
|
1622 #endif |
|
1623 } else { |
|
1624 /* Use generic values for endpoints. */ |
|
1625 loopback_scope = 1; |
|
1626 #if defined(INET) |
|
1627 ipv4_local_scope = 1; |
|
1628 #endif |
|
1629 #if defined(INET6) |
|
1630 local_scope = 1; |
|
1631 site_scope = 1; |
|
1632 #endif |
|
1633 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
1634 #if defined(INET6) |
|
1635 ipv6_addr_legal = 1; |
|
1636 #endif |
|
1637 #if defined(INET) |
|
1638 if (SCTP_IPV6_V6ONLY(inp)) { |
|
1639 ipv4_addr_legal = 0; |
|
1640 } else { |
|
1641 ipv4_addr_legal = 1; |
|
1642 } |
|
1643 #endif |
|
1644 #if defined(__Userspace__) |
|
1645 conn_addr_legal = 0; |
|
1646 #endif |
|
1647 } else { |
|
1648 #if defined(INET6) |
|
1649 ipv6_addr_legal = 0; |
|
1650 #endif |
|
1651 #if defined(__Userspace__) |
|
1652 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) { |
|
1653 conn_addr_legal = 1; |
|
1654 #if defined(INET) |
|
1655 ipv4_addr_legal = 0; |
|
1656 #endif |
|
1657 } else { |
|
1658 conn_addr_legal = 0; |
|
1659 #if defined(INET) |
|
1660 ipv4_addr_legal = 1; |
|
1661 #endif |
|
1662 } |
|
1663 #else |
|
1664 #if defined(INET) |
|
1665 ipv4_addr_legal = 1; |
|
1666 #endif |
|
1667 #endif |
|
1668 } |
|
1669 } |
|
1670 vrf = sctp_find_vrf(vrf_id); |
|
1671 if (vrf == NULL) { |
|
1672 return (0); |
|
1673 } |
|
1674 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
1675 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
|
1676 if ((loopback_scope == 0) && |
|
1677 SCTP_IFN_IS_IFT_LOOP(sctp_ifn)) { |
|
1678 /* Skip loopback if loopback_scope not set */ |
|
1679 continue; |
|
1680 } |
|
1681 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
|
1682 if (stcb) { |
|
1683 /* |
|
1684 * For the BOUND-ALL case, the list |
|
1685 * associated with a TCB is Always |
|
1686 * considered a reverse list.. i.e. |
|
1687 * it lists addresses that are NOT |
|
1688 * part of the association. If this |
|
1689 * is one of those we must skip it. |
|
1690 */ |
|
1691 if (sctp_is_addr_restricted(stcb, |
|
1692 sctp_ifa)) { |
|
1693 continue; |
|
1694 } |
|
1695 } |
|
1696 switch (sctp_ifa->address.sa.sa_family) { |
|
1697 #ifdef INET |
|
1698 case AF_INET: |
|
1699 if (ipv4_addr_legal) { |
|
1700 struct sockaddr_in *sin; |
|
1701 |
|
1702 sin = (struct sockaddr_in *)&sctp_ifa->address.sa; |
|
1703 if (sin->sin_addr.s_addr == 0) { |
|
1704 /* |
|
1705 * we skip unspecifed |
|
1706 * addresses |
|
1707 */ |
|
1708 continue; |
|
1709 } |
|
1710 if ((ipv4_local_scope == 0) && |
|
1711 (IN4_ISPRIVATE_ADDRESS(&sin->sin_addr))) { |
|
1712 continue; |
|
1713 } |
|
1714 #ifdef INET6 |
|
1715 if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { |
|
1716 in6_sin_2_v4mapsin6(sin, (struct sockaddr_in6 *)sas); |
|
1717 ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; |
|
1718 sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_in6)); |
|
1719 actual += sizeof(struct sockaddr_in6); |
|
1720 } else { |
|
1721 #endif |
|
1722 memcpy(sas, sin, sizeof(*sin)); |
|
1723 ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; |
|
1724 sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin)); |
|
1725 actual += sizeof(*sin); |
|
1726 #ifdef INET6 |
|
1727 } |
|
1728 #endif |
|
1729 if (actual >= limit) { |
|
1730 return (actual); |
|
1731 } |
|
1732 } else { |
|
1733 continue; |
|
1734 } |
|
1735 break; |
|
1736 #endif |
|
1737 #ifdef INET6 |
|
1738 case AF_INET6: |
|
1739 if (ipv6_addr_legal) { |
|
1740 struct sockaddr_in6 *sin6; |
|
1741 |
|
1742 #if defined(SCTP_EMBEDDED_V6_SCOPE) && !defined(SCTP_KAME) |
|
1743 struct sockaddr_in6 lsa6; |
|
1744 #endif |
|
1745 sin6 = (struct sockaddr_in6 *)&sctp_ifa->address.sa; |
|
1746 if (IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
1747 /* |
|
1748 * we skip unspecifed |
|
1749 * addresses |
|
1750 */ |
|
1751 continue; |
|
1752 } |
|
1753 if (IN6_IS_ADDR_LINKLOCAL(&sin6->sin6_addr)) { |
|
1754 if (local_scope == 0) |
|
1755 continue; |
|
1756 #if defined(SCTP_EMBEDDED_V6_SCOPE) |
|
1757 if (sin6->sin6_scope_id == 0) { |
|
1758 #ifdef SCTP_KAME |
|
1759 if (sa6_recoverscope(sin6) != 0) |
|
1760 /* |
|
1761 * bad link |
|
1762 * local |
|
1763 * address |
|
1764 */ |
|
1765 continue; |
|
1766 #else |
|
1767 lsa6 = *sin6; |
|
1768 if (in6_recoverscope(&lsa6, |
|
1769 &lsa6.sin6_addr, |
|
1770 NULL)) |
|
1771 /* |
|
1772 * bad link |
|
1773 * local |
|
1774 * address |
|
1775 */ |
|
1776 continue; |
|
1777 sin6 = &lsa6; |
|
1778 #endif /* SCTP_KAME */ |
|
1779 } |
|
1780 #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
|
1781 } |
|
1782 if ((site_scope == 0) && |
|
1783 (IN6_IS_ADDR_SITELOCAL(&sin6->sin6_addr))) { |
|
1784 continue; |
|
1785 } |
|
1786 memcpy(sas, sin6, sizeof(*sin6)); |
|
1787 ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; |
|
1788 sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(*sin6)); |
|
1789 actual += sizeof(*sin6); |
|
1790 if (actual >= limit) { |
|
1791 return (actual); |
|
1792 } |
|
1793 } else { |
|
1794 continue; |
|
1795 } |
|
1796 break; |
|
1797 #endif |
|
1798 #if defined(__Userspace__) |
|
1799 case AF_CONN: |
|
1800 if (conn_addr_legal) { |
|
1801 memcpy(sas, &sctp_ifa->address.sconn, sizeof(struct sockaddr_conn)); |
|
1802 ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport; |
|
1803 sas = (struct sockaddr_storage *)((caddr_t)sas + sizeof(struct sockaddr_conn)); |
|
1804 actual += sizeof(struct sockaddr_conn); |
|
1805 if (actual >= limit) { |
|
1806 return (actual); |
|
1807 } |
|
1808 } else { |
|
1809 continue; |
|
1810 } |
|
1811 #endif |
|
1812 default: |
|
1813 /* TSNH */ |
|
1814 break; |
|
1815 } |
|
1816 } |
|
1817 } |
|
1818 } else { |
|
1819 struct sctp_laddr *laddr; |
|
1820 #ifndef HAVE_SA_LEN |
|
1821 uint32_t sa_len = 0; |
|
1822 #endif |
|
1823 |
|
1824 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
|
1825 if (stcb) { |
|
1826 if (sctp_is_addr_restricted(stcb, laddr->ifa)) { |
|
1827 continue; |
|
1828 } |
|
1829 } |
|
1830 if (sctp_fill_user_address(sas, &laddr->ifa->address.sa)) |
|
1831 continue; |
|
1832 switch (laddr->ifa->address.sa.sa_family) { |
|
1833 #ifdef INET |
|
1834 case AF_INET: |
|
1835 ((struct sockaddr_in *)sas)->sin_port = inp->sctp_lport; |
|
1836 break; |
|
1837 #endif |
|
1838 #ifdef INET6 |
|
1839 case AF_INET6: |
|
1840 ((struct sockaddr_in6 *)sas)->sin6_port = inp->sctp_lport; |
|
1841 break; |
|
1842 #endif |
|
1843 #if defined(__Userspace__) |
|
1844 case AF_CONN: |
|
1845 ((struct sockaddr_conn *)sas)->sconn_port = inp->sctp_lport; |
|
1846 break; |
|
1847 #endif |
|
1848 default: |
|
1849 /* TSNH */ |
|
1850 break; |
|
1851 } |
|
1852 #ifdef HAVE_SA_LEN |
|
1853 sas = (struct sockaddr_storage *)((caddr_t)sas + |
|
1854 laddr->ifa->address.sa.sa_len); |
|
1855 actual += laddr->ifa->address.sa.sa_len; |
|
1856 #else |
|
1857 switch (laddr->ifa->address.sa.sa_family) { |
|
1858 #ifdef INET |
|
1859 case AF_INET: |
|
1860 sa_len = sizeof(struct sockaddr_in); |
|
1861 break; |
|
1862 #endif |
|
1863 #ifdef INET6 |
|
1864 case AF_INET6: |
|
1865 sa_len = sizeof(struct sockaddr_in6); |
|
1866 break; |
|
1867 #endif |
|
1868 #if defined(__Userspace__) |
|
1869 case AF_CONN: |
|
1870 sa_len = sizeof(struct sockaddr_conn); |
|
1871 break; |
|
1872 #endif |
|
1873 default: |
|
1874 /* TSNH */ |
|
1875 break; |
|
1876 } |
|
1877 sas = (struct sockaddr_storage *)((caddr_t)sas + sa_len); |
|
1878 actual += sa_len; |
|
1879 #endif |
|
1880 if (actual >= limit) { |
|
1881 return (actual); |
|
1882 } |
|
1883 } |
|
1884 } |
|
1885 return (actual); |
|
1886 } |
|
1887 |
|
1888 static size_t |
|
1889 sctp_fill_up_addresses(struct sctp_inpcb *inp, |
|
1890 struct sctp_tcb *stcb, |
|
1891 size_t limit, |
|
1892 struct sockaddr_storage *sas) |
|
1893 { |
|
1894 size_t size = 0; |
|
1895 #ifdef SCTP_MVRF |
|
1896 uint32_t id; |
|
1897 #endif |
|
1898 |
|
1899 SCTP_IPI_ADDR_RLOCK(); |
|
1900 #ifdef SCTP_MVRF |
|
1901 /* |
|
1902 * FIX ME: ?? this WILL report duplicate addresses if they appear |
|
1903 * in more than one VRF. |
|
1904 */ |
|
1905 /* fill up addresses for all VRFs on the endpoint */ |
|
1906 for (id = 0; (id < inp->num_vrfs) && (size < limit); id++) { |
|
1907 size += sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, |
|
1908 inp->m_vrf_ids[id]); |
|
1909 sas = (struct sockaddr_storage *)((caddr_t)sas + size); |
|
1910 } |
|
1911 #else |
|
1912 /* fill up addresses for the endpoint's default vrf */ |
|
1913 size = sctp_fill_up_addresses_vrf(inp, stcb, limit, sas, |
|
1914 inp->def_vrf_id); |
|
1915 #endif |
|
1916 SCTP_IPI_ADDR_RUNLOCK(); |
|
1917 return (size); |
|
1918 } |
|
1919 |
|
1920 /* |
|
1921 * NOTE: assumes addr lock is held |
|
1922 */ |
|
1923 static int |
|
1924 sctp_count_max_addresses_vrf(struct sctp_inpcb *inp, uint32_t vrf_id) |
|
1925 { |
|
1926 int cnt = 0; |
|
1927 struct sctp_vrf *vrf = NULL; |
|
1928 |
|
1929 /* |
|
1930 * In both sub-set bound an bound_all cases we return the MAXIMUM |
|
1931 * number of addresses that you COULD get. In reality the sub-set |
|
1932 * bound may have an exclusion list for a given TCB OR in the |
|
1933 * bound-all case a TCB may NOT include the loopback or other |
|
1934 * addresses as well. |
|
1935 */ |
|
1936 vrf = sctp_find_vrf(vrf_id); |
|
1937 if (vrf == NULL) { |
|
1938 return (0); |
|
1939 } |
|
1940 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
1941 struct sctp_ifn *sctp_ifn; |
|
1942 struct sctp_ifa *sctp_ifa; |
|
1943 |
|
1944 LIST_FOREACH(sctp_ifn, &vrf->ifnlist, next_ifn) { |
|
1945 LIST_FOREACH(sctp_ifa, &sctp_ifn->ifalist, next_ifa) { |
|
1946 /* Count them if they are the right type */ |
|
1947 switch (sctp_ifa->address.sa.sa_family) { |
|
1948 #ifdef INET |
|
1949 case AF_INET: |
|
1950 if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) |
|
1951 cnt += sizeof(struct sockaddr_in6); |
|
1952 else |
|
1953 cnt += sizeof(struct sockaddr_in); |
|
1954 break; |
|
1955 #endif |
|
1956 #ifdef INET6 |
|
1957 case AF_INET6: |
|
1958 cnt += sizeof(struct sockaddr_in6); |
|
1959 break; |
|
1960 #endif |
|
1961 #if defined(__Userspace__) |
|
1962 case AF_CONN: |
|
1963 cnt += sizeof(struct sockaddr_conn); |
|
1964 break; |
|
1965 #endif |
|
1966 default: |
|
1967 break; |
|
1968 } |
|
1969 } |
|
1970 } |
|
1971 } else { |
|
1972 struct sctp_laddr *laddr; |
|
1973 |
|
1974 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
|
1975 switch (laddr->ifa->address.sa.sa_family) { |
|
1976 #ifdef INET |
|
1977 case AF_INET: |
|
1978 if (sctp_is_feature_on(inp,SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) |
|
1979 cnt += sizeof(struct sockaddr_in6); |
|
1980 else |
|
1981 cnt += sizeof(struct sockaddr_in); |
|
1982 break; |
|
1983 #endif |
|
1984 #ifdef INET6 |
|
1985 case AF_INET6: |
|
1986 cnt += sizeof(struct sockaddr_in6); |
|
1987 break; |
|
1988 #endif |
|
1989 #if defined(__Userspace__) |
|
1990 case AF_CONN: |
|
1991 cnt += sizeof(struct sockaddr_conn); |
|
1992 break; |
|
1993 #endif |
|
1994 default: |
|
1995 break; |
|
1996 } |
|
1997 } |
|
1998 } |
|
1999 return (cnt); |
|
2000 } |
|
2001 |
|
2002 static int |
|
2003 sctp_count_max_addresses(struct sctp_inpcb *inp) |
|
2004 { |
|
2005 int cnt = 0; |
|
2006 #ifdef SCTP_MVRF |
|
2007 int id; |
|
2008 #endif |
|
2009 |
|
2010 SCTP_IPI_ADDR_RLOCK(); |
|
2011 #ifdef SCTP_MVRF |
|
2012 /* |
|
2013 * FIX ME: ?? this WILL count duplicate addresses if they appear |
|
2014 * in more than one VRF. |
|
2015 */ |
|
2016 /* count addresses for all VRFs on the endpoint */ |
|
2017 for (id = 0; id < inp->num_vrfs; id++) { |
|
2018 cnt += sctp_count_max_addresses_vrf(inp, inp->m_vrf_ids[id]); |
|
2019 } |
|
2020 #else |
|
2021 /* count addresses for the endpoint's default VRF */ |
|
2022 cnt = sctp_count_max_addresses_vrf(inp, inp->def_vrf_id); |
|
2023 #endif |
|
2024 SCTP_IPI_ADDR_RUNLOCK(); |
|
2025 return (cnt); |
|
2026 } |
|
2027 |
|
2028 static int |
|
2029 sctp_do_connect_x(struct socket *so, struct sctp_inpcb *inp, void *optval, |
|
2030 size_t optsize, void *p, int delay) |
|
2031 { |
|
2032 int error = 0; |
|
2033 int creat_lock_on = 0; |
|
2034 struct sctp_tcb *stcb = NULL; |
|
2035 struct sockaddr *sa; |
|
2036 int num_v6 = 0, num_v4 = 0, *totaddrp, totaddr; |
|
2037 uint32_t vrf_id; |
|
2038 int bad_addresses = 0; |
|
2039 sctp_assoc_t *a_id; |
|
2040 |
|
2041 SCTPDBG(SCTP_DEBUG_PCB1, "Connectx called\n"); |
|
2042 |
|
2043 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
2044 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { |
|
2045 /* We are already connected AND the TCP model */ |
|
2046 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); |
|
2047 return (EADDRINUSE); |
|
2048 } |
|
2049 |
|
2050 if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && |
|
2051 (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { |
|
2052 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2053 return (EINVAL); |
|
2054 } |
|
2055 |
|
2056 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { |
|
2057 SCTP_INP_RLOCK(inp); |
|
2058 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
2059 SCTP_INP_RUNLOCK(inp); |
|
2060 } |
|
2061 if (stcb) { |
|
2062 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
2063 return (EALREADY); |
|
2064 } |
|
2065 SCTP_INP_INCR_REF(inp); |
|
2066 SCTP_ASOC_CREATE_LOCK(inp); |
|
2067 creat_lock_on = 1; |
|
2068 if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || |
|
2069 (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { |
|
2070 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); |
|
2071 error = EFAULT; |
|
2072 goto out_now; |
|
2073 } |
|
2074 totaddrp = (int *)optval; |
|
2075 totaddr = *totaddrp; |
|
2076 sa = (struct sockaddr *)(totaddrp + 1); |
|
2077 stcb = sctp_connectx_helper_find(inp, sa, &totaddr, &num_v4, &num_v6, &error, (optsize - sizeof(int)), &bad_addresses); |
|
2078 if ((stcb != NULL) || bad_addresses) { |
|
2079 /* Already have or am bring up an association */ |
|
2080 SCTP_ASOC_CREATE_UNLOCK(inp); |
|
2081 creat_lock_on = 0; |
|
2082 if (stcb) |
|
2083 SCTP_TCB_UNLOCK(stcb); |
|
2084 if (bad_addresses == 0) { |
|
2085 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
2086 error = EALREADY; |
|
2087 } |
|
2088 goto out_now; |
|
2089 } |
|
2090 #ifdef INET6 |
|
2091 if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && |
|
2092 (num_v6 > 0)) { |
|
2093 error = EINVAL; |
|
2094 goto out_now; |
|
2095 } |
|
2096 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
2097 (num_v4 > 0)) { |
|
2098 struct in6pcb *inp6; |
|
2099 |
|
2100 inp6 = (struct in6pcb *)inp; |
|
2101 if (SCTP_IPV6_V6ONLY(inp6)) { |
|
2102 /* |
|
2103 * if IPV6_V6ONLY flag, ignore connections destined |
|
2104 * to a v4 addr or v4-mapped addr |
|
2105 */ |
|
2106 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2107 error = EINVAL; |
|
2108 goto out_now; |
|
2109 } |
|
2110 } |
|
2111 #endif /* INET6 */ |
|
2112 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == |
|
2113 SCTP_PCB_FLAGS_UNBOUND) { |
|
2114 /* Bind a ephemeral port */ |
|
2115 error = sctp_inpcb_bind(so, NULL, NULL, p); |
|
2116 if (error) { |
|
2117 goto out_now; |
|
2118 } |
|
2119 } |
|
2120 |
|
2121 /* FIX ME: do we want to pass in a vrf on the connect call? */ |
|
2122 vrf_id = inp->def_vrf_id; |
|
2123 |
|
2124 |
|
2125 /* We are GOOD to go */ |
|
2126 stcb = sctp_aloc_assoc(inp, sa, &error, 0, vrf_id, |
|
2127 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
2128 (struct thread *)p |
|
2129 #elif defined(__Windows__) |
|
2130 (PKTHREAD)p |
|
2131 #else |
|
2132 (struct proc *)p |
|
2133 #endif |
|
2134 ); |
|
2135 if (stcb == NULL) { |
|
2136 /* Gak! no memory */ |
|
2137 goto out_now; |
|
2138 } |
|
2139 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { |
|
2140 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
2141 /* Set the connected flag so we can queue data */ |
|
2142 soisconnecting(so); |
|
2143 } |
|
2144 SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); |
|
2145 /* move to second address */ |
|
2146 switch (sa->sa_family) { |
|
2147 #ifdef INET |
|
2148 case AF_INET: |
|
2149 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in)); |
|
2150 break; |
|
2151 #endif |
|
2152 #ifdef INET6 |
|
2153 case AF_INET6: |
|
2154 sa = (struct sockaddr *)((caddr_t)sa + sizeof(struct sockaddr_in6)); |
|
2155 break; |
|
2156 #endif |
|
2157 default: |
|
2158 break; |
|
2159 } |
|
2160 |
|
2161 error = 0; |
|
2162 sctp_connectx_helper_add(stcb, sa, (totaddr-1), &error); |
|
2163 /* Fill in the return id */ |
|
2164 if (error) { |
|
2165 (void)sctp_free_assoc(inp, stcb, SCTP_PCBFREE_FORCE, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_6); |
|
2166 goto out_now; |
|
2167 } |
|
2168 a_id = (sctp_assoc_t *)optval; |
|
2169 *a_id = sctp_get_associd(stcb); |
|
2170 |
|
2171 /* initialize authentication parameters for the assoc */ |
|
2172 sctp_initialize_auth_params(inp, stcb); |
|
2173 |
|
2174 if (delay) { |
|
2175 /* doing delayed connection */ |
|
2176 stcb->asoc.delayed_connection = 1; |
|
2177 sctp_timer_start(SCTP_TIMER_TYPE_INIT, inp, stcb, stcb->asoc.primary_destination); |
|
2178 } else { |
|
2179 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
2180 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
|
2181 } |
|
2182 SCTP_TCB_UNLOCK(stcb); |
|
2183 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { |
|
2184 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
2185 /* Set the connected flag so we can queue data */ |
|
2186 soisconnecting(so); |
|
2187 } |
|
2188 out_now: |
|
2189 if (creat_lock_on) { |
|
2190 SCTP_ASOC_CREATE_UNLOCK(inp); |
|
2191 } |
|
2192 SCTP_INP_DECR_REF(inp); |
|
2193 return (error); |
|
2194 } |
|
2195 |
|
2196 #define SCTP_FIND_STCB(inp, stcb, assoc_id) { \ |
|
2197 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) ||\ |
|
2198 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { \ |
|
2199 SCTP_INP_RLOCK(inp); \ |
|
2200 stcb = LIST_FIRST(&inp->sctp_asoc_list); \ |
|
2201 if (stcb) { \ |
|
2202 SCTP_TCB_LOCK(stcb); \ |
|
2203 } \ |
|
2204 SCTP_INP_RUNLOCK(inp); \ |
|
2205 } else if (assoc_id > SCTP_ALL_ASSOC) { \ |
|
2206 stcb = sctp_findassociation_ep_asocid(inp, assoc_id, 1); \ |
|
2207 if (stcb == NULL) { \ |
|
2208 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); \ |
|
2209 error = ENOENT; \ |
|
2210 break; \ |
|
2211 } \ |
|
2212 } else { \ |
|
2213 stcb = NULL; \ |
|
2214 } \ |
|
2215 } |
|
2216 |
|
2217 |
|
2218 #define SCTP_CHECK_AND_CAST(destp, srcp, type, size) {\ |
|
2219 if (size < sizeof(type)) { \ |
|
2220 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); \ |
|
2221 error = EINVAL; \ |
|
2222 break; \ |
|
2223 } else { \ |
|
2224 destp = (type *)srcp; \ |
|
2225 } \ |
|
2226 } |
|
2227 |
|
2228 #if defined(__Panda__) || defined(__Userspace__) |
|
2229 int |
|
2230 #else |
|
2231 static int |
|
2232 #endif |
|
2233 sctp_getopt(struct socket *so, int optname, void *optval, size_t *optsize, |
|
2234 void *p) { |
|
2235 struct sctp_inpcb *inp = NULL; |
|
2236 int error, val = 0; |
|
2237 struct sctp_tcb *stcb = NULL; |
|
2238 |
|
2239 if (optval == NULL) { |
|
2240 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2241 return (EINVAL); |
|
2242 } |
|
2243 |
|
2244 inp = (struct sctp_inpcb *)so->so_pcb; |
|
2245 if (inp == NULL) { |
|
2246 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2247 return EINVAL; |
|
2248 } |
|
2249 error = 0; |
|
2250 |
|
2251 switch (optname) { |
|
2252 case SCTP_NODELAY: |
|
2253 case SCTP_AUTOCLOSE: |
|
2254 case SCTP_EXPLICIT_EOR: |
|
2255 case SCTP_AUTO_ASCONF: |
|
2256 case SCTP_DISABLE_FRAGMENTS: |
|
2257 case SCTP_I_WANT_MAPPED_V4_ADDR: |
|
2258 case SCTP_USE_EXT_RCVINFO: |
|
2259 SCTP_INP_RLOCK(inp); |
|
2260 switch (optname) { |
|
2261 case SCTP_DISABLE_FRAGMENTS: |
|
2262 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NO_FRAGMENT); |
|
2263 break; |
|
2264 case SCTP_I_WANT_MAPPED_V4_ADDR: |
|
2265 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4); |
|
2266 break; |
|
2267 case SCTP_AUTO_ASCONF: |
|
2268 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
2269 /* only valid for bound all sockets */ |
|
2270 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTO_ASCONF); |
|
2271 } else { |
|
2272 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2273 error = EINVAL; |
|
2274 goto flags_out; |
|
2275 } |
|
2276 break; |
|
2277 case SCTP_EXPLICIT_EOR: |
|
2278 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXPLICIT_EOR); |
|
2279 break; |
|
2280 case SCTP_NODELAY: |
|
2281 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NODELAY); |
|
2282 break; |
|
2283 case SCTP_USE_EXT_RCVINFO: |
|
2284 val = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_EXT_RCVINFO); |
|
2285 break; |
|
2286 case SCTP_AUTOCLOSE: |
|
2287 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTOCLOSE)) |
|
2288 val = TICKS_TO_SEC(inp->sctp_ep.auto_close_time); |
|
2289 else |
|
2290 val = 0; |
|
2291 break; |
|
2292 |
|
2293 default: |
|
2294 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); |
|
2295 error = ENOPROTOOPT; |
|
2296 } /* end switch (sopt->sopt_name) */ |
|
2297 if (*optsize < sizeof(val)) { |
|
2298 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2299 error = EINVAL; |
|
2300 } |
|
2301 flags_out: |
|
2302 SCTP_INP_RUNLOCK(inp); |
|
2303 if (error == 0) { |
|
2304 /* return the option value */ |
|
2305 *(int *)optval = val; |
|
2306 *optsize = sizeof(val); |
|
2307 } |
|
2308 break; |
|
2309 case SCTP_GET_PACKET_LOG: |
|
2310 { |
|
2311 #ifdef SCTP_PACKET_LOGGING |
|
2312 uint8_t *target; |
|
2313 int ret; |
|
2314 |
|
2315 SCTP_CHECK_AND_CAST(target, optval, uint8_t, *optsize); |
|
2316 ret = sctp_copy_out_packet_log(target , (int)*optsize); |
|
2317 *optsize = ret; |
|
2318 #else |
|
2319 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
2320 error = EOPNOTSUPP; |
|
2321 #endif |
|
2322 break; |
|
2323 } |
|
2324 case SCTP_REUSE_PORT: |
|
2325 { |
|
2326 uint32_t *value; |
|
2327 |
|
2328 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { |
|
2329 /* Can't do this for a 1-m socket */ |
|
2330 error = EINVAL; |
|
2331 break; |
|
2332 } |
|
2333 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2334 *value = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); |
|
2335 *optsize = sizeof(uint32_t); |
|
2336 break; |
|
2337 } |
|
2338 case SCTP_PARTIAL_DELIVERY_POINT: |
|
2339 { |
|
2340 uint32_t *value; |
|
2341 |
|
2342 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2343 *value = inp->partial_delivery_point; |
|
2344 *optsize = sizeof(uint32_t); |
|
2345 break; |
|
2346 } |
|
2347 case SCTP_FRAGMENT_INTERLEAVE: |
|
2348 { |
|
2349 uint32_t *value; |
|
2350 |
|
2351 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2352 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE)) { |
|
2353 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS)) { |
|
2354 *value = SCTP_FRAG_LEVEL_2; |
|
2355 } else { |
|
2356 *value = SCTP_FRAG_LEVEL_1; |
|
2357 } |
|
2358 } else { |
|
2359 *value = SCTP_FRAG_LEVEL_0; |
|
2360 } |
|
2361 *optsize = sizeof(uint32_t); |
|
2362 break; |
|
2363 } |
|
2364 case SCTP_CMT_ON_OFF: |
|
2365 { |
|
2366 struct sctp_assoc_value *av; |
|
2367 |
|
2368 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2369 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2370 if (stcb) { |
|
2371 av->assoc_value = stcb->asoc.sctp_cmt_on_off; |
|
2372 SCTP_TCB_UNLOCK(stcb); |
|
2373 } else { |
|
2374 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2375 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2376 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2377 SCTP_INP_RLOCK(inp); |
|
2378 av->assoc_value = inp->sctp_cmt_on_off; |
|
2379 SCTP_INP_RUNLOCK(inp); |
|
2380 } else { |
|
2381 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2382 error = EINVAL; |
|
2383 } |
|
2384 } |
|
2385 if (error == 0) { |
|
2386 *optsize = sizeof(struct sctp_assoc_value); |
|
2387 } |
|
2388 break; |
|
2389 } |
|
2390 case SCTP_PLUGGABLE_CC: |
|
2391 { |
|
2392 struct sctp_assoc_value *av; |
|
2393 |
|
2394 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2395 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2396 if (stcb) { |
|
2397 av->assoc_value = stcb->asoc.congestion_control_module; |
|
2398 SCTP_TCB_UNLOCK(stcb); |
|
2399 } else { |
|
2400 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2401 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2402 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2403 SCTP_INP_RLOCK(inp); |
|
2404 av->assoc_value = inp->sctp_ep.sctp_default_cc_module; |
|
2405 SCTP_INP_RUNLOCK(inp); |
|
2406 } else { |
|
2407 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2408 error = EINVAL; |
|
2409 } |
|
2410 } |
|
2411 if (error == 0) { |
|
2412 *optsize = sizeof(struct sctp_assoc_value); |
|
2413 } |
|
2414 break; |
|
2415 } |
|
2416 case SCTP_CC_OPTION: |
|
2417 { |
|
2418 struct sctp_cc_option *cc_opt; |
|
2419 |
|
2420 SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, *optsize); |
|
2421 SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); |
|
2422 if (stcb == NULL) { |
|
2423 error = EINVAL; |
|
2424 } else { |
|
2425 if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { |
|
2426 error = ENOTSUP; |
|
2427 } else { |
|
2428 error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 0, cc_opt); |
|
2429 *optsize = sizeof(struct sctp_cc_option); |
|
2430 } |
|
2431 SCTP_TCB_UNLOCK(stcb); |
|
2432 } |
|
2433 break; |
|
2434 } |
|
2435 case SCTP_PLUGGABLE_SS: |
|
2436 { |
|
2437 struct sctp_assoc_value *av; |
|
2438 |
|
2439 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2440 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2441 if (stcb) { |
|
2442 av->assoc_value = stcb->asoc.stream_scheduling_module; |
|
2443 SCTP_TCB_UNLOCK(stcb); |
|
2444 } else { |
|
2445 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2446 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2447 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2448 SCTP_INP_RLOCK(inp); |
|
2449 av->assoc_value = inp->sctp_ep.sctp_default_ss_module; |
|
2450 SCTP_INP_RUNLOCK(inp); |
|
2451 } else { |
|
2452 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2453 error = EINVAL; |
|
2454 } |
|
2455 } |
|
2456 if (error == 0) { |
|
2457 *optsize = sizeof(struct sctp_assoc_value); |
|
2458 } |
|
2459 break; |
|
2460 } |
|
2461 case SCTP_SS_VALUE: |
|
2462 { |
|
2463 struct sctp_stream_value *av; |
|
2464 |
|
2465 SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, *optsize); |
|
2466 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2467 if (stcb) { |
|
2468 if (stcb->asoc.ss_functions.sctp_ss_get_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], |
|
2469 &av->stream_value) < 0) { |
|
2470 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2471 error = EINVAL; |
|
2472 } else { |
|
2473 *optsize = sizeof(struct sctp_stream_value); |
|
2474 } |
|
2475 SCTP_TCB_UNLOCK(stcb); |
|
2476 } else { |
|
2477 /* Can't get stream value without association */ |
|
2478 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2479 error = EINVAL; |
|
2480 } |
|
2481 break; |
|
2482 } |
|
2483 case SCTP_GET_ADDR_LEN: |
|
2484 { |
|
2485 struct sctp_assoc_value *av; |
|
2486 |
|
2487 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2488 error = EINVAL; |
|
2489 #ifdef INET |
|
2490 if (av->assoc_value == AF_INET) { |
|
2491 av->assoc_value = sizeof(struct sockaddr_in); |
|
2492 error = 0; |
|
2493 } |
|
2494 #endif |
|
2495 #ifdef INET6 |
|
2496 if (av->assoc_value == AF_INET6) { |
|
2497 av->assoc_value = sizeof(struct sockaddr_in6); |
|
2498 error = 0; |
|
2499 } |
|
2500 #endif |
|
2501 #if defined(__Userspace__) |
|
2502 if (av->assoc_value == AF_CONN) { |
|
2503 av->assoc_value = sizeof(struct sockaddr_conn); |
|
2504 error = 0; |
|
2505 } |
|
2506 #endif |
|
2507 if (error) { |
|
2508 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
2509 } else { |
|
2510 *optsize = sizeof(struct sctp_assoc_value); |
|
2511 } |
|
2512 break; |
|
2513 } |
|
2514 case SCTP_GET_ASSOC_NUMBER: |
|
2515 { |
|
2516 uint32_t *value, cnt; |
|
2517 |
|
2518 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2519 cnt = 0; |
|
2520 SCTP_INP_RLOCK(inp); |
|
2521 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
2522 cnt++; |
|
2523 } |
|
2524 SCTP_INP_RUNLOCK(inp); |
|
2525 *value = cnt; |
|
2526 *optsize = sizeof(uint32_t); |
|
2527 break; |
|
2528 } |
|
2529 case SCTP_GET_ASSOC_ID_LIST: |
|
2530 { |
|
2531 struct sctp_assoc_ids *ids; |
|
2532 unsigned int at, limit; |
|
2533 |
|
2534 SCTP_CHECK_AND_CAST(ids, optval, struct sctp_assoc_ids, *optsize); |
|
2535 at = 0; |
|
2536 limit = (*optsize-sizeof(uint32_t))/ sizeof(sctp_assoc_t); |
|
2537 SCTP_INP_RLOCK(inp); |
|
2538 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
2539 if (at < limit) { |
|
2540 ids->gaids_assoc_id[at++] = sctp_get_associd(stcb); |
|
2541 } else { |
|
2542 error = EINVAL; |
|
2543 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
2544 break; |
|
2545 } |
|
2546 } |
|
2547 SCTP_INP_RUNLOCK(inp); |
|
2548 if (error == 0) { |
|
2549 ids->gaids_number_of_ids = at; |
|
2550 *optsize = ((at * sizeof(sctp_assoc_t)) + sizeof(uint32_t)); |
|
2551 } |
|
2552 break; |
|
2553 } |
|
2554 case SCTP_CONTEXT: |
|
2555 { |
|
2556 struct sctp_assoc_value *av; |
|
2557 |
|
2558 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2559 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2560 |
|
2561 if (stcb) { |
|
2562 av->assoc_value = stcb->asoc.context; |
|
2563 SCTP_TCB_UNLOCK(stcb); |
|
2564 } else { |
|
2565 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2566 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2567 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2568 SCTP_INP_RLOCK(inp); |
|
2569 av->assoc_value = inp->sctp_context; |
|
2570 SCTP_INP_RUNLOCK(inp); |
|
2571 } else { |
|
2572 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2573 error = EINVAL; |
|
2574 } |
|
2575 } |
|
2576 if (error == 0) { |
|
2577 *optsize = sizeof(struct sctp_assoc_value); |
|
2578 } |
|
2579 break; |
|
2580 } |
|
2581 case SCTP_VRF_ID: |
|
2582 { |
|
2583 uint32_t *default_vrfid; |
|
2584 |
|
2585 SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, *optsize); |
|
2586 *default_vrfid = inp->def_vrf_id; |
|
2587 *optsize = sizeof(uint32_t); |
|
2588 break; |
|
2589 } |
|
2590 case SCTP_GET_ASOC_VRF: |
|
2591 { |
|
2592 struct sctp_assoc_value *id; |
|
2593 |
|
2594 SCTP_CHECK_AND_CAST(id, optval, struct sctp_assoc_value, *optsize); |
|
2595 SCTP_FIND_STCB(inp, stcb, id->assoc_id); |
|
2596 if (stcb == NULL) { |
|
2597 error = EINVAL; |
|
2598 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
2599 } else { |
|
2600 id->assoc_value = stcb->asoc.vrf_id; |
|
2601 *optsize = sizeof(struct sctp_assoc_value); |
|
2602 } |
|
2603 break; |
|
2604 } |
|
2605 case SCTP_GET_VRF_IDS: |
|
2606 { |
|
2607 #ifdef SCTP_MVRF |
|
2608 int siz_needed; |
|
2609 uint32_t *vrf_ids; |
|
2610 |
|
2611 SCTP_CHECK_AND_CAST(vrf_ids, optval, uint32_t, *optsize); |
|
2612 siz_needed = inp->num_vrfs * sizeof(uint32_t); |
|
2613 if (*optsize < siz_needed) { |
|
2614 error = EINVAL; |
|
2615 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
2616 } else { |
|
2617 memcpy(vrf_ids, inp->m_vrf_ids, siz_needed); |
|
2618 *optsize = siz_needed; |
|
2619 } |
|
2620 #else |
|
2621 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
2622 error = EOPNOTSUPP; |
|
2623 #endif |
|
2624 break; |
|
2625 } |
|
2626 case SCTP_GET_NONCE_VALUES: |
|
2627 { |
|
2628 struct sctp_get_nonce_values *gnv; |
|
2629 |
|
2630 SCTP_CHECK_AND_CAST(gnv, optval, struct sctp_get_nonce_values, *optsize); |
|
2631 SCTP_FIND_STCB(inp, stcb, gnv->gn_assoc_id); |
|
2632 |
|
2633 if (stcb) { |
|
2634 gnv->gn_peers_tag = stcb->asoc.peer_vtag; |
|
2635 gnv->gn_local_tag = stcb->asoc.my_vtag; |
|
2636 SCTP_TCB_UNLOCK(stcb); |
|
2637 *optsize = sizeof(struct sctp_get_nonce_values); |
|
2638 } else { |
|
2639 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); |
|
2640 error = ENOTCONN; |
|
2641 } |
|
2642 break; |
|
2643 } |
|
2644 case SCTP_DELAYED_SACK: |
|
2645 { |
|
2646 struct sctp_sack_info *sack; |
|
2647 |
|
2648 SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, *optsize); |
|
2649 SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); |
|
2650 if (stcb) { |
|
2651 sack->sack_delay = stcb->asoc.delayed_ack; |
|
2652 sack->sack_freq = stcb->asoc.sack_freq; |
|
2653 SCTP_TCB_UNLOCK(stcb); |
|
2654 } else { |
|
2655 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2656 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2657 (sack->sack_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2658 SCTP_INP_RLOCK(inp); |
|
2659 sack->sack_delay = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV]); |
|
2660 sack->sack_freq = inp->sctp_ep.sctp_sack_freq; |
|
2661 SCTP_INP_RUNLOCK(inp); |
|
2662 } else { |
|
2663 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2664 error = EINVAL; |
|
2665 } |
|
2666 } |
|
2667 if (error == 0) { |
|
2668 *optsize = sizeof(struct sctp_sack_info); |
|
2669 } |
|
2670 break; |
|
2671 } |
|
2672 case SCTP_GET_SNDBUF_USE: |
|
2673 { |
|
2674 struct sctp_sockstat *ss; |
|
2675 |
|
2676 SCTP_CHECK_AND_CAST(ss, optval, struct sctp_sockstat, *optsize); |
|
2677 SCTP_FIND_STCB(inp, stcb, ss->ss_assoc_id); |
|
2678 |
|
2679 if (stcb) { |
|
2680 ss->ss_total_sndbuf = stcb->asoc.total_output_queue_size; |
|
2681 ss->ss_total_recv_buf = (stcb->asoc.size_on_reasm_queue + |
|
2682 stcb->asoc.size_on_all_streams); |
|
2683 SCTP_TCB_UNLOCK(stcb); |
|
2684 *optsize = sizeof(struct sctp_sockstat); |
|
2685 } else { |
|
2686 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); |
|
2687 error = ENOTCONN; |
|
2688 } |
|
2689 break; |
|
2690 } |
|
2691 case SCTP_MAX_BURST: |
|
2692 { |
|
2693 #if defined(__FreeBSD__) && __FreeBSD_version < 900000 |
|
2694 uint8_t *value; |
|
2695 |
|
2696 SCTP_CHECK_AND_CAST(value, optval, uint8_t, *optsize); |
|
2697 |
|
2698 SCTP_INP_RLOCK(inp); |
|
2699 if (inp->sctp_ep.max_burst < 256) { |
|
2700 *value = inp->sctp_ep.max_burst; |
|
2701 } else { |
|
2702 *value = 255; |
|
2703 } |
|
2704 SCTP_INP_RUNLOCK(inp); |
|
2705 *optsize = sizeof(uint8_t); |
|
2706 #else |
|
2707 struct sctp_assoc_value *av; |
|
2708 |
|
2709 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2710 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2711 |
|
2712 if (stcb) { |
|
2713 av->assoc_value = stcb->asoc.max_burst; |
|
2714 SCTP_TCB_UNLOCK(stcb); |
|
2715 } else { |
|
2716 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2717 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2718 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2719 SCTP_INP_RLOCK(inp); |
|
2720 av->assoc_value = inp->sctp_ep.max_burst; |
|
2721 SCTP_INP_RUNLOCK(inp); |
|
2722 } else { |
|
2723 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2724 error = EINVAL; |
|
2725 } |
|
2726 } |
|
2727 if (error == 0) { |
|
2728 *optsize = sizeof(struct sctp_assoc_value); |
|
2729 } |
|
2730 #endif |
|
2731 break; |
|
2732 } |
|
2733 case SCTP_MAXSEG: |
|
2734 { |
|
2735 struct sctp_assoc_value *av; |
|
2736 int ovh; |
|
2737 |
|
2738 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
2739 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
2740 |
|
2741 if (stcb) { |
|
2742 av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); |
|
2743 SCTP_TCB_UNLOCK(stcb); |
|
2744 } else { |
|
2745 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
2746 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
2747 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
2748 SCTP_INP_RLOCK(inp); |
|
2749 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
2750 ovh = SCTP_MED_OVERHEAD; |
|
2751 } else { |
|
2752 ovh = SCTP_MED_V4_OVERHEAD; |
|
2753 } |
|
2754 if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) |
|
2755 av->assoc_value = 0; |
|
2756 else |
|
2757 av->assoc_value = inp->sctp_frag_point - ovh; |
|
2758 SCTP_INP_RUNLOCK(inp); |
|
2759 } else { |
|
2760 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
2761 error = EINVAL; |
|
2762 } |
|
2763 } |
|
2764 if (error == 0) { |
|
2765 *optsize = sizeof(struct sctp_assoc_value); |
|
2766 } |
|
2767 break; |
|
2768 } |
|
2769 case SCTP_GET_STAT_LOG: |
|
2770 error = sctp_fill_stat_log(optval, optsize); |
|
2771 break; |
|
2772 case SCTP_EVENTS: |
|
2773 { |
|
2774 struct sctp_event_subscribe *events; |
|
2775 |
|
2776 SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, *optsize); |
|
2777 memset(events, 0, sizeof(struct sctp_event_subscribe)); |
|
2778 SCTP_INP_RLOCK(inp); |
|
2779 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT)) |
|
2780 events->sctp_data_io_event = 1; |
|
2781 |
|
2782 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT)) |
|
2783 events->sctp_association_event = 1; |
|
2784 |
|
2785 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT)) |
|
2786 events->sctp_address_event = 1; |
|
2787 |
|
2788 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT)) |
|
2789 events->sctp_send_failure_event = 1; |
|
2790 |
|
2791 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR)) |
|
2792 events->sctp_peer_error_event = 1; |
|
2793 |
|
2794 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT)) |
|
2795 events->sctp_shutdown_event = 1; |
|
2796 |
|
2797 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT)) |
|
2798 events->sctp_partial_delivery_event = 1; |
|
2799 |
|
2800 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT)) |
|
2801 events->sctp_adaptation_layer_event = 1; |
|
2802 |
|
2803 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT)) |
|
2804 events->sctp_authentication_event = 1; |
|
2805 |
|
2806 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT)) |
|
2807 events->sctp_sender_dry_event = 1; |
|
2808 |
|
2809 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT)) |
|
2810 events->sctp_stream_reset_event = 1; |
|
2811 SCTP_INP_RUNLOCK(inp); |
|
2812 *optsize = sizeof(struct sctp_event_subscribe); |
|
2813 break; |
|
2814 } |
|
2815 case SCTP_ADAPTATION_LAYER: |
|
2816 { |
|
2817 uint32_t *value; |
|
2818 |
|
2819 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2820 |
|
2821 SCTP_INP_RLOCK(inp); |
|
2822 *value = inp->sctp_ep.adaptation_layer_indicator; |
|
2823 SCTP_INP_RUNLOCK(inp); |
|
2824 *optsize = sizeof(uint32_t); |
|
2825 break; |
|
2826 } |
|
2827 case SCTP_SET_INITIAL_DBG_SEQ: |
|
2828 { |
|
2829 uint32_t *value; |
|
2830 |
|
2831 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2832 SCTP_INP_RLOCK(inp); |
|
2833 *value = inp->sctp_ep.initial_sequence_debug; |
|
2834 SCTP_INP_RUNLOCK(inp); |
|
2835 *optsize = sizeof(uint32_t); |
|
2836 break; |
|
2837 } |
|
2838 case SCTP_GET_LOCAL_ADDR_SIZE: |
|
2839 { |
|
2840 uint32_t *value; |
|
2841 |
|
2842 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2843 SCTP_INP_RLOCK(inp); |
|
2844 *value = sctp_count_max_addresses(inp); |
|
2845 SCTP_INP_RUNLOCK(inp); |
|
2846 *optsize = sizeof(uint32_t); |
|
2847 break; |
|
2848 } |
|
2849 case SCTP_GET_REMOTE_ADDR_SIZE: |
|
2850 { |
|
2851 uint32_t *value; |
|
2852 size_t size; |
|
2853 struct sctp_nets *net; |
|
2854 |
|
2855 SCTP_CHECK_AND_CAST(value, optval, uint32_t, *optsize); |
|
2856 /* FIXME MT: change to sctp_assoc_value? */ |
|
2857 SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value); |
|
2858 |
|
2859 if (stcb) { |
|
2860 size = 0; |
|
2861 /* Count the sizes */ |
|
2862 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
2863 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { |
|
2864 size += sizeof(struct sockaddr_in6); |
|
2865 } else { |
|
2866 switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { |
|
2867 #ifdef INET |
|
2868 case AF_INET: |
|
2869 size += sizeof(struct sockaddr_in); |
|
2870 break; |
|
2871 #endif |
|
2872 #ifdef INET6 |
|
2873 case AF_INET6: |
|
2874 size += sizeof(struct sockaddr_in6); |
|
2875 break; |
|
2876 #endif |
|
2877 #if defined(__Userspace__) |
|
2878 case AF_CONN: |
|
2879 size += sizeof(struct sockaddr_conn); |
|
2880 break; |
|
2881 #endif |
|
2882 default: |
|
2883 break; |
|
2884 } |
|
2885 } |
|
2886 } |
|
2887 SCTP_TCB_UNLOCK(stcb); |
|
2888 *value = (uint32_t) size; |
|
2889 *optsize = sizeof(uint32_t); |
|
2890 } else { |
|
2891 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); |
|
2892 error = ENOTCONN; |
|
2893 } |
|
2894 break; |
|
2895 } |
|
2896 case SCTP_GET_PEER_ADDRESSES: |
|
2897 /* |
|
2898 * Get the address information, an array is passed in to |
|
2899 * fill up we pack it. |
|
2900 */ |
|
2901 { |
|
2902 size_t cpsz, left; |
|
2903 struct sockaddr_storage *sas; |
|
2904 struct sctp_nets *net; |
|
2905 struct sctp_getaddresses *saddr; |
|
2906 |
|
2907 SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); |
|
2908 SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); |
|
2909 |
|
2910 if (stcb) { |
|
2911 left = (*optsize) - sizeof(struct sctp_getaddresses); |
|
2912 *optsize = sizeof(struct sctp_getaddresses); |
|
2913 sas = (struct sockaddr_storage *)&saddr->addr[0]; |
|
2914 |
|
2915 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
2916 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) { |
|
2917 cpsz = sizeof(struct sockaddr_in6); |
|
2918 } else { |
|
2919 switch (((struct sockaddr *)&net->ro._l_addr)->sa_family) { |
|
2920 #ifdef INET |
|
2921 case AF_INET: |
|
2922 cpsz = sizeof(struct sockaddr_in); |
|
2923 break; |
|
2924 #endif |
|
2925 #ifdef INET6 |
|
2926 case AF_INET6: |
|
2927 cpsz = sizeof(struct sockaddr_in6); |
|
2928 break; |
|
2929 #endif |
|
2930 #if defined(__Userspace__) |
|
2931 case AF_CONN: |
|
2932 cpsz = sizeof(struct sockaddr_conn); |
|
2933 break; |
|
2934 #endif |
|
2935 default: |
|
2936 cpsz = 0; |
|
2937 break; |
|
2938 } |
|
2939 } |
|
2940 if (cpsz == 0) { |
|
2941 break; |
|
2942 } |
|
2943 if (left < cpsz) { |
|
2944 /* not enough room. */ |
|
2945 break; |
|
2946 } |
|
2947 #if defined(INET) && defined(INET6) |
|
2948 if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_NEEDS_MAPPED_V4)) && |
|
2949 (((struct sockaddr *)&net->ro._l_addr)->sa_family == AF_INET)) { |
|
2950 /* Must map the address */ |
|
2951 in6_sin_2_v4mapsin6((struct sockaddr_in *)&net->ro._l_addr, |
|
2952 (struct sockaddr_in6 *)sas); |
|
2953 } else { |
|
2954 #endif |
|
2955 memcpy(sas, &net->ro._l_addr, cpsz); |
|
2956 #if defined(INET) && defined(INET6) |
|
2957 } |
|
2958 #endif |
|
2959 ((struct sockaddr_in *)sas)->sin_port = stcb->rport; |
|
2960 |
|
2961 sas = (struct sockaddr_storage *)((caddr_t)sas + cpsz); |
|
2962 left -= cpsz; |
|
2963 *optsize += cpsz; |
|
2964 } |
|
2965 SCTP_TCB_UNLOCK(stcb); |
|
2966 } else { |
|
2967 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
2968 error = ENOENT; |
|
2969 } |
|
2970 break; |
|
2971 } |
|
2972 case SCTP_GET_LOCAL_ADDRESSES: |
|
2973 { |
|
2974 size_t limit, actual; |
|
2975 struct sockaddr_storage *sas; |
|
2976 struct sctp_getaddresses *saddr; |
|
2977 |
|
2978 SCTP_CHECK_AND_CAST(saddr, optval, struct sctp_getaddresses, *optsize); |
|
2979 SCTP_FIND_STCB(inp, stcb, saddr->sget_assoc_id); |
|
2980 |
|
2981 sas = (struct sockaddr_storage *)&saddr->addr[0]; |
|
2982 limit = *optsize - sizeof(sctp_assoc_t); |
|
2983 actual = sctp_fill_up_addresses(inp, stcb, limit, sas); |
|
2984 if (stcb) { |
|
2985 SCTP_TCB_UNLOCK(stcb); |
|
2986 } |
|
2987 *optsize = sizeof(struct sockaddr_storage) + actual; |
|
2988 break; |
|
2989 } |
|
2990 case SCTP_PEER_ADDR_PARAMS: |
|
2991 { |
|
2992 struct sctp_paddrparams *paddrp; |
|
2993 struct sctp_nets *net; |
|
2994 |
|
2995 SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, *optsize); |
|
2996 SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); |
|
2997 |
|
2998 net = NULL; |
|
2999 if (stcb) { |
|
3000 net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); |
|
3001 } else { |
|
3002 /* We increment here since sctp_findassociation_ep_addr() wil |
|
3003 * do a decrement if it finds the stcb as long as the locked |
|
3004 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
3005 */ |
|
3006 SCTP_INP_INCR_REF(inp); |
|
3007 stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddrp->spp_address, &net, NULL, NULL); |
|
3008 if (stcb == NULL) { |
|
3009 SCTP_INP_DECR_REF(inp); |
|
3010 } |
|
3011 } |
|
3012 if (stcb && (net == NULL)) { |
|
3013 struct sockaddr *sa; |
|
3014 |
|
3015 sa = (struct sockaddr *)&paddrp->spp_address; |
|
3016 #ifdef INET |
|
3017 if (sa->sa_family == AF_INET) { |
|
3018 struct sockaddr_in *sin; |
|
3019 |
|
3020 sin = (struct sockaddr_in *)sa; |
|
3021 if (sin->sin_addr.s_addr) { |
|
3022 error = EINVAL; |
|
3023 SCTP_TCB_UNLOCK(stcb); |
|
3024 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3025 break; |
|
3026 } |
|
3027 } else |
|
3028 #endif |
|
3029 #ifdef INET6 |
|
3030 if (sa->sa_family == AF_INET6) { |
|
3031 struct sockaddr_in6 *sin6; |
|
3032 |
|
3033 sin6 = (struct sockaddr_in6 *)sa; |
|
3034 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
3035 error = EINVAL; |
|
3036 SCTP_TCB_UNLOCK(stcb); |
|
3037 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3038 break; |
|
3039 } |
|
3040 } else |
|
3041 #endif |
|
3042 #if defined(__Userspace__) |
|
3043 if (sa->sa_family == AF_CONN) { |
|
3044 struct sockaddr_conn *sconn; |
|
3045 |
|
3046 sconn = (struct sockaddr_conn *)sa; |
|
3047 if (sconn->sconn_addr != NULL) { |
|
3048 error = EINVAL; |
|
3049 SCTP_TCB_UNLOCK(stcb); |
|
3050 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3051 break; |
|
3052 } |
|
3053 } else |
|
3054 #endif |
|
3055 { |
|
3056 error = EAFNOSUPPORT; |
|
3057 SCTP_TCB_UNLOCK(stcb); |
|
3058 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3059 break; |
|
3060 } |
|
3061 } |
|
3062 |
|
3063 if (stcb) { |
|
3064 /* Applies to the specific association */ |
|
3065 paddrp->spp_flags = 0; |
|
3066 if (net) { |
|
3067 int ovh; |
|
3068 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
3069 ovh = SCTP_MED_OVERHEAD; |
|
3070 } else { |
|
3071 ovh = SCTP_MED_V4_OVERHEAD; |
|
3072 } |
|
3073 |
|
3074 paddrp->spp_hbinterval = net->heart_beat_delay; |
|
3075 paddrp->spp_pathmaxrxt = net->failure_threshold; |
|
3076 paddrp->spp_pathmtu = net->mtu - ovh; |
|
3077 /* get flags for HB */ |
|
3078 if (net->dest_state & SCTP_ADDR_NOHB) { |
|
3079 paddrp->spp_flags |= SPP_HB_DISABLE; |
|
3080 } else { |
|
3081 paddrp->spp_flags |= SPP_HB_ENABLE; |
|
3082 } |
|
3083 /* get flags for PMTU */ |
|
3084 if (net->dest_state & SCTP_ADDR_NO_PMTUD) { |
|
3085 paddrp->spp_flags |= SPP_PMTUD_ENABLE; |
|
3086 } else { |
|
3087 paddrp->spp_flags |= SPP_PMTUD_DISABLE; |
|
3088 } |
|
3089 if (net->dscp & 0x01) { |
|
3090 paddrp->spp_dscp = net->dscp & 0xfc; |
|
3091 paddrp->spp_flags |= SPP_DSCP; |
|
3092 } |
|
3093 #ifdef INET6 |
|
3094 if ((net->ro._l_addr.sa.sa_family == AF_INET6) && |
|
3095 (net->flowlabel & 0x80000000)) { |
|
3096 paddrp->spp_ipv6_flowlabel = net->flowlabel & 0x000fffff; |
|
3097 paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; |
|
3098 } |
|
3099 #endif |
|
3100 } else { |
|
3101 /* |
|
3102 * No destination so return default |
|
3103 * value |
|
3104 */ |
|
3105 paddrp->spp_pathmaxrxt = stcb->asoc.def_net_failure; |
|
3106 paddrp->spp_pathmtu = sctp_get_frag_point(stcb, &stcb->asoc); |
|
3107 if (stcb->asoc.default_dscp & 0x01) { |
|
3108 paddrp->spp_dscp = stcb->asoc.default_dscp & 0xfc; |
|
3109 paddrp->spp_flags |= SPP_DSCP; |
|
3110 } |
|
3111 #ifdef INET6 |
|
3112 if (stcb->asoc.default_flowlabel & 0x80000000) { |
|
3113 paddrp->spp_ipv6_flowlabel = stcb->asoc.default_flowlabel & 0x000fffff; |
|
3114 paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; |
|
3115 } |
|
3116 #endif |
|
3117 /* default settings should be these */ |
|
3118 if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { |
|
3119 paddrp->spp_flags |= SPP_HB_DISABLE; |
|
3120 } else { |
|
3121 paddrp->spp_flags |= SPP_HB_ENABLE; |
|
3122 } |
|
3123 if (sctp_stcb_is_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { |
|
3124 paddrp->spp_flags |= SPP_PMTUD_DISABLE; |
|
3125 } else { |
|
3126 paddrp->spp_flags |= SPP_PMTUD_ENABLE; |
|
3127 } |
|
3128 paddrp->spp_hbinterval = stcb->asoc.heart_beat_delay; |
|
3129 } |
|
3130 paddrp->spp_assoc_id = sctp_get_associd(stcb); |
|
3131 SCTP_TCB_UNLOCK(stcb); |
|
3132 } else { |
|
3133 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3134 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3135 (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3136 /* Use endpoint defaults */ |
|
3137 SCTP_INP_RLOCK(inp); |
|
3138 paddrp->spp_pathmaxrxt = inp->sctp_ep.def_net_failure; |
|
3139 paddrp->spp_hbinterval = TICKS_TO_MSEC(inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT]); |
|
3140 paddrp->spp_assoc_id = SCTP_FUTURE_ASSOC; |
|
3141 /* get inp's default */ |
|
3142 if (inp->sctp_ep.default_dscp & 0x01) { |
|
3143 paddrp->spp_dscp = inp->sctp_ep.default_dscp & 0xfc; |
|
3144 paddrp->spp_flags |= SPP_DSCP; |
|
3145 } |
|
3146 #ifdef INET6 |
|
3147 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) && |
|
3148 (inp->sctp_ep.default_flowlabel & 0x80000000)) { |
|
3149 paddrp->spp_ipv6_flowlabel = inp->sctp_ep.default_flowlabel & 0x000fffff; |
|
3150 paddrp->spp_flags |= SPP_IPV6_FLOWLABEL; |
|
3151 } |
|
3152 #endif |
|
3153 /* can't return this */ |
|
3154 paddrp->spp_pathmtu = 0; |
|
3155 |
|
3156 if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT)) { |
|
3157 paddrp->spp_flags |= SPP_HB_ENABLE; |
|
3158 } else { |
|
3159 paddrp->spp_flags |= SPP_HB_DISABLE; |
|
3160 } |
|
3161 if (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD)) { |
|
3162 paddrp->spp_flags |= SPP_PMTUD_ENABLE; |
|
3163 } else { |
|
3164 paddrp->spp_flags |= SPP_PMTUD_DISABLE; |
|
3165 } |
|
3166 SCTP_INP_RUNLOCK(inp); |
|
3167 } else { |
|
3168 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3169 error = EINVAL; |
|
3170 } |
|
3171 } |
|
3172 if (error == 0) { |
|
3173 *optsize = sizeof(struct sctp_paddrparams); |
|
3174 } |
|
3175 break; |
|
3176 } |
|
3177 case SCTP_GET_PEER_ADDR_INFO: |
|
3178 { |
|
3179 struct sctp_paddrinfo *paddri; |
|
3180 struct sctp_nets *net; |
|
3181 |
|
3182 SCTP_CHECK_AND_CAST(paddri, optval, struct sctp_paddrinfo, *optsize); |
|
3183 SCTP_FIND_STCB(inp, stcb, paddri->spinfo_assoc_id); |
|
3184 |
|
3185 net = NULL; |
|
3186 if (stcb) { |
|
3187 net = sctp_findnet(stcb, (struct sockaddr *)&paddri->spinfo_address); |
|
3188 } else { |
|
3189 /* We increment here since sctp_findassociation_ep_addr() wil |
|
3190 * do a decrement if it finds the stcb as long as the locked |
|
3191 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
3192 */ |
|
3193 SCTP_INP_INCR_REF(inp); |
|
3194 stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&paddri->spinfo_address, &net, NULL, NULL); |
|
3195 if (stcb == NULL) { |
|
3196 SCTP_INP_DECR_REF(inp); |
|
3197 } |
|
3198 } |
|
3199 |
|
3200 if ((stcb) && (net)) { |
|
3201 if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { |
|
3202 /* It's unconfirmed */ |
|
3203 paddri->spinfo_state = SCTP_UNCONFIRMED; |
|
3204 } else if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
3205 /* It's active */ |
|
3206 paddri->spinfo_state = SCTP_ACTIVE; |
|
3207 } else { |
|
3208 /* It's inactive */ |
|
3209 paddri->spinfo_state = SCTP_INACTIVE; |
|
3210 } |
|
3211 paddri->spinfo_cwnd = net->cwnd; |
|
3212 paddri->spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; |
|
3213 paddri->spinfo_rto = net->RTO; |
|
3214 paddri->spinfo_assoc_id = sctp_get_associd(stcb); |
|
3215 paddri->spinfo_mtu = net->mtu; |
|
3216 SCTP_TCB_UNLOCK(stcb); |
|
3217 *optsize = sizeof(struct sctp_paddrinfo); |
|
3218 } else { |
|
3219 if (stcb) { |
|
3220 SCTP_TCB_UNLOCK(stcb); |
|
3221 } |
|
3222 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
3223 error = ENOENT; |
|
3224 } |
|
3225 break; |
|
3226 } |
|
3227 case SCTP_PCB_STATUS: |
|
3228 { |
|
3229 struct sctp_pcbinfo *spcb; |
|
3230 |
|
3231 SCTP_CHECK_AND_CAST(spcb, optval, struct sctp_pcbinfo, *optsize); |
|
3232 sctp_fill_pcbinfo(spcb); |
|
3233 *optsize = sizeof(struct sctp_pcbinfo); |
|
3234 break; |
|
3235 } |
|
3236 case SCTP_STATUS: |
|
3237 { |
|
3238 struct sctp_nets *net; |
|
3239 struct sctp_status *sstat; |
|
3240 |
|
3241 SCTP_CHECK_AND_CAST(sstat, optval, struct sctp_status, *optsize); |
|
3242 SCTP_FIND_STCB(inp, stcb, sstat->sstat_assoc_id); |
|
3243 |
|
3244 if (stcb == NULL) { |
|
3245 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3246 error = EINVAL; |
|
3247 break; |
|
3248 } |
|
3249 /* |
|
3250 * I think passing the state is fine since |
|
3251 * sctp_constants.h will be available to the user |
|
3252 * land. |
|
3253 */ |
|
3254 sstat->sstat_state = stcb->asoc.state; |
|
3255 sstat->sstat_assoc_id = sctp_get_associd(stcb); |
|
3256 sstat->sstat_rwnd = stcb->asoc.peers_rwnd; |
|
3257 sstat->sstat_unackdata = stcb->asoc.sent_queue_cnt; |
|
3258 /* |
|
3259 * We can't include chunks that have been passed to |
|
3260 * the socket layer. Only things in queue. |
|
3261 */ |
|
3262 sstat->sstat_penddata = (stcb->asoc.cnt_on_reasm_queue + |
|
3263 stcb->asoc.cnt_on_all_streams); |
|
3264 |
|
3265 |
|
3266 sstat->sstat_instrms = stcb->asoc.streamincnt; |
|
3267 sstat->sstat_outstrms = stcb->asoc.streamoutcnt; |
|
3268 sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); |
|
3269 #ifdef HAVE_SA_LEN |
|
3270 memcpy(&sstat->sstat_primary.spinfo_address, |
|
3271 &stcb->asoc.primary_destination->ro._l_addr, |
|
3272 ((struct sockaddr *)(&stcb->asoc.primary_destination->ro._l_addr))->sa_len); |
|
3273 #else |
|
3274 if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET) { |
|
3275 memcpy(&sstat->sstat_primary.spinfo_address, |
|
3276 &stcb->asoc.primary_destination->ro._l_addr, |
|
3277 sizeof(struct sockaddr_in)); |
|
3278 } else { |
|
3279 memcpy(&sstat->sstat_primary.spinfo_address, |
|
3280 &stcb->asoc.primary_destination->ro._l_addr, |
|
3281 sizeof(struct sockaddr_in6)); |
|
3282 } |
|
3283 #endif |
|
3284 net = stcb->asoc.primary_destination; |
|
3285 ((struct sockaddr_in *)&sstat->sstat_primary.spinfo_address)->sin_port = stcb->rport; |
|
3286 /* |
|
3287 * Again the user can get info from sctp_constants.h |
|
3288 * for what the state of the network is. |
|
3289 */ |
|
3290 if (net->dest_state & SCTP_ADDR_UNCONFIRMED) { |
|
3291 /* It's unconfirmed */ |
|
3292 sstat->sstat_primary.spinfo_state = SCTP_UNCONFIRMED; |
|
3293 } else if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
3294 /* It's active */ |
|
3295 sstat->sstat_primary.spinfo_state = SCTP_ACTIVE; |
|
3296 } else { |
|
3297 /* It's inactive */ |
|
3298 sstat->sstat_primary.spinfo_state = SCTP_INACTIVE; |
|
3299 } |
|
3300 sstat->sstat_primary.spinfo_cwnd = net->cwnd; |
|
3301 sstat->sstat_primary.spinfo_srtt = net->lastsa >> SCTP_RTT_SHIFT; |
|
3302 sstat->sstat_primary.spinfo_rto = net->RTO; |
|
3303 sstat->sstat_primary.spinfo_mtu = net->mtu; |
|
3304 sstat->sstat_primary.spinfo_assoc_id = sctp_get_associd(stcb); |
|
3305 SCTP_TCB_UNLOCK(stcb); |
|
3306 *optsize = sizeof(struct sctp_status); |
|
3307 break; |
|
3308 } |
|
3309 case SCTP_RTOINFO: |
|
3310 { |
|
3311 struct sctp_rtoinfo *srto; |
|
3312 |
|
3313 SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, *optsize); |
|
3314 SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); |
|
3315 |
|
3316 if (stcb) { |
|
3317 srto->srto_initial = stcb->asoc.initial_rto; |
|
3318 srto->srto_max = stcb->asoc.maxrto; |
|
3319 srto->srto_min = stcb->asoc.minrto; |
|
3320 SCTP_TCB_UNLOCK(stcb); |
|
3321 } else { |
|
3322 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3323 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3324 (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3325 SCTP_INP_RLOCK(inp); |
|
3326 srto->srto_initial = inp->sctp_ep.initial_rto; |
|
3327 srto->srto_max = inp->sctp_ep.sctp_maxrto; |
|
3328 srto->srto_min = inp->sctp_ep.sctp_minrto; |
|
3329 SCTP_INP_RUNLOCK(inp); |
|
3330 } else { |
|
3331 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3332 error = EINVAL; |
|
3333 } |
|
3334 } |
|
3335 if (error == 0) { |
|
3336 *optsize = sizeof(struct sctp_rtoinfo); |
|
3337 } |
|
3338 break; |
|
3339 } |
|
3340 case SCTP_TIMEOUTS: |
|
3341 { |
|
3342 struct sctp_timeouts *stimo; |
|
3343 |
|
3344 SCTP_CHECK_AND_CAST(stimo, optval, struct sctp_timeouts, *optsize); |
|
3345 SCTP_FIND_STCB(inp, stcb, stimo->stimo_assoc_id); |
|
3346 |
|
3347 if (stcb) { |
|
3348 stimo->stimo_init= stcb->asoc.timoinit; |
|
3349 stimo->stimo_data= stcb->asoc.timodata; |
|
3350 stimo->stimo_sack= stcb->asoc.timosack; |
|
3351 stimo->stimo_shutdown= stcb->asoc.timoshutdown; |
|
3352 stimo->stimo_heartbeat= stcb->asoc.timoheartbeat; |
|
3353 stimo->stimo_cookie= stcb->asoc.timocookie; |
|
3354 stimo->stimo_shutdownack= stcb->asoc.timoshutdownack; |
|
3355 SCTP_TCB_UNLOCK(stcb); |
|
3356 *optsize = sizeof(struct sctp_timeouts); |
|
3357 } else { |
|
3358 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3359 error = EINVAL; |
|
3360 } |
|
3361 break; |
|
3362 } |
|
3363 case SCTP_ASSOCINFO: |
|
3364 { |
|
3365 struct sctp_assocparams *sasoc; |
|
3366 |
|
3367 SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, *optsize); |
|
3368 SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); |
|
3369 |
|
3370 if (stcb) { |
|
3371 sasoc->sasoc_cookie_life = TICKS_TO_MSEC(stcb->asoc.cookie_life); |
|
3372 sasoc->sasoc_asocmaxrxt = stcb->asoc.max_send_times; |
|
3373 sasoc->sasoc_number_peer_destinations = stcb->asoc.numnets; |
|
3374 sasoc->sasoc_peer_rwnd = stcb->asoc.peers_rwnd; |
|
3375 sasoc->sasoc_local_rwnd = stcb->asoc.my_rwnd; |
|
3376 SCTP_TCB_UNLOCK(stcb); |
|
3377 } else { |
|
3378 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3379 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3380 (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3381 SCTP_INP_RLOCK(inp); |
|
3382 sasoc->sasoc_cookie_life = TICKS_TO_MSEC(inp->sctp_ep.def_cookie_life); |
|
3383 sasoc->sasoc_asocmaxrxt = inp->sctp_ep.max_send_times; |
|
3384 sasoc->sasoc_number_peer_destinations = 0; |
|
3385 sasoc->sasoc_peer_rwnd = 0; |
|
3386 sasoc->sasoc_local_rwnd = sbspace(&inp->sctp_socket->so_rcv); |
|
3387 SCTP_INP_RUNLOCK(inp); |
|
3388 } else { |
|
3389 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3390 error = EINVAL; |
|
3391 } |
|
3392 } |
|
3393 if (error == 0) { |
|
3394 *optsize = sizeof(struct sctp_assocparams); |
|
3395 } |
|
3396 break; |
|
3397 } |
|
3398 case SCTP_DEFAULT_SEND_PARAM: |
|
3399 { |
|
3400 struct sctp_sndrcvinfo *s_info; |
|
3401 |
|
3402 SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, *optsize); |
|
3403 SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); |
|
3404 |
|
3405 if (stcb) { |
|
3406 memcpy(s_info, &stcb->asoc.def_send, sizeof(stcb->asoc.def_send)); |
|
3407 SCTP_TCB_UNLOCK(stcb); |
|
3408 } else { |
|
3409 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3410 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3411 (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3412 SCTP_INP_RLOCK(inp); |
|
3413 memcpy(s_info, &inp->def_send, sizeof(inp->def_send)); |
|
3414 SCTP_INP_RUNLOCK(inp); |
|
3415 } else { |
|
3416 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3417 error = EINVAL; |
|
3418 } |
|
3419 } |
|
3420 if (error == 0) { |
|
3421 *optsize = sizeof(struct sctp_sndrcvinfo); |
|
3422 } |
|
3423 break; |
|
3424 } |
|
3425 case SCTP_INITMSG: |
|
3426 { |
|
3427 struct sctp_initmsg *sinit; |
|
3428 |
|
3429 SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, *optsize); |
|
3430 SCTP_INP_RLOCK(inp); |
|
3431 sinit->sinit_num_ostreams = inp->sctp_ep.pre_open_stream_count; |
|
3432 sinit->sinit_max_instreams = inp->sctp_ep.max_open_streams_intome; |
|
3433 sinit->sinit_max_attempts = inp->sctp_ep.max_init_times; |
|
3434 sinit->sinit_max_init_timeo = inp->sctp_ep.initial_init_rto_max; |
|
3435 SCTP_INP_RUNLOCK(inp); |
|
3436 *optsize = sizeof(struct sctp_initmsg); |
|
3437 break; |
|
3438 } |
|
3439 case SCTP_PRIMARY_ADDR: |
|
3440 /* we allow a "get" operation on this */ |
|
3441 { |
|
3442 struct sctp_setprim *ssp; |
|
3443 |
|
3444 SCTP_CHECK_AND_CAST(ssp, optval, struct sctp_setprim, *optsize); |
|
3445 SCTP_FIND_STCB(inp, stcb, ssp->ssp_assoc_id); |
|
3446 |
|
3447 if (stcb) { |
|
3448 /* simply copy out the sockaddr_storage... */ |
|
3449 size_t len; |
|
3450 |
|
3451 len = *optsize; |
|
3452 #ifdef HAVE_SA_LEN |
|
3453 if (len > stcb->asoc.primary_destination->ro._l_addr.sa.sa_len) |
|
3454 len = stcb->asoc.primary_destination->ro._l_addr.sa.sa_len; |
|
3455 #else |
|
3456 if (stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET && |
|
3457 len > sizeof(struct sockaddr_in)) |
|
3458 len = sizeof(struct sockaddr_in); |
|
3459 else if ( |
|
3460 stcb->asoc.primary_destination->ro._l_addr.sa.sa_family == AF_INET6 && |
|
3461 len > sizeof(struct sockaddr_in6)) |
|
3462 len = sizeof(struct sockaddr_in6); |
|
3463 #endif |
|
3464 |
|
3465 memcpy(&ssp->ssp_addr, |
|
3466 &stcb->asoc.primary_destination->ro._l_addr, |
|
3467 len); |
|
3468 SCTP_TCB_UNLOCK(stcb); |
|
3469 *optsize = sizeof(struct sctp_setprim); |
|
3470 } else { |
|
3471 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3472 error = EINVAL; |
|
3473 } |
|
3474 break; |
|
3475 } |
|
3476 case SCTP_HMAC_IDENT: |
|
3477 { |
|
3478 struct sctp_hmacalgo *shmac; |
|
3479 sctp_hmaclist_t *hmaclist; |
|
3480 uint32_t size; |
|
3481 int i; |
|
3482 |
|
3483 SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, *optsize); |
|
3484 |
|
3485 SCTP_INP_RLOCK(inp); |
|
3486 hmaclist = inp->sctp_ep.local_hmacs; |
|
3487 if (hmaclist == NULL) { |
|
3488 /* no HMACs to return */ |
|
3489 *optsize = sizeof(*shmac); |
|
3490 SCTP_INP_RUNLOCK(inp); |
|
3491 break; |
|
3492 } |
|
3493 /* is there room for all of the hmac ids? */ |
|
3494 size = sizeof(*shmac) + (hmaclist->num_algo * |
|
3495 sizeof(shmac->shmac_idents[0])); |
|
3496 if ((size_t)(*optsize) < size) { |
|
3497 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3498 error = EINVAL; |
|
3499 SCTP_INP_RUNLOCK(inp); |
|
3500 break; |
|
3501 } |
|
3502 /* copy in the list */ |
|
3503 shmac->shmac_number_of_idents = hmaclist->num_algo; |
|
3504 for (i = 0; i < hmaclist->num_algo; i++) { |
|
3505 shmac->shmac_idents[i] = hmaclist->hmac[i]; |
|
3506 } |
|
3507 SCTP_INP_RUNLOCK(inp); |
|
3508 *optsize = size; |
|
3509 break; |
|
3510 } |
|
3511 case SCTP_AUTH_ACTIVE_KEY: |
|
3512 { |
|
3513 struct sctp_authkeyid *scact; |
|
3514 |
|
3515 SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, *optsize); |
|
3516 SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); |
|
3517 |
|
3518 if (stcb) { |
|
3519 /* get the active key on the assoc */ |
|
3520 scact->scact_keynumber = stcb->asoc.authinfo.active_keyid; |
|
3521 SCTP_TCB_UNLOCK(stcb); |
|
3522 } else { |
|
3523 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3524 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3525 (scact->scact_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3526 /* get the endpoint active key */ |
|
3527 SCTP_INP_RLOCK(inp); |
|
3528 scact->scact_keynumber = inp->sctp_ep.default_keyid; |
|
3529 SCTP_INP_RUNLOCK(inp); |
|
3530 } else { |
|
3531 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3532 error = EINVAL; |
|
3533 } |
|
3534 } |
|
3535 if (error == 0) { |
|
3536 *optsize = sizeof(struct sctp_authkeyid); |
|
3537 } |
|
3538 break; |
|
3539 } |
|
3540 case SCTP_LOCAL_AUTH_CHUNKS: |
|
3541 { |
|
3542 struct sctp_authchunks *sac; |
|
3543 sctp_auth_chklist_t *chklist = NULL; |
|
3544 size_t size = 0; |
|
3545 |
|
3546 SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); |
|
3547 SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); |
|
3548 |
|
3549 if (stcb) { |
|
3550 /* get off the assoc */ |
|
3551 chklist = stcb->asoc.local_auth_chunks; |
|
3552 /* is there enough space? */ |
|
3553 size = sctp_auth_get_chklist_size(chklist); |
|
3554 if (*optsize < (sizeof(struct sctp_authchunks) + size)) { |
|
3555 error = EINVAL; |
|
3556 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3557 } else { |
|
3558 /* copy in the chunks */ |
|
3559 (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); |
|
3560 sac->gauth_number_of_chunks = (uint32_t)size; |
|
3561 *optsize = sizeof(struct sctp_authchunks) + size; |
|
3562 } |
|
3563 SCTP_TCB_UNLOCK(stcb); |
|
3564 } else { |
|
3565 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3566 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3567 (sac->gauth_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3568 /* get off the endpoint */ |
|
3569 SCTP_INP_RLOCK(inp); |
|
3570 chklist = inp->sctp_ep.local_auth_chunks; |
|
3571 /* is there enough space? */ |
|
3572 size = sctp_auth_get_chklist_size(chklist); |
|
3573 if (*optsize < (sizeof(struct sctp_authchunks) + size)) { |
|
3574 error = EINVAL; |
|
3575 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3576 } else { |
|
3577 /* copy in the chunks */ |
|
3578 (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); |
|
3579 sac->gauth_number_of_chunks = (uint32_t)size; |
|
3580 *optsize = sizeof(struct sctp_authchunks) + size; |
|
3581 } |
|
3582 SCTP_INP_RUNLOCK(inp); |
|
3583 } else { |
|
3584 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3585 error = EINVAL; |
|
3586 } |
|
3587 } |
|
3588 break; |
|
3589 } |
|
3590 case SCTP_PEER_AUTH_CHUNKS: |
|
3591 { |
|
3592 struct sctp_authchunks *sac; |
|
3593 sctp_auth_chklist_t *chklist = NULL; |
|
3594 size_t size = 0; |
|
3595 |
|
3596 SCTP_CHECK_AND_CAST(sac, optval, struct sctp_authchunks, *optsize); |
|
3597 SCTP_FIND_STCB(inp, stcb, sac->gauth_assoc_id); |
|
3598 |
|
3599 if (stcb) { |
|
3600 /* get off the assoc */ |
|
3601 chklist = stcb->asoc.peer_auth_chunks; |
|
3602 /* is there enough space? */ |
|
3603 size = sctp_auth_get_chklist_size(chklist); |
|
3604 if (*optsize < (sizeof(struct sctp_authchunks) + size)) { |
|
3605 error = EINVAL; |
|
3606 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3607 } else { |
|
3608 /* copy in the chunks */ |
|
3609 (void)sctp_serialize_auth_chunks(chklist, sac->gauth_chunks); |
|
3610 sac->gauth_number_of_chunks = (uint32_t)size; |
|
3611 *optsize = sizeof(struct sctp_authchunks) + size; |
|
3612 } |
|
3613 SCTP_TCB_UNLOCK(stcb); |
|
3614 } else { |
|
3615 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
3616 error = ENOENT; |
|
3617 } |
|
3618 break; |
|
3619 } |
|
3620 #if defined(HAVE_SCTP_PEELOFF_SOCKOPT) |
|
3621 case SCTP_PEELOFF: |
|
3622 { |
|
3623 struct sctp_peeloff_opt *peeloff; |
|
3624 |
|
3625 SCTP_CHECK_AND_CAST(peeloff, optval, struct sctp_peeloff_opt, *optsize); |
|
3626 /* do the peeloff */ |
|
3627 error = sctp_peeloff_option(p, peeloff); |
|
3628 if (error == 0) { |
|
3629 *optsize = sizeof(struct sctp_peeloff_opt); |
|
3630 } |
|
3631 } |
|
3632 break; |
|
3633 #endif /* HAVE_SCTP_PEELOFF_SOCKOPT */ |
|
3634 case SCTP_EVENT: |
|
3635 { |
|
3636 struct sctp_event *event; |
|
3637 uint32_t event_type; |
|
3638 |
|
3639 SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, *optsize); |
|
3640 SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); |
|
3641 |
|
3642 switch (event->se_type) { |
|
3643 case SCTP_ASSOC_CHANGE: |
|
3644 event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; |
|
3645 break; |
|
3646 case SCTP_PEER_ADDR_CHANGE: |
|
3647 event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; |
|
3648 break; |
|
3649 case SCTP_REMOTE_ERROR: |
|
3650 event_type = SCTP_PCB_FLAGS_RECVPEERERR; |
|
3651 break; |
|
3652 case SCTP_SEND_FAILED: |
|
3653 event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; |
|
3654 break; |
|
3655 case SCTP_SHUTDOWN_EVENT: |
|
3656 event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; |
|
3657 break; |
|
3658 case SCTP_ADAPTATION_INDICATION: |
|
3659 event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; |
|
3660 break; |
|
3661 case SCTP_PARTIAL_DELIVERY_EVENT: |
|
3662 event_type = SCTP_PCB_FLAGS_PDAPIEVNT; |
|
3663 break; |
|
3664 case SCTP_AUTHENTICATION_EVENT: |
|
3665 event_type = SCTP_PCB_FLAGS_AUTHEVNT; |
|
3666 break; |
|
3667 case SCTP_STREAM_RESET_EVENT: |
|
3668 event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; |
|
3669 break; |
|
3670 case SCTP_SENDER_DRY_EVENT: |
|
3671 event_type = SCTP_PCB_FLAGS_DRYEVNT; |
|
3672 break; |
|
3673 case SCTP_NOTIFICATIONS_STOPPED_EVENT: |
|
3674 event_type = 0; |
|
3675 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); |
|
3676 error = ENOTSUP; |
|
3677 break; |
|
3678 case SCTP_ASSOC_RESET_EVENT: |
|
3679 event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; |
|
3680 break; |
|
3681 case SCTP_STREAM_CHANGE_EVENT: |
|
3682 event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; |
|
3683 break; |
|
3684 case SCTP_SEND_FAILED_EVENT: |
|
3685 event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; |
|
3686 break; |
|
3687 default: |
|
3688 event_type = 0; |
|
3689 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3690 error = EINVAL; |
|
3691 break; |
|
3692 } |
|
3693 if (event_type > 0) { |
|
3694 if (stcb) { |
|
3695 event->se_on = sctp_stcb_is_feature_on(inp, stcb, event_type); |
|
3696 SCTP_TCB_UNLOCK(stcb); |
|
3697 } else { |
|
3698 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3699 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3700 (event->se_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3701 SCTP_INP_RLOCK(inp); |
|
3702 event->se_on = sctp_is_feature_on(inp, event_type); |
|
3703 SCTP_INP_RUNLOCK(inp); |
|
3704 } else { |
|
3705 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3706 error = EINVAL; |
|
3707 } |
|
3708 } |
|
3709 } |
|
3710 if (error == 0) { |
|
3711 *optsize = sizeof(struct sctp_event); |
|
3712 } |
|
3713 break; |
|
3714 } |
|
3715 case SCTP_RECVRCVINFO: |
|
3716 { |
|
3717 int onoff; |
|
3718 |
|
3719 if (*optsize < sizeof(int)) { |
|
3720 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3721 error = EINVAL; |
|
3722 } else { |
|
3723 SCTP_INP_RLOCK(inp); |
|
3724 onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); |
|
3725 SCTP_INP_RUNLOCK(inp); |
|
3726 } |
|
3727 if (error == 0) { |
|
3728 /* return the option value */ |
|
3729 *(int *)optval = onoff; |
|
3730 *optsize = sizeof(int); |
|
3731 } |
|
3732 break; |
|
3733 } |
|
3734 case SCTP_RECVNXTINFO: |
|
3735 { |
|
3736 int onoff; |
|
3737 |
|
3738 if (*optsize < sizeof(int)) { |
|
3739 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3740 error = EINVAL; |
|
3741 } else { |
|
3742 SCTP_INP_RLOCK(inp); |
|
3743 onoff = sctp_is_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); |
|
3744 SCTP_INP_RUNLOCK(inp); |
|
3745 } |
|
3746 if (error == 0) { |
|
3747 /* return the option value */ |
|
3748 *(int *)optval = onoff; |
|
3749 *optsize = sizeof(int); |
|
3750 } |
|
3751 break; |
|
3752 } |
|
3753 case SCTP_DEFAULT_SNDINFO: |
|
3754 { |
|
3755 struct sctp_sndinfo *info; |
|
3756 |
|
3757 SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, *optsize); |
|
3758 SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); |
|
3759 |
|
3760 if (stcb) { |
|
3761 info->snd_sid = stcb->asoc.def_send.sinfo_stream; |
|
3762 info->snd_flags = stcb->asoc.def_send.sinfo_flags; |
|
3763 info->snd_flags &= 0xfff0; |
|
3764 info->snd_ppid = stcb->asoc.def_send.sinfo_ppid; |
|
3765 info->snd_context = stcb->asoc.def_send.sinfo_context; |
|
3766 SCTP_TCB_UNLOCK(stcb); |
|
3767 } else { |
|
3768 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3769 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3770 (info->snd_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3771 SCTP_INP_RLOCK(inp); |
|
3772 info->snd_sid = inp->def_send.sinfo_stream; |
|
3773 info->snd_flags = inp->def_send.sinfo_flags; |
|
3774 info->snd_flags &= 0xfff0; |
|
3775 info->snd_ppid = inp->def_send.sinfo_ppid; |
|
3776 info->snd_context = inp->def_send.sinfo_context; |
|
3777 SCTP_INP_RUNLOCK(inp); |
|
3778 } else { |
|
3779 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3780 error = EINVAL; |
|
3781 } |
|
3782 } |
|
3783 if (error == 0) { |
|
3784 *optsize = sizeof(struct sctp_sndinfo); |
|
3785 } |
|
3786 break; |
|
3787 } |
|
3788 case SCTP_DEFAULT_PRINFO: |
|
3789 { |
|
3790 struct sctp_default_prinfo *info; |
|
3791 |
|
3792 SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, *optsize); |
|
3793 SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); |
|
3794 |
|
3795 if (stcb) { |
|
3796 info->pr_policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); |
|
3797 info->pr_value = stcb->asoc.def_send.sinfo_timetolive; |
|
3798 SCTP_TCB_UNLOCK(stcb); |
|
3799 } else { |
|
3800 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3801 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3802 (info->pr_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3803 SCTP_INP_RLOCK(inp); |
|
3804 info->pr_policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); |
|
3805 info->pr_value = inp->def_send.sinfo_timetolive; |
|
3806 SCTP_INP_RUNLOCK(inp); |
|
3807 } else { |
|
3808 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3809 error = EINVAL; |
|
3810 } |
|
3811 } |
|
3812 if (error == 0) { |
|
3813 *optsize = sizeof(struct sctp_default_prinfo); |
|
3814 } |
|
3815 break; |
|
3816 } |
|
3817 case SCTP_PEER_ADDR_THLDS: |
|
3818 { |
|
3819 struct sctp_paddrthlds *thlds; |
|
3820 struct sctp_nets *net; |
|
3821 |
|
3822 SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, *optsize); |
|
3823 SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); |
|
3824 |
|
3825 net = NULL; |
|
3826 if (stcb) { |
|
3827 net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_address); |
|
3828 } else { |
|
3829 /* We increment here since sctp_findassociation_ep_addr() wil |
|
3830 * do a decrement if it finds the stcb as long as the locked |
|
3831 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
3832 */ |
|
3833 SCTP_INP_INCR_REF(inp); |
|
3834 stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&thlds->spt_address, &net, NULL, NULL); |
|
3835 if (stcb == NULL) { |
|
3836 SCTP_INP_DECR_REF(inp); |
|
3837 } |
|
3838 } |
|
3839 if (stcb && (net == NULL)) { |
|
3840 struct sockaddr *sa; |
|
3841 |
|
3842 sa = (struct sockaddr *)&thlds->spt_address; |
|
3843 #ifdef INET |
|
3844 if (sa->sa_family == AF_INET) { |
|
3845 struct sockaddr_in *sin; |
|
3846 |
|
3847 sin = (struct sockaddr_in *)sa; |
|
3848 if (sin->sin_addr.s_addr) { |
|
3849 error = EINVAL; |
|
3850 SCTP_TCB_UNLOCK(stcb); |
|
3851 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3852 break; |
|
3853 } |
|
3854 } else |
|
3855 #endif |
|
3856 #ifdef INET6 |
|
3857 if (sa->sa_family == AF_INET6) { |
|
3858 struct sockaddr_in6 *sin6; |
|
3859 |
|
3860 sin6 = (struct sockaddr_in6 *)sa; |
|
3861 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
3862 error = EINVAL; |
|
3863 SCTP_TCB_UNLOCK(stcb); |
|
3864 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3865 break; |
|
3866 } |
|
3867 } else |
|
3868 #endif |
|
3869 #if defined(__Userspace__) |
|
3870 if (sa->sa_family == AF_CONN) { |
|
3871 struct sockaddr_conn *sconn; |
|
3872 |
|
3873 sconn = (struct sockaddr_conn *)sa; |
|
3874 if (sconn->sconn_addr != NULL) { |
|
3875 error = EINVAL; |
|
3876 SCTP_TCB_UNLOCK(stcb); |
|
3877 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3878 break; |
|
3879 } |
|
3880 } else |
|
3881 #endif |
|
3882 { |
|
3883 error = EAFNOSUPPORT; |
|
3884 SCTP_TCB_UNLOCK(stcb); |
|
3885 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3886 break; |
|
3887 } |
|
3888 } |
|
3889 |
|
3890 if (stcb) { |
|
3891 if (net) { |
|
3892 thlds->spt_pathmaxrxt = net->failure_threshold; |
|
3893 thlds->spt_pathpfthld = net->pf_threshold; |
|
3894 } else { |
|
3895 thlds->spt_pathmaxrxt = stcb->asoc.def_net_failure; |
|
3896 thlds->spt_pathpfthld = stcb->asoc.def_net_pf_threshold; |
|
3897 } |
|
3898 thlds->spt_assoc_id = sctp_get_associd(stcb); |
|
3899 SCTP_TCB_UNLOCK(stcb); |
|
3900 } else { |
|
3901 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
3902 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
3903 (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
3904 /* Use endpoint defaults */ |
|
3905 SCTP_INP_RLOCK(inp); |
|
3906 thlds->spt_pathmaxrxt = inp->sctp_ep.def_net_failure; |
|
3907 thlds->spt_pathpfthld = inp->sctp_ep.def_net_pf_threshold; |
|
3908 SCTP_INP_RUNLOCK(inp); |
|
3909 } else { |
|
3910 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
3911 error = EINVAL; |
|
3912 } |
|
3913 } |
|
3914 if (error == 0) { |
|
3915 *optsize = sizeof(struct sctp_paddrthlds); |
|
3916 } |
|
3917 break; |
|
3918 } |
|
3919 case SCTP_REMOTE_UDP_ENCAPS_PORT: |
|
3920 { |
|
3921 struct sctp_udpencaps *encaps; |
|
3922 struct sctp_nets *net; |
|
3923 |
|
3924 SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, *optsize); |
|
3925 SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); |
|
3926 |
|
3927 if (stcb) { |
|
3928 net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); |
|
3929 } else { |
|
3930 /* We increment here since sctp_findassociation_ep_addr() wil |
|
3931 * do a decrement if it finds the stcb as long as the locked |
|
3932 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
3933 */ |
|
3934 net = NULL; |
|
3935 SCTP_INP_INCR_REF(inp); |
|
3936 stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); |
|
3937 if (stcb == NULL) { |
|
3938 SCTP_INP_DECR_REF(inp); |
|
3939 } |
|
3940 } |
|
3941 if (stcb && (net == NULL)) { |
|
3942 struct sockaddr *sa; |
|
3943 |
|
3944 sa = (struct sockaddr *)&encaps->sue_address; |
|
3945 #ifdef INET |
|
3946 if (sa->sa_family == AF_INET) { |
|
3947 struct sockaddr_in *sin; |
|
3948 |
|
3949 sin = (struct sockaddr_in *)sa; |
|
3950 if (sin->sin_addr.s_addr) { |
|
3951 error = EINVAL; |
|
3952 SCTP_TCB_UNLOCK(stcb); |
|
3953 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3954 break; |
|
3955 } |
|
3956 } else |
|
3957 #endif |
|
3958 #ifdef INET6 |
|
3959 if (sa->sa_family == AF_INET6) { |
|
3960 struct sockaddr_in6 *sin6; |
|
3961 |
|
3962 sin6 = (struct sockaddr_in6 *)sa; |
|
3963 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
3964 error = EINVAL; |
|
3965 SCTP_TCB_UNLOCK(stcb); |
|
3966 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3967 break; |
|
3968 } |
|
3969 } else |
|
3970 #endif |
|
3971 #if defined(__Userspace__) |
|
3972 if (sa->sa_family == AF_CONN) { |
|
3973 struct sockaddr_conn *sconn; |
|
3974 |
|
3975 sconn = (struct sockaddr_conn *)sa; |
|
3976 if (sconn->sconn_addr != NULL) { |
|
3977 error = EINVAL; |
|
3978 SCTP_TCB_UNLOCK(stcb); |
|
3979 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3980 break; |
|
3981 } |
|
3982 } else |
|
3983 #endif |
|
3984 { |
|
3985 error = EAFNOSUPPORT; |
|
3986 SCTP_TCB_UNLOCK(stcb); |
|
3987 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
3988 break; |
|
3989 } |
|
3990 } |
|
3991 |
|
3992 if (stcb) { |
|
3993 if (net) { |
|
3994 encaps->sue_port = net->port; |
|
3995 } else { |
|
3996 encaps->sue_port = stcb->asoc.port; |
|
3997 } |
|
3998 SCTP_TCB_UNLOCK(stcb); |
|
3999 } else { |
|
4000 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4001 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4002 (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
4003 SCTP_INP_RLOCK(inp); |
|
4004 encaps->sue_port = inp->sctp_ep.port; |
|
4005 SCTP_INP_RUNLOCK(inp); |
|
4006 } else { |
|
4007 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4008 error = EINVAL; |
|
4009 } |
|
4010 } |
|
4011 if (error == 0) { |
|
4012 *optsize = sizeof(struct sctp_udpencaps); |
|
4013 } |
|
4014 break; |
|
4015 } |
|
4016 case SCTP_ENABLE_STREAM_RESET: |
|
4017 { |
|
4018 struct sctp_assoc_value *av; |
|
4019 |
|
4020 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); |
|
4021 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4022 |
|
4023 if (stcb) { |
|
4024 av->assoc_value = (uint32_t)stcb->asoc.local_strreset_support; |
|
4025 SCTP_TCB_UNLOCK(stcb); |
|
4026 } else { |
|
4027 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4028 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4029 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
4030 SCTP_INP_RLOCK(inp); |
|
4031 av->assoc_value = (uint32_t)inp->local_strreset_support; |
|
4032 SCTP_INP_RUNLOCK(inp); |
|
4033 } else { |
|
4034 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4035 error = EINVAL; |
|
4036 } |
|
4037 } |
|
4038 if (error == 0) { |
|
4039 *optsize = sizeof(struct sctp_assoc_value); |
|
4040 } |
|
4041 break; |
|
4042 } |
|
4043 default: |
|
4044 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); |
|
4045 error = ENOPROTOOPT; |
|
4046 break; |
|
4047 } /* end switch (sopt->sopt_name) */ |
|
4048 if (error) { |
|
4049 *optsize = 0; |
|
4050 } |
|
4051 return (error); |
|
4052 } |
|
4053 |
|
4054 #if defined(__Panda__) || defined(__Userspace__) |
|
4055 int |
|
4056 #else |
|
4057 static int |
|
4058 #endif |
|
4059 sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, |
|
4060 void *p) |
|
4061 { |
|
4062 int error, set_opt; |
|
4063 uint32_t *mopt; |
|
4064 struct sctp_tcb *stcb = NULL; |
|
4065 struct sctp_inpcb *inp = NULL; |
|
4066 uint32_t vrf_id; |
|
4067 |
|
4068 if (optval == NULL) { |
|
4069 SCTP_PRINTF("optval is NULL\n"); |
|
4070 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4071 return (EINVAL); |
|
4072 } |
|
4073 inp = (struct sctp_inpcb *)so->so_pcb; |
|
4074 if (inp == NULL) { |
|
4075 SCTP_PRINTF("inp is NULL?\n"); |
|
4076 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4077 return (EINVAL); |
|
4078 } |
|
4079 vrf_id = inp->def_vrf_id; |
|
4080 |
|
4081 error = 0; |
|
4082 switch (optname) { |
|
4083 case SCTP_NODELAY: |
|
4084 case SCTP_AUTOCLOSE: |
|
4085 case SCTP_AUTO_ASCONF: |
|
4086 case SCTP_EXPLICIT_EOR: |
|
4087 case SCTP_DISABLE_FRAGMENTS: |
|
4088 case SCTP_USE_EXT_RCVINFO: |
|
4089 case SCTP_I_WANT_MAPPED_V4_ADDR: |
|
4090 /* copy in the option value */ |
|
4091 SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); |
|
4092 set_opt = 0; |
|
4093 if (error) |
|
4094 break; |
|
4095 switch (optname) { |
|
4096 case SCTP_DISABLE_FRAGMENTS: |
|
4097 set_opt = SCTP_PCB_FLAGS_NO_FRAGMENT; |
|
4098 break; |
|
4099 case SCTP_AUTO_ASCONF: |
|
4100 /* |
|
4101 * NOTE: we don't really support this flag |
|
4102 */ |
|
4103 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
4104 /* only valid for bound all sockets */ |
|
4105 if ((SCTP_BASE_SYSCTL(sctp_auto_asconf) == 0) && |
|
4106 (*mopt != 0)) { |
|
4107 /* forbidden by admin */ |
|
4108 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EPERM); |
|
4109 return (EPERM); |
|
4110 } |
|
4111 set_opt = SCTP_PCB_FLAGS_AUTO_ASCONF; |
|
4112 } else { |
|
4113 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4114 return (EINVAL); |
|
4115 } |
|
4116 break; |
|
4117 case SCTP_EXPLICIT_EOR: |
|
4118 set_opt = SCTP_PCB_FLAGS_EXPLICIT_EOR; |
|
4119 break; |
|
4120 case SCTP_USE_EXT_RCVINFO: |
|
4121 set_opt = SCTP_PCB_FLAGS_EXT_RCVINFO; |
|
4122 break; |
|
4123 case SCTP_I_WANT_MAPPED_V4_ADDR: |
|
4124 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
4125 set_opt = SCTP_PCB_FLAGS_NEEDS_MAPPED_V4; |
|
4126 } else { |
|
4127 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4128 return (EINVAL); |
|
4129 } |
|
4130 break; |
|
4131 case SCTP_NODELAY: |
|
4132 set_opt = SCTP_PCB_FLAGS_NODELAY; |
|
4133 break; |
|
4134 case SCTP_AUTOCLOSE: |
|
4135 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4136 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
4137 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4138 return (EINVAL); |
|
4139 } |
|
4140 set_opt = SCTP_PCB_FLAGS_AUTOCLOSE; |
|
4141 /* |
|
4142 * The value is in ticks. Note this does not effect |
|
4143 * old associations, only new ones. |
|
4144 */ |
|
4145 inp->sctp_ep.auto_close_time = SEC_TO_TICKS(*mopt); |
|
4146 break; |
|
4147 } |
|
4148 SCTP_INP_WLOCK(inp); |
|
4149 if (*mopt != 0) { |
|
4150 sctp_feature_on(inp, set_opt); |
|
4151 } else { |
|
4152 sctp_feature_off(inp, set_opt); |
|
4153 } |
|
4154 SCTP_INP_WUNLOCK(inp); |
|
4155 break; |
|
4156 case SCTP_REUSE_PORT: |
|
4157 { |
|
4158 SCTP_CHECK_AND_CAST(mopt, optval, uint32_t, optsize); |
|
4159 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { |
|
4160 /* Can't set it after we are bound */ |
|
4161 error = EINVAL; |
|
4162 break; |
|
4163 } |
|
4164 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE)) { |
|
4165 /* Can't do this for a 1-m socket */ |
|
4166 error = EINVAL; |
|
4167 break; |
|
4168 } |
|
4169 if (optval) |
|
4170 sctp_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE); |
|
4171 else |
|
4172 sctp_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE); |
|
4173 break; |
|
4174 } |
|
4175 case SCTP_PARTIAL_DELIVERY_POINT: |
|
4176 { |
|
4177 uint32_t *value; |
|
4178 |
|
4179 SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); |
|
4180 if (*value > SCTP_SB_LIMIT_RCV(so)) { |
|
4181 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4182 error = EINVAL; |
|
4183 break; |
|
4184 } |
|
4185 inp->partial_delivery_point = *value; |
|
4186 break; |
|
4187 } |
|
4188 case SCTP_FRAGMENT_INTERLEAVE: |
|
4189 /* not yet until we re-write sctp_recvmsg() */ |
|
4190 { |
|
4191 uint32_t *level; |
|
4192 |
|
4193 SCTP_CHECK_AND_CAST(level, optval, uint32_t, optsize); |
|
4194 if (*level == SCTP_FRAG_LEVEL_2) { |
|
4195 sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); |
|
4196 sctp_feature_on(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); |
|
4197 } else if (*level == SCTP_FRAG_LEVEL_1) { |
|
4198 sctp_feature_on(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); |
|
4199 sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); |
|
4200 } else if (*level == SCTP_FRAG_LEVEL_0) { |
|
4201 sctp_feature_off(inp, SCTP_PCB_FLAGS_FRAG_INTERLEAVE); |
|
4202 sctp_feature_off(inp, SCTP_PCB_FLAGS_INTERLEAVE_STRMS); |
|
4203 |
|
4204 } else { |
|
4205 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4206 error = EINVAL; |
|
4207 } |
|
4208 break; |
|
4209 } |
|
4210 case SCTP_CMT_ON_OFF: |
|
4211 if (SCTP_BASE_SYSCTL(sctp_cmt_on_off)) { |
|
4212 struct sctp_assoc_value *av; |
|
4213 |
|
4214 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
4215 if (av->assoc_value > SCTP_CMT_MAX) { |
|
4216 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4217 error = EINVAL; |
|
4218 break; |
|
4219 } |
|
4220 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4221 if (stcb) { |
|
4222 stcb->asoc.sctp_cmt_on_off = av->assoc_value; |
|
4223 SCTP_TCB_UNLOCK(stcb); |
|
4224 } else { |
|
4225 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4226 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4227 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
4228 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4229 SCTP_INP_WLOCK(inp); |
|
4230 inp->sctp_cmt_on_off = av->assoc_value; |
|
4231 SCTP_INP_WUNLOCK(inp); |
|
4232 } |
|
4233 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
4234 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4235 SCTP_INP_RLOCK(inp); |
|
4236 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4237 SCTP_TCB_LOCK(stcb); |
|
4238 stcb->asoc.sctp_cmt_on_off = av->assoc_value; |
|
4239 SCTP_TCB_UNLOCK(stcb); |
|
4240 } |
|
4241 SCTP_INP_RUNLOCK(inp); |
|
4242 } |
|
4243 } |
|
4244 } else { |
|
4245 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); |
|
4246 error = ENOPROTOOPT; |
|
4247 } |
|
4248 break; |
|
4249 case SCTP_PLUGGABLE_CC: |
|
4250 { |
|
4251 struct sctp_assoc_value *av; |
|
4252 struct sctp_nets *net; |
|
4253 |
|
4254 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
4255 if ((av->assoc_value != SCTP_CC_RFC2581) && |
|
4256 (av->assoc_value != SCTP_CC_HSTCP) && |
|
4257 (av->assoc_value != SCTP_CC_HTCP) && |
|
4258 (av->assoc_value != SCTP_CC_RTCC)) { |
|
4259 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4260 error = EINVAL; |
|
4261 break; |
|
4262 } |
|
4263 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4264 if (stcb) { |
|
4265 stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; |
|
4266 stcb->asoc.congestion_control_module = av->assoc_value; |
|
4267 if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { |
|
4268 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
4269 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); |
|
4270 } |
|
4271 } |
|
4272 SCTP_TCB_UNLOCK(stcb); |
|
4273 } else { |
|
4274 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4275 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4276 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
4277 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4278 SCTP_INP_WLOCK(inp); |
|
4279 inp->sctp_ep.sctp_default_cc_module = av->assoc_value; |
|
4280 SCTP_INP_WUNLOCK(inp); |
|
4281 } |
|
4282 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
4283 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4284 SCTP_INP_RLOCK(inp); |
|
4285 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4286 SCTP_TCB_LOCK(stcb); |
|
4287 stcb->asoc.cc_functions = sctp_cc_functions[av->assoc_value]; |
|
4288 stcb->asoc.congestion_control_module = av->assoc_value; |
|
4289 if (stcb->asoc.cc_functions.sctp_set_initial_cc_param != NULL) { |
|
4290 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
4291 stcb->asoc.cc_functions.sctp_set_initial_cc_param(stcb, net); |
|
4292 } |
|
4293 } |
|
4294 SCTP_TCB_UNLOCK(stcb); |
|
4295 } |
|
4296 SCTP_INP_RUNLOCK(inp); |
|
4297 } |
|
4298 } |
|
4299 break; |
|
4300 } |
|
4301 case SCTP_CC_OPTION: |
|
4302 { |
|
4303 struct sctp_cc_option *cc_opt; |
|
4304 |
|
4305 SCTP_CHECK_AND_CAST(cc_opt, optval, struct sctp_cc_option, optsize); |
|
4306 SCTP_FIND_STCB(inp, stcb, cc_opt->aid_value.assoc_id); |
|
4307 if (stcb == NULL) { |
|
4308 if (cc_opt->aid_value.assoc_id == SCTP_CURRENT_ASSOC) { |
|
4309 SCTP_INP_RLOCK(inp); |
|
4310 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4311 SCTP_TCB_LOCK(stcb); |
|
4312 if (stcb->asoc.cc_functions.sctp_cwnd_socket_option) { |
|
4313 (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, cc_opt); |
|
4314 } |
|
4315 SCTP_TCB_UNLOCK(stcb); |
|
4316 } |
|
4317 SCTP_INP_RUNLOCK(inp); |
|
4318 } else { |
|
4319 error = EINVAL; |
|
4320 } |
|
4321 } else { |
|
4322 if (stcb->asoc.cc_functions.sctp_cwnd_socket_option == NULL) { |
|
4323 error = ENOTSUP; |
|
4324 } else { |
|
4325 error = (*stcb->asoc.cc_functions.sctp_cwnd_socket_option)(stcb, 1, |
|
4326 cc_opt); |
|
4327 } |
|
4328 SCTP_TCB_UNLOCK(stcb); |
|
4329 } |
|
4330 break; |
|
4331 } |
|
4332 case SCTP_PLUGGABLE_SS: |
|
4333 { |
|
4334 struct sctp_assoc_value *av; |
|
4335 |
|
4336 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
4337 if ((av->assoc_value != SCTP_SS_DEFAULT) && |
|
4338 (av->assoc_value != SCTP_SS_ROUND_ROBIN) && |
|
4339 (av->assoc_value != SCTP_SS_ROUND_ROBIN_PACKET) && |
|
4340 (av->assoc_value != SCTP_SS_PRIORITY) && |
|
4341 (av->assoc_value != SCTP_SS_FAIR_BANDWITH) && |
|
4342 (av->assoc_value != SCTP_SS_FIRST_COME)) { |
|
4343 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4344 error = EINVAL; |
|
4345 break; |
|
4346 } |
|
4347 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4348 if (stcb) { |
|
4349 stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); |
|
4350 stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; |
|
4351 stcb->asoc.stream_scheduling_module = av->assoc_value; |
|
4352 stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); |
|
4353 SCTP_TCB_UNLOCK(stcb); |
|
4354 } else { |
|
4355 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4356 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4357 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
4358 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4359 SCTP_INP_WLOCK(inp); |
|
4360 inp->sctp_ep.sctp_default_ss_module = av->assoc_value; |
|
4361 SCTP_INP_WUNLOCK(inp); |
|
4362 } |
|
4363 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
4364 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4365 SCTP_INP_RLOCK(inp); |
|
4366 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4367 SCTP_TCB_LOCK(stcb); |
|
4368 stcb->asoc.ss_functions.sctp_ss_clear(stcb, &stcb->asoc, 1, 1); |
|
4369 stcb->asoc.ss_functions = sctp_ss_functions[av->assoc_value]; |
|
4370 stcb->asoc.stream_scheduling_module = av->assoc_value; |
|
4371 stcb->asoc.ss_functions.sctp_ss_init(stcb, &stcb->asoc, 1); |
|
4372 SCTP_TCB_UNLOCK(stcb); |
|
4373 } |
|
4374 SCTP_INP_RUNLOCK(inp); |
|
4375 } |
|
4376 } |
|
4377 break; |
|
4378 } |
|
4379 case SCTP_SS_VALUE: |
|
4380 { |
|
4381 struct sctp_stream_value *av; |
|
4382 |
|
4383 SCTP_CHECK_AND_CAST(av, optval, struct sctp_stream_value, optsize); |
|
4384 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4385 if (stcb) { |
|
4386 if (stcb->asoc.ss_functions.sctp_ss_set_value(stcb, &stcb->asoc, &stcb->asoc.strmout[av->stream_id], |
|
4387 av->stream_value) < 0) { |
|
4388 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4389 error = EINVAL; |
|
4390 } |
|
4391 SCTP_TCB_UNLOCK(stcb); |
|
4392 } else { |
|
4393 if (av->assoc_id == SCTP_CURRENT_ASSOC) { |
|
4394 SCTP_INP_RLOCK(inp); |
|
4395 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4396 SCTP_TCB_LOCK(stcb); |
|
4397 stcb->asoc.ss_functions.sctp_ss_set_value(stcb, |
|
4398 &stcb->asoc, |
|
4399 &stcb->asoc.strmout[av->stream_id], |
|
4400 av->stream_value); |
|
4401 SCTP_TCB_UNLOCK(stcb); |
|
4402 } |
|
4403 SCTP_INP_RUNLOCK(inp); |
|
4404 |
|
4405 } else { |
|
4406 /* Can't set stream value without association */ |
|
4407 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4408 error = EINVAL; |
|
4409 } |
|
4410 } |
|
4411 break; |
|
4412 } |
|
4413 case SCTP_CLR_STAT_LOG: |
|
4414 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
4415 error = EOPNOTSUPP; |
|
4416 break; |
|
4417 case SCTP_CONTEXT: |
|
4418 { |
|
4419 struct sctp_assoc_value *av; |
|
4420 |
|
4421 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
4422 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4423 |
|
4424 if (stcb) { |
|
4425 stcb->asoc.context = av->assoc_value; |
|
4426 SCTP_TCB_UNLOCK(stcb); |
|
4427 } else { |
|
4428 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4429 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4430 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
4431 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4432 SCTP_INP_WLOCK(inp); |
|
4433 inp->sctp_context = av->assoc_value; |
|
4434 SCTP_INP_WUNLOCK(inp); |
|
4435 } |
|
4436 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
4437 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4438 SCTP_INP_RLOCK(inp); |
|
4439 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4440 SCTP_TCB_LOCK(stcb); |
|
4441 stcb->asoc.context = av->assoc_value; |
|
4442 SCTP_TCB_UNLOCK(stcb); |
|
4443 } |
|
4444 SCTP_INP_RUNLOCK(inp); |
|
4445 } |
|
4446 } |
|
4447 break; |
|
4448 } |
|
4449 case SCTP_VRF_ID: |
|
4450 { |
|
4451 uint32_t *default_vrfid; |
|
4452 #ifdef SCTP_MVRF |
|
4453 int i; |
|
4454 #endif |
|
4455 SCTP_CHECK_AND_CAST(default_vrfid, optval, uint32_t, optsize); |
|
4456 if (*default_vrfid > SCTP_MAX_VRF_ID) { |
|
4457 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4458 error = EINVAL; |
|
4459 break; |
|
4460 } |
|
4461 #ifdef SCTP_MVRF |
|
4462 for (i = 0; i < inp->num_vrfs; i++) { |
|
4463 /* The VRF must be in the VRF list */ |
|
4464 if (*default_vrfid == inp->m_vrf_ids[i]) { |
|
4465 SCTP_INP_WLOCK(inp); |
|
4466 inp->def_vrf_id = *default_vrfid; |
|
4467 SCTP_INP_WUNLOCK(inp); |
|
4468 goto sctp_done; |
|
4469 } |
|
4470 } |
|
4471 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4472 error = EINVAL; |
|
4473 #else |
|
4474 inp->def_vrf_id = *default_vrfid; |
|
4475 #endif |
|
4476 #ifdef SCTP_MVRF |
|
4477 sctp_done: |
|
4478 #endif |
|
4479 break; |
|
4480 } |
|
4481 case SCTP_DEL_VRF_ID: |
|
4482 { |
|
4483 #ifdef SCTP_MVRF |
|
4484 uint32_t *del_vrfid; |
|
4485 int i, fnd = 0; |
|
4486 |
|
4487 SCTP_CHECK_AND_CAST(del_vrfid, optval, uint32_t, optsize); |
|
4488 if (*del_vrfid > SCTP_MAX_VRF_ID) { |
|
4489 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4490 error = EINVAL; |
|
4491 break; |
|
4492 } |
|
4493 if (inp->num_vrfs == 1) { |
|
4494 /* Can't delete last one */ |
|
4495 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4496 error = EINVAL; |
|
4497 break; |
|
4498 } |
|
4499 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { |
|
4500 /* Can't add more once you are bound */ |
|
4501 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4502 error = EINVAL; |
|
4503 break; |
|
4504 } |
|
4505 SCTP_INP_WLOCK(inp); |
|
4506 for (i = 0; i < inp->num_vrfs; i++) { |
|
4507 if (*del_vrfid == inp->m_vrf_ids[i]) { |
|
4508 fnd = 1; |
|
4509 break; |
|
4510 } |
|
4511 } |
|
4512 if (!fnd) { |
|
4513 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4514 error = EINVAL; |
|
4515 break; |
|
4516 } |
|
4517 if (i != (inp->num_vrfs - 1)) { |
|
4518 /* Take bottom one and move to this slot */ |
|
4519 inp->m_vrf_ids[i] = inp->m_vrf_ids[(inp->num_vrfs-1)]; |
|
4520 } |
|
4521 if (*del_vrfid == inp->def_vrf_id) { |
|
4522 /* Take the first one as the new default */ |
|
4523 inp->def_vrf_id = inp->m_vrf_ids[0]; |
|
4524 } |
|
4525 /* Drop the number by one killing last one */ |
|
4526 inp->num_vrfs--; |
|
4527 #else |
|
4528 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
4529 error = EOPNOTSUPP; |
|
4530 #endif |
|
4531 break; |
|
4532 } |
|
4533 case SCTP_ADD_VRF_ID: |
|
4534 { |
|
4535 #ifdef SCTP_MVRF |
|
4536 uint32_t *add_vrfid; |
|
4537 int i; |
|
4538 |
|
4539 SCTP_CHECK_AND_CAST(add_vrfid, optval, uint32_t, optsize); |
|
4540 if (*add_vrfid > SCTP_MAX_VRF_ID) { |
|
4541 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4542 error = EINVAL; |
|
4543 break; |
|
4544 } |
|
4545 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == 0) { |
|
4546 /* Can't add more once you are bound */ |
|
4547 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4548 error = EINVAL; |
|
4549 break; |
|
4550 } |
|
4551 SCTP_INP_WLOCK(inp); |
|
4552 /* Verify its not already here */ |
|
4553 for (i = 0; i < inp->num_vrfs; i++) { |
|
4554 if (*add_vrfid == inp->m_vrf_ids[i]) { |
|
4555 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
4556 error = EALREADY; |
|
4557 SCTP_INP_WUNLOCK(inp); |
|
4558 break; |
|
4559 } |
|
4560 } |
|
4561 if ((inp->num_vrfs + 1) > inp->vrf_size) { |
|
4562 /* need to grow array */ |
|
4563 uint32_t *tarray; |
|
4564 SCTP_MALLOC(tarray, uint32_t *, |
|
4565 (sizeof(uint32_t) * (inp->vrf_size + SCTP_DEFAULT_VRF_SIZE)), |
|
4566 SCTP_M_MVRF); |
|
4567 if (tarray == NULL) { |
|
4568 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4569 error = ENOMEM; |
|
4570 SCTP_INP_WUNLOCK(inp); |
|
4571 break; |
|
4572 } |
|
4573 memcpy(tarray, inp->m_vrf_ids, (sizeof(uint32_t) * inp->vrf_size)); |
|
4574 SCTP_FREE(inp->m_vrf_ids, SCTP_M_MVRF); |
|
4575 inp->m_vrf_ids = tarray; |
|
4576 inp->vrf_size += SCTP_DEFAULT_VRF_SIZE; |
|
4577 } |
|
4578 inp->m_vrf_ids[inp->num_vrfs] = *add_vrfid; |
|
4579 inp->num_vrfs++; |
|
4580 SCTP_INP_WUNLOCK(inp); |
|
4581 #else |
|
4582 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
4583 error = EOPNOTSUPP; |
|
4584 #endif |
|
4585 break; |
|
4586 } |
|
4587 case SCTP_DELAYED_SACK: |
|
4588 { |
|
4589 struct sctp_sack_info *sack; |
|
4590 |
|
4591 SCTP_CHECK_AND_CAST(sack, optval, struct sctp_sack_info, optsize); |
|
4592 SCTP_FIND_STCB(inp, stcb, sack->sack_assoc_id); |
|
4593 if (sack->sack_delay) { |
|
4594 if (sack->sack_delay > SCTP_MAX_SACK_DELAY) |
|
4595 sack->sack_delay = SCTP_MAX_SACK_DELAY; |
|
4596 if (MSEC_TO_TICKS(sack->sack_delay) < 1) { |
|
4597 sack->sack_delay = TICKS_TO_MSEC(1); |
|
4598 } |
|
4599 } |
|
4600 if (stcb) { |
|
4601 if (sack->sack_delay) { |
|
4602 stcb->asoc.delayed_ack = sack->sack_delay; |
|
4603 } |
|
4604 if (sack->sack_freq) { |
|
4605 stcb->asoc.sack_freq = sack->sack_freq; |
|
4606 } |
|
4607 SCTP_TCB_UNLOCK(stcb); |
|
4608 } else { |
|
4609 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4610 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4611 (sack->sack_assoc_id == SCTP_FUTURE_ASSOC) || |
|
4612 (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { |
|
4613 SCTP_INP_WLOCK(inp); |
|
4614 if (sack->sack_delay) { |
|
4615 inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_RECV] = MSEC_TO_TICKS(sack->sack_delay); |
|
4616 } |
|
4617 if (sack->sack_freq) { |
|
4618 inp->sctp_ep.sctp_sack_freq = sack->sack_freq; |
|
4619 } |
|
4620 SCTP_INP_WUNLOCK(inp); |
|
4621 } |
|
4622 if ((sack->sack_assoc_id == SCTP_CURRENT_ASSOC) || |
|
4623 (sack->sack_assoc_id == SCTP_ALL_ASSOC)) { |
|
4624 SCTP_INP_RLOCK(inp); |
|
4625 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4626 SCTP_TCB_LOCK(stcb); |
|
4627 if (sack->sack_delay) { |
|
4628 stcb->asoc.delayed_ack = sack->sack_delay; |
|
4629 } |
|
4630 if (sack->sack_freq) { |
|
4631 stcb->asoc.sack_freq = sack->sack_freq; |
|
4632 } |
|
4633 SCTP_TCB_UNLOCK(stcb); |
|
4634 } |
|
4635 SCTP_INP_RUNLOCK(inp); |
|
4636 } |
|
4637 } |
|
4638 break; |
|
4639 } |
|
4640 case SCTP_AUTH_CHUNK: |
|
4641 { |
|
4642 struct sctp_authchunk *sauth; |
|
4643 |
|
4644 SCTP_CHECK_AND_CAST(sauth, optval, struct sctp_authchunk, optsize); |
|
4645 |
|
4646 SCTP_INP_WLOCK(inp); |
|
4647 if (sctp_auth_add_chunk(sauth->sauth_chunk, inp->sctp_ep.local_auth_chunks)) { |
|
4648 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4649 error = EINVAL; |
|
4650 } |
|
4651 SCTP_INP_WUNLOCK(inp); |
|
4652 break; |
|
4653 } |
|
4654 case SCTP_AUTH_KEY: |
|
4655 { |
|
4656 struct sctp_authkey *sca; |
|
4657 struct sctp_keyhead *shared_keys; |
|
4658 sctp_sharedkey_t *shared_key; |
|
4659 sctp_key_t *key = NULL; |
|
4660 size_t size; |
|
4661 |
|
4662 SCTP_CHECK_AND_CAST(sca, optval, struct sctp_authkey, optsize); |
|
4663 if (sca->sca_keylength == 0) { |
|
4664 size = optsize - sizeof(struct sctp_authkey); |
|
4665 } else { |
|
4666 if (sca->sca_keylength + sizeof(struct sctp_authkey) <= optsize) { |
|
4667 size = sca->sca_keylength; |
|
4668 } else { |
|
4669 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4670 error = EINVAL; |
|
4671 break; |
|
4672 } |
|
4673 } |
|
4674 SCTP_FIND_STCB(inp, stcb, sca->sca_assoc_id); |
|
4675 |
|
4676 if (stcb) { |
|
4677 shared_keys = &stcb->asoc.shared_keys; |
|
4678 /* clear the cached keys for this key id */ |
|
4679 sctp_clear_cachedkeys(stcb, sca->sca_keynumber); |
|
4680 /* |
|
4681 * create the new shared key and |
|
4682 * insert/replace it |
|
4683 */ |
|
4684 if (size > 0) { |
|
4685 key = sctp_set_key(sca->sca_key, (uint32_t) size); |
|
4686 if (key == NULL) { |
|
4687 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4688 error = ENOMEM; |
|
4689 SCTP_TCB_UNLOCK(stcb); |
|
4690 break; |
|
4691 } |
|
4692 } |
|
4693 shared_key = sctp_alloc_sharedkey(); |
|
4694 if (shared_key == NULL) { |
|
4695 sctp_free_key(key); |
|
4696 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4697 error = ENOMEM; |
|
4698 SCTP_TCB_UNLOCK(stcb); |
|
4699 break; |
|
4700 } |
|
4701 shared_key->key = key; |
|
4702 shared_key->keyid = sca->sca_keynumber; |
|
4703 error = sctp_insert_sharedkey(shared_keys, shared_key); |
|
4704 SCTP_TCB_UNLOCK(stcb); |
|
4705 } else { |
|
4706 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4707 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4708 (sca->sca_assoc_id == SCTP_FUTURE_ASSOC) || |
|
4709 (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { |
|
4710 SCTP_INP_WLOCK(inp); |
|
4711 shared_keys = &inp->sctp_ep.shared_keys; |
|
4712 /* |
|
4713 * clear the cached keys on all assocs for |
|
4714 * this key id |
|
4715 */ |
|
4716 sctp_clear_cachedkeys_ep(inp, sca->sca_keynumber); |
|
4717 /* |
|
4718 * create the new shared key and |
|
4719 * insert/replace it |
|
4720 */ |
|
4721 if (size > 0) { |
|
4722 key = sctp_set_key(sca->sca_key, (uint32_t) size); |
|
4723 if (key == NULL) { |
|
4724 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4725 error = ENOMEM; |
|
4726 SCTP_INP_WUNLOCK(inp); |
|
4727 break; |
|
4728 } |
|
4729 } |
|
4730 shared_key = sctp_alloc_sharedkey(); |
|
4731 if (shared_key == NULL) { |
|
4732 sctp_free_key(key); |
|
4733 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4734 error = ENOMEM; |
|
4735 SCTP_INP_WUNLOCK(inp); |
|
4736 break; |
|
4737 } |
|
4738 shared_key->key = key; |
|
4739 shared_key->keyid = sca->sca_keynumber; |
|
4740 error = sctp_insert_sharedkey(shared_keys, shared_key); |
|
4741 SCTP_INP_WUNLOCK(inp); |
|
4742 } |
|
4743 if ((sca->sca_assoc_id == SCTP_CURRENT_ASSOC) || |
|
4744 (sca->sca_assoc_id == SCTP_ALL_ASSOC)) { |
|
4745 SCTP_INP_RLOCK(inp); |
|
4746 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4747 SCTP_TCB_LOCK(stcb); |
|
4748 shared_keys = &stcb->asoc.shared_keys; |
|
4749 /* clear the cached keys for this key id */ |
|
4750 sctp_clear_cachedkeys(stcb, sca->sca_keynumber); |
|
4751 /* |
|
4752 * create the new shared key and |
|
4753 * insert/replace it |
|
4754 */ |
|
4755 if (size > 0) { |
|
4756 key = sctp_set_key(sca->sca_key, (uint32_t) size); |
|
4757 if (key == NULL) { |
|
4758 SCTP_TCB_UNLOCK(stcb); |
|
4759 continue; |
|
4760 } |
|
4761 } |
|
4762 shared_key = sctp_alloc_sharedkey(); |
|
4763 if (shared_key == NULL) { |
|
4764 sctp_free_key(key); |
|
4765 SCTP_TCB_UNLOCK(stcb); |
|
4766 continue; |
|
4767 } |
|
4768 shared_key->key = key; |
|
4769 shared_key->keyid = sca->sca_keynumber; |
|
4770 error = sctp_insert_sharedkey(shared_keys, shared_key); |
|
4771 SCTP_TCB_UNLOCK(stcb); |
|
4772 } |
|
4773 SCTP_INP_RUNLOCK(inp); |
|
4774 } |
|
4775 } |
|
4776 break; |
|
4777 } |
|
4778 case SCTP_HMAC_IDENT: |
|
4779 { |
|
4780 struct sctp_hmacalgo *shmac; |
|
4781 sctp_hmaclist_t *hmaclist; |
|
4782 uint16_t hmacid; |
|
4783 uint32_t i; |
|
4784 |
|
4785 SCTP_CHECK_AND_CAST(shmac, optval, struct sctp_hmacalgo, optsize); |
|
4786 if (optsize < sizeof(struct sctp_hmacalgo) + shmac->shmac_number_of_idents * sizeof(uint16_t)) { |
|
4787 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4788 error = EINVAL; |
|
4789 break; |
|
4790 } |
|
4791 |
|
4792 hmaclist = sctp_alloc_hmaclist(shmac->shmac_number_of_idents); |
|
4793 if (hmaclist == NULL) { |
|
4794 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOMEM); |
|
4795 error = ENOMEM; |
|
4796 break; |
|
4797 } |
|
4798 for (i = 0; i < shmac->shmac_number_of_idents; i++) { |
|
4799 hmacid = shmac->shmac_idents[i]; |
|
4800 if (sctp_auth_add_hmacid(hmaclist, hmacid)) { |
|
4801 /* invalid HMACs were found */; |
|
4802 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4803 error = EINVAL; |
|
4804 sctp_free_hmaclist(hmaclist); |
|
4805 goto sctp_set_hmac_done; |
|
4806 } |
|
4807 } |
|
4808 for (i = 0; i < hmaclist->num_algo; i++) { |
|
4809 if (hmaclist->hmac[i] == SCTP_AUTH_HMAC_ID_SHA1) { |
|
4810 /* already in list */ |
|
4811 break; |
|
4812 } |
|
4813 } |
|
4814 if (i == hmaclist->num_algo) { |
|
4815 /* not found in list */ |
|
4816 sctp_free_hmaclist(hmaclist); |
|
4817 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4818 error = EINVAL; |
|
4819 break; |
|
4820 } |
|
4821 /* set it on the endpoint */ |
|
4822 SCTP_INP_WLOCK(inp); |
|
4823 if (inp->sctp_ep.local_hmacs) |
|
4824 sctp_free_hmaclist(inp->sctp_ep.local_hmacs); |
|
4825 inp->sctp_ep.local_hmacs = hmaclist; |
|
4826 SCTP_INP_WUNLOCK(inp); |
|
4827 sctp_set_hmac_done: |
|
4828 break; |
|
4829 } |
|
4830 case SCTP_AUTH_ACTIVE_KEY: |
|
4831 { |
|
4832 struct sctp_authkeyid *scact; |
|
4833 |
|
4834 SCTP_CHECK_AND_CAST(scact, optval, struct sctp_authkeyid, optsize); |
|
4835 SCTP_FIND_STCB(inp, stcb, scact->scact_assoc_id); |
|
4836 |
|
4837 /* set the active key on the right place */ |
|
4838 if (stcb) { |
|
4839 /* set the active key on the assoc */ |
|
4840 if (sctp_auth_setactivekey(stcb, |
|
4841 scact->scact_keynumber)) { |
|
4842 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, |
|
4843 SCTP_FROM_SCTP_USRREQ, |
|
4844 EINVAL); |
|
4845 error = EINVAL; |
|
4846 } |
|
4847 SCTP_TCB_UNLOCK(stcb); |
|
4848 } else { |
|
4849 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4850 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4851 (scact->scact_assoc_id == SCTP_FUTURE_ASSOC) || |
|
4852 (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4853 SCTP_INP_WLOCK(inp); |
|
4854 if (sctp_auth_setactivekey_ep(inp, scact->scact_keynumber)) { |
|
4855 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4856 error = EINVAL; |
|
4857 } |
|
4858 SCTP_INP_WUNLOCK(inp); |
|
4859 } |
|
4860 if ((scact->scact_assoc_id == SCTP_CURRENT_ASSOC) || |
|
4861 (scact->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4862 SCTP_INP_RLOCK(inp); |
|
4863 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4864 SCTP_TCB_LOCK(stcb); |
|
4865 sctp_auth_setactivekey(stcb, scact->scact_keynumber); |
|
4866 SCTP_TCB_UNLOCK(stcb); |
|
4867 } |
|
4868 SCTP_INP_RUNLOCK(inp); |
|
4869 } |
|
4870 } |
|
4871 break; |
|
4872 } |
|
4873 case SCTP_AUTH_DELETE_KEY: |
|
4874 { |
|
4875 struct sctp_authkeyid *scdel; |
|
4876 |
|
4877 SCTP_CHECK_AND_CAST(scdel, optval, struct sctp_authkeyid, optsize); |
|
4878 SCTP_FIND_STCB(inp, stcb, scdel->scact_assoc_id); |
|
4879 |
|
4880 /* delete the key from the right place */ |
|
4881 if (stcb) { |
|
4882 if (sctp_delete_sharedkey(stcb, scdel->scact_keynumber)) { |
|
4883 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4884 error = EINVAL; |
|
4885 } |
|
4886 SCTP_TCB_UNLOCK(stcb); |
|
4887 } else { |
|
4888 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4889 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4890 (scdel->scact_assoc_id == SCTP_FUTURE_ASSOC) || |
|
4891 (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4892 SCTP_INP_WLOCK(inp); |
|
4893 if (sctp_delete_sharedkey_ep(inp, scdel->scact_keynumber)) { |
|
4894 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4895 error = EINVAL; |
|
4896 } |
|
4897 SCTP_INP_WUNLOCK(inp); |
|
4898 } |
|
4899 if ((scdel->scact_assoc_id == SCTP_CURRENT_ASSOC) || |
|
4900 (scdel->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4901 SCTP_INP_RLOCK(inp); |
|
4902 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4903 SCTP_TCB_LOCK(stcb); |
|
4904 sctp_delete_sharedkey(stcb, scdel->scact_keynumber); |
|
4905 SCTP_TCB_UNLOCK(stcb); |
|
4906 } |
|
4907 SCTP_INP_RUNLOCK(inp); |
|
4908 } |
|
4909 } |
|
4910 break; |
|
4911 } |
|
4912 case SCTP_AUTH_DEACTIVATE_KEY: |
|
4913 { |
|
4914 struct sctp_authkeyid *keyid; |
|
4915 |
|
4916 SCTP_CHECK_AND_CAST(keyid, optval, struct sctp_authkeyid, optsize); |
|
4917 SCTP_FIND_STCB(inp, stcb, keyid->scact_assoc_id); |
|
4918 |
|
4919 /* deactivate the key from the right place */ |
|
4920 if (stcb) { |
|
4921 if (sctp_deact_sharedkey(stcb, keyid->scact_keynumber)) { |
|
4922 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4923 error = EINVAL; |
|
4924 } |
|
4925 SCTP_TCB_UNLOCK(stcb); |
|
4926 } else { |
|
4927 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4928 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4929 (keyid->scact_assoc_id == SCTP_FUTURE_ASSOC) || |
|
4930 (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4931 SCTP_INP_WLOCK(inp); |
|
4932 if (sctp_deact_sharedkey_ep(inp, keyid->scact_keynumber)) { |
|
4933 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4934 error = EINVAL; |
|
4935 } |
|
4936 SCTP_INP_WUNLOCK(inp); |
|
4937 } |
|
4938 if ((keyid->scact_assoc_id == SCTP_CURRENT_ASSOC) || |
|
4939 (keyid->scact_assoc_id == SCTP_ALL_ASSOC)) { |
|
4940 SCTP_INP_RLOCK(inp); |
|
4941 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4942 SCTP_TCB_LOCK(stcb); |
|
4943 sctp_deact_sharedkey(stcb, keyid->scact_keynumber); |
|
4944 SCTP_TCB_UNLOCK(stcb); |
|
4945 } |
|
4946 SCTP_INP_RUNLOCK(inp); |
|
4947 } |
|
4948 } |
|
4949 break; |
|
4950 } |
|
4951 case SCTP_ENABLE_STREAM_RESET: |
|
4952 { |
|
4953 struct sctp_assoc_value *av; |
|
4954 |
|
4955 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
4956 if (av->assoc_value & (~SCTP_ENABLE_VALUE_MASK)) { |
|
4957 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
4958 error = EINVAL; |
|
4959 break; |
|
4960 } |
|
4961 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
4962 if (stcb) { |
|
4963 stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value; |
|
4964 SCTP_TCB_UNLOCK(stcb); |
|
4965 } else { |
|
4966 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
4967 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
4968 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
4969 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4970 SCTP_INP_WLOCK(inp); |
|
4971 inp->local_strreset_support = (uint8_t)av->assoc_value; |
|
4972 SCTP_INP_WUNLOCK(inp); |
|
4973 } |
|
4974 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
4975 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
4976 SCTP_INP_RLOCK(inp); |
|
4977 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
4978 SCTP_TCB_LOCK(stcb); |
|
4979 stcb->asoc.local_strreset_support = (uint8_t)av->assoc_value; |
|
4980 SCTP_TCB_UNLOCK(stcb); |
|
4981 } |
|
4982 SCTP_INP_RUNLOCK(inp); |
|
4983 } |
|
4984 |
|
4985 } |
|
4986 break; |
|
4987 } |
|
4988 case SCTP_RESET_STREAMS: |
|
4989 { |
|
4990 struct sctp_reset_streams *strrst; |
|
4991 int i, send_out = 0; |
|
4992 int send_in = 0; |
|
4993 |
|
4994 SCTP_CHECK_AND_CAST(strrst, optval, struct sctp_reset_streams, optsize); |
|
4995 SCTP_FIND_STCB(inp, stcb, strrst->srs_assoc_id); |
|
4996 if (stcb == NULL) { |
|
4997 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
4998 error = ENOENT; |
|
4999 break; |
|
5000 } |
|
5001 if (stcb->asoc.peer_supports_strreset == 0) { |
|
5002 /* |
|
5003 * Peer does not support the chunk type. |
|
5004 */ |
|
5005 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
5006 error = EOPNOTSUPP; |
|
5007 SCTP_TCB_UNLOCK(stcb); |
|
5008 break; |
|
5009 } |
|
5010 if (stcb->asoc.stream_reset_outstanding) { |
|
5011 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
5012 error = EALREADY; |
|
5013 SCTP_TCB_UNLOCK(stcb); |
|
5014 break; |
|
5015 } |
|
5016 if (strrst->srs_flags & SCTP_STREAM_RESET_INCOMING) { |
|
5017 send_in = 1; |
|
5018 } |
|
5019 if (strrst->srs_flags & SCTP_STREAM_RESET_OUTGOING) { |
|
5020 send_out = 1; |
|
5021 } |
|
5022 if ((send_in == 0) && (send_out == 0)) { |
|
5023 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5024 error = EINVAL; |
|
5025 SCTP_TCB_UNLOCK(stcb); |
|
5026 break; |
|
5027 } |
|
5028 for (i = 0; i < strrst->srs_number_streams; i++) { |
|
5029 if ((send_in) && |
|
5030 (strrst->srs_stream_list[i] > stcb->asoc.streamincnt)) { |
|
5031 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5032 error = EINVAL; |
|
5033 break; |
|
5034 } |
|
5035 if ((send_out) && |
|
5036 (strrst->srs_stream_list[i] > stcb->asoc.streamoutcnt)) { |
|
5037 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5038 error = EINVAL; |
|
5039 break; |
|
5040 } |
|
5041 } |
|
5042 if (error) { |
|
5043 SCTP_TCB_UNLOCK(stcb); |
|
5044 break; |
|
5045 } |
|
5046 error = sctp_send_str_reset_req(stcb, strrst->srs_number_streams, |
|
5047 strrst->srs_stream_list, |
|
5048 send_out, send_in, 0, 0, 0, 0, 0); |
|
5049 |
|
5050 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); |
|
5051 SCTP_TCB_UNLOCK(stcb); |
|
5052 break; |
|
5053 } |
|
5054 case SCTP_ADD_STREAMS: |
|
5055 { |
|
5056 struct sctp_add_streams *stradd; |
|
5057 uint8_t addstream = 0; |
|
5058 uint16_t add_o_strmcnt = 0; |
|
5059 uint16_t add_i_strmcnt = 0; |
|
5060 |
|
5061 SCTP_CHECK_AND_CAST(stradd, optval, struct sctp_add_streams, optsize); |
|
5062 SCTP_FIND_STCB(inp, stcb, stradd->sas_assoc_id); |
|
5063 if (stcb == NULL) { |
|
5064 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
5065 error = ENOENT; |
|
5066 break; |
|
5067 } |
|
5068 if (stcb->asoc.peer_supports_strreset == 0) { |
|
5069 /* |
|
5070 * Peer does not support the chunk type. |
|
5071 */ |
|
5072 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
5073 error = EOPNOTSUPP; |
|
5074 SCTP_TCB_UNLOCK(stcb); |
|
5075 break; |
|
5076 } |
|
5077 if (stcb->asoc.stream_reset_outstanding) { |
|
5078 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
5079 error = EALREADY; |
|
5080 SCTP_TCB_UNLOCK(stcb); |
|
5081 break; |
|
5082 } |
|
5083 if ((stradd->sas_outstrms == 0) && |
|
5084 (stradd->sas_instrms == 0)) { |
|
5085 error = EINVAL; |
|
5086 goto skip_stuff; |
|
5087 } |
|
5088 if (stradd->sas_outstrms) { |
|
5089 addstream = 1; |
|
5090 /* We allocate here */ |
|
5091 add_o_strmcnt = stradd->sas_outstrms; |
|
5092 if ((((int)add_o_strmcnt) + ((int)stcb->asoc.streamoutcnt)) > 0x0000ffff) { |
|
5093 /* You can't have more than 64k */ |
|
5094 error = EINVAL; |
|
5095 goto skip_stuff; |
|
5096 } |
|
5097 } |
|
5098 if (stradd->sas_instrms) { |
|
5099 int cnt; |
|
5100 |
|
5101 addstream |= 2; |
|
5102 /* We allocate inside sctp_send_str_reset_req() */ |
|
5103 add_i_strmcnt = stradd->sas_instrms; |
|
5104 cnt = add_i_strmcnt; |
|
5105 cnt += stcb->asoc.streamincnt; |
|
5106 if (cnt > 0x0000ffff) { |
|
5107 /* You can't have more than 64k */ |
|
5108 error = EINVAL; |
|
5109 goto skip_stuff; |
|
5110 } |
|
5111 if (cnt > (int)stcb->asoc.max_inbound_streams) { |
|
5112 /* More than you are allowed */ |
|
5113 error = EINVAL; |
|
5114 goto skip_stuff; |
|
5115 } |
|
5116 } |
|
5117 error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 0, addstream, add_o_strmcnt, add_i_strmcnt, 0); |
|
5118 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); |
|
5119 skip_stuff: |
|
5120 SCTP_TCB_UNLOCK(stcb); |
|
5121 break; |
|
5122 } |
|
5123 case SCTP_RESET_ASSOC: |
|
5124 { |
|
5125 uint32_t *value; |
|
5126 |
|
5127 SCTP_CHECK_AND_CAST(value, optval, uint32_t, optsize); |
|
5128 SCTP_FIND_STCB(inp, stcb, (sctp_assoc_t) *value); |
|
5129 if (stcb == NULL) { |
|
5130 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
5131 error = ENOENT; |
|
5132 break; |
|
5133 } |
|
5134 if (stcb->asoc.peer_supports_strreset == 0) { |
|
5135 /* |
|
5136 * Peer does not support the chunk type. |
|
5137 */ |
|
5138 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
5139 error = EOPNOTSUPP; |
|
5140 SCTP_TCB_UNLOCK(stcb); |
|
5141 break; |
|
5142 } |
|
5143 if (stcb->asoc.stream_reset_outstanding) { |
|
5144 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
5145 error = EALREADY; |
|
5146 SCTP_TCB_UNLOCK(stcb); |
|
5147 break; |
|
5148 } |
|
5149 error = sctp_send_str_reset_req(stcb, 0, NULL, 0, 0, 1, 0, 0, 0, 0); |
|
5150 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_STRRST_REQ, SCTP_SO_LOCKED); |
|
5151 SCTP_TCB_UNLOCK(stcb); |
|
5152 break; |
|
5153 } |
|
5154 case SCTP_CONNECT_X: |
|
5155 if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { |
|
5156 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5157 error = EINVAL; |
|
5158 break; |
|
5159 } |
|
5160 error = sctp_do_connect_x(so, inp, optval, optsize, p, 0); |
|
5161 break; |
|
5162 case SCTP_CONNECT_X_DELAYED: |
|
5163 if (optsize < (sizeof(int) + sizeof(struct sockaddr_in))) { |
|
5164 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5165 error = EINVAL; |
|
5166 break; |
|
5167 } |
|
5168 error = sctp_do_connect_x(so, inp, optval, optsize, p, 1); |
|
5169 break; |
|
5170 case SCTP_CONNECT_X_COMPLETE: |
|
5171 { |
|
5172 struct sockaddr *sa; |
|
5173 struct sctp_nets *net; |
|
5174 |
|
5175 /* FIXME MT: check correct? */ |
|
5176 SCTP_CHECK_AND_CAST(sa, optval, struct sockaddr, optsize); |
|
5177 |
|
5178 /* find tcb */ |
|
5179 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { |
|
5180 SCTP_INP_RLOCK(inp); |
|
5181 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
5182 if (stcb) { |
|
5183 SCTP_TCB_LOCK(stcb); |
|
5184 net = sctp_findnet(stcb, sa); |
|
5185 } |
|
5186 SCTP_INP_RUNLOCK(inp); |
|
5187 } else { |
|
5188 /* We increment here since sctp_findassociation_ep_addr() wil |
|
5189 * do a decrement if it finds the stcb as long as the locked |
|
5190 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
5191 */ |
|
5192 SCTP_INP_INCR_REF(inp); |
|
5193 stcb = sctp_findassociation_ep_addr(&inp, sa, &net, NULL, NULL); |
|
5194 if (stcb == NULL) { |
|
5195 SCTP_INP_DECR_REF(inp); |
|
5196 } |
|
5197 } |
|
5198 |
|
5199 if (stcb == NULL) { |
|
5200 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
5201 error = ENOENT; |
|
5202 break; |
|
5203 } |
|
5204 if (stcb->asoc.delayed_connection == 1) { |
|
5205 stcb->asoc.delayed_connection = 0; |
|
5206 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
5207 sctp_timer_stop(SCTP_TIMER_TYPE_INIT, inp, stcb, |
|
5208 stcb->asoc.primary_destination, |
|
5209 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_9); |
|
5210 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
|
5211 } else { |
|
5212 /* |
|
5213 * already expired or did not use delayed |
|
5214 * connectx |
|
5215 */ |
|
5216 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
5217 error = EALREADY; |
|
5218 } |
|
5219 SCTP_TCB_UNLOCK(stcb); |
|
5220 break; |
|
5221 } |
|
5222 case SCTP_MAX_BURST: |
|
5223 { |
|
5224 #if defined(__FreeBSD__) && __FreeBSD_version < 900000 |
|
5225 uint8_t *burst; |
|
5226 |
|
5227 SCTP_CHECK_AND_CAST(burst, optval, uint8_t, optsize); |
|
5228 |
|
5229 SCTP_INP_WLOCK(inp); |
|
5230 inp->sctp_ep.max_burst = *burst; |
|
5231 SCTP_INP_WUNLOCK(inp); |
|
5232 #else |
|
5233 struct sctp_assoc_value *av; |
|
5234 |
|
5235 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
5236 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
5237 |
|
5238 if (stcb) { |
|
5239 stcb->asoc.max_burst = av->assoc_value; |
|
5240 SCTP_TCB_UNLOCK(stcb); |
|
5241 } else { |
|
5242 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5243 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5244 (av->assoc_id == SCTP_FUTURE_ASSOC) || |
|
5245 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
5246 SCTP_INP_WLOCK(inp); |
|
5247 inp->sctp_ep.max_burst = av->assoc_value; |
|
5248 SCTP_INP_WUNLOCK(inp); |
|
5249 } |
|
5250 if ((av->assoc_id == SCTP_CURRENT_ASSOC) || |
|
5251 (av->assoc_id == SCTP_ALL_ASSOC)) { |
|
5252 SCTP_INP_RLOCK(inp); |
|
5253 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
5254 SCTP_TCB_LOCK(stcb); |
|
5255 stcb->asoc.max_burst = av->assoc_value; |
|
5256 SCTP_TCB_UNLOCK(stcb); |
|
5257 } |
|
5258 SCTP_INP_RUNLOCK(inp); |
|
5259 } |
|
5260 } |
|
5261 #endif |
|
5262 break; |
|
5263 } |
|
5264 case SCTP_MAXSEG: |
|
5265 { |
|
5266 struct sctp_assoc_value *av; |
|
5267 int ovh; |
|
5268 |
|
5269 SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); |
|
5270 SCTP_FIND_STCB(inp, stcb, av->assoc_id); |
|
5271 |
|
5272 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
5273 ovh = SCTP_MED_OVERHEAD; |
|
5274 } else { |
|
5275 ovh = SCTP_MED_V4_OVERHEAD; |
|
5276 } |
|
5277 if (stcb) { |
|
5278 if (av->assoc_value) { |
|
5279 stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); |
|
5280 } else { |
|
5281 stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; |
|
5282 } |
|
5283 SCTP_TCB_UNLOCK(stcb); |
|
5284 } else { |
|
5285 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5286 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5287 (av->assoc_id == SCTP_FUTURE_ASSOC)) { |
|
5288 SCTP_INP_WLOCK(inp); |
|
5289 /* FIXME MT: I think this is not in tune with the API ID */ |
|
5290 if (av->assoc_value) { |
|
5291 inp->sctp_frag_point = (av->assoc_value + ovh); |
|
5292 } else { |
|
5293 inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; |
|
5294 } |
|
5295 SCTP_INP_WUNLOCK(inp); |
|
5296 } else { |
|
5297 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5298 error = EINVAL; |
|
5299 } |
|
5300 } |
|
5301 break; |
|
5302 } |
|
5303 case SCTP_EVENTS: |
|
5304 { |
|
5305 struct sctp_event_subscribe *events; |
|
5306 |
|
5307 SCTP_CHECK_AND_CAST(events, optval, struct sctp_event_subscribe, optsize); |
|
5308 |
|
5309 SCTP_INP_WLOCK(inp); |
|
5310 if (events->sctp_data_io_event) { |
|
5311 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); |
|
5312 } else { |
|
5313 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVDATAIOEVNT); |
|
5314 } |
|
5315 |
|
5316 if (events->sctp_association_event) { |
|
5317 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); |
|
5318 } else { |
|
5319 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVASSOCEVNT); |
|
5320 } |
|
5321 |
|
5322 if (events->sctp_address_event) { |
|
5323 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); |
|
5324 } else { |
|
5325 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPADDREVNT); |
|
5326 } |
|
5327 |
|
5328 if (events->sctp_send_failure_event) { |
|
5329 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); |
|
5330 } else { |
|
5331 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); |
|
5332 } |
|
5333 |
|
5334 if (events->sctp_peer_error_event) { |
|
5335 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVPEERERR); |
|
5336 } else { |
|
5337 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVPEERERR); |
|
5338 } |
|
5339 |
|
5340 if (events->sctp_shutdown_event) { |
|
5341 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); |
|
5342 } else { |
|
5343 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); |
|
5344 } |
|
5345 |
|
5346 if (events->sctp_partial_delivery_event) { |
|
5347 sctp_feature_on(inp, SCTP_PCB_FLAGS_PDAPIEVNT); |
|
5348 } else { |
|
5349 sctp_feature_off(inp, SCTP_PCB_FLAGS_PDAPIEVNT); |
|
5350 } |
|
5351 |
|
5352 if (events->sctp_adaptation_layer_event) { |
|
5353 sctp_feature_on(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); |
|
5354 } else { |
|
5355 sctp_feature_off(inp, SCTP_PCB_FLAGS_ADAPTATIONEVNT); |
|
5356 } |
|
5357 |
|
5358 if (events->sctp_authentication_event) { |
|
5359 sctp_feature_on(inp, SCTP_PCB_FLAGS_AUTHEVNT); |
|
5360 } else { |
|
5361 sctp_feature_off(inp, SCTP_PCB_FLAGS_AUTHEVNT); |
|
5362 } |
|
5363 |
|
5364 if (events->sctp_sender_dry_event) { |
|
5365 sctp_feature_on(inp, SCTP_PCB_FLAGS_DRYEVNT); |
|
5366 } else { |
|
5367 sctp_feature_off(inp, SCTP_PCB_FLAGS_DRYEVNT); |
|
5368 } |
|
5369 |
|
5370 if (events->sctp_stream_reset_event) { |
|
5371 sctp_feature_on(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); |
|
5372 } else { |
|
5373 sctp_feature_off(inp, SCTP_PCB_FLAGS_STREAM_RESETEVNT); |
|
5374 } |
|
5375 SCTP_INP_WUNLOCK(inp); |
|
5376 |
|
5377 SCTP_INP_RLOCK(inp); |
|
5378 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
5379 SCTP_TCB_LOCK(stcb); |
|
5380 if (events->sctp_association_event) { |
|
5381 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); |
|
5382 } else { |
|
5383 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVASSOCEVNT); |
|
5384 } |
|
5385 if (events->sctp_address_event) { |
|
5386 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); |
|
5387 } else { |
|
5388 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPADDREVNT); |
|
5389 } |
|
5390 if (events->sctp_send_failure_event) { |
|
5391 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); |
|
5392 } else { |
|
5393 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSENDFAILEVNT); |
|
5394 } |
|
5395 if (events->sctp_peer_error_event) { |
|
5396 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); |
|
5397 } else { |
|
5398 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVPEERERR); |
|
5399 } |
|
5400 if (events->sctp_shutdown_event) { |
|
5401 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); |
|
5402 } else { |
|
5403 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT); |
|
5404 } |
|
5405 if (events->sctp_partial_delivery_event) { |
|
5406 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); |
|
5407 } else { |
|
5408 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_PDAPIEVNT); |
|
5409 } |
|
5410 if (events->sctp_adaptation_layer_event) { |
|
5411 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); |
|
5412 } else { |
|
5413 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_ADAPTATIONEVNT); |
|
5414 } |
|
5415 if (events->sctp_authentication_event) { |
|
5416 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); |
|
5417 } else { |
|
5418 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_AUTHEVNT); |
|
5419 } |
|
5420 if (events->sctp_sender_dry_event) { |
|
5421 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); |
|
5422 } else { |
|
5423 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DRYEVNT); |
|
5424 } |
|
5425 if (events->sctp_stream_reset_event) { |
|
5426 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); |
|
5427 } else { |
|
5428 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_STREAM_RESETEVNT); |
|
5429 } |
|
5430 SCTP_TCB_UNLOCK(stcb); |
|
5431 } |
|
5432 /* Send up the sender dry event only for 1-to-1 style sockets. */ |
|
5433 if (events->sctp_sender_dry_event) { |
|
5434 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5435 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
5436 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
5437 if (stcb) { |
|
5438 SCTP_TCB_LOCK(stcb); |
|
5439 if (TAILQ_EMPTY(&stcb->asoc.send_queue) && |
|
5440 TAILQ_EMPTY(&stcb->asoc.sent_queue) && |
|
5441 (stcb->asoc.stream_queue_cnt == 0)) { |
|
5442 sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); |
|
5443 } |
|
5444 SCTP_TCB_UNLOCK(stcb); |
|
5445 } |
|
5446 } |
|
5447 } |
|
5448 SCTP_INP_RUNLOCK(inp); |
|
5449 break; |
|
5450 } |
|
5451 case SCTP_ADAPTATION_LAYER: |
|
5452 { |
|
5453 struct sctp_setadaptation *adap_bits; |
|
5454 |
|
5455 SCTP_CHECK_AND_CAST(adap_bits, optval, struct sctp_setadaptation, optsize); |
|
5456 SCTP_INP_WLOCK(inp); |
|
5457 inp->sctp_ep.adaptation_layer_indicator = adap_bits->ssb_adaptation_ind; |
|
5458 inp->sctp_ep.adaptation_layer_indicator_provided = 1; |
|
5459 SCTP_INP_WUNLOCK(inp); |
|
5460 break; |
|
5461 } |
|
5462 #ifdef SCTP_DEBUG |
|
5463 case SCTP_SET_INITIAL_DBG_SEQ: |
|
5464 { |
|
5465 uint32_t *vvv; |
|
5466 |
|
5467 SCTP_CHECK_AND_CAST(vvv, optval, uint32_t, optsize); |
|
5468 SCTP_INP_WLOCK(inp); |
|
5469 inp->sctp_ep.initial_sequence_debug = *vvv; |
|
5470 SCTP_INP_WUNLOCK(inp); |
|
5471 break; |
|
5472 } |
|
5473 #endif |
|
5474 case SCTP_DEFAULT_SEND_PARAM: |
|
5475 { |
|
5476 struct sctp_sndrcvinfo *s_info; |
|
5477 |
|
5478 SCTP_CHECK_AND_CAST(s_info, optval, struct sctp_sndrcvinfo, optsize); |
|
5479 SCTP_FIND_STCB(inp, stcb, s_info->sinfo_assoc_id); |
|
5480 |
|
5481 if (stcb) { |
|
5482 if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { |
|
5483 memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); |
|
5484 } else { |
|
5485 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5486 error = EINVAL; |
|
5487 } |
|
5488 SCTP_TCB_UNLOCK(stcb); |
|
5489 } else { |
|
5490 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5491 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5492 (s_info->sinfo_assoc_id == SCTP_FUTURE_ASSOC) || |
|
5493 (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { |
|
5494 SCTP_INP_WLOCK(inp); |
|
5495 memcpy(&inp->def_send, s_info, min(optsize, sizeof(inp->def_send))); |
|
5496 SCTP_INP_WUNLOCK(inp); |
|
5497 } |
|
5498 if ((s_info->sinfo_assoc_id == SCTP_CURRENT_ASSOC) || |
|
5499 (s_info->sinfo_assoc_id == SCTP_ALL_ASSOC)) { |
|
5500 SCTP_INP_RLOCK(inp); |
|
5501 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
5502 SCTP_TCB_LOCK(stcb); |
|
5503 if (s_info->sinfo_stream < stcb->asoc.streamoutcnt) { |
|
5504 memcpy(&stcb->asoc.def_send, s_info, min(optsize, sizeof(stcb->asoc.def_send))); |
|
5505 } |
|
5506 SCTP_TCB_UNLOCK(stcb); |
|
5507 } |
|
5508 SCTP_INP_RUNLOCK(inp); |
|
5509 } |
|
5510 } |
|
5511 break; |
|
5512 } |
|
5513 case SCTP_PEER_ADDR_PARAMS: |
|
5514 { |
|
5515 struct sctp_paddrparams *paddrp; |
|
5516 struct sctp_nets *net; |
|
5517 |
|
5518 SCTP_CHECK_AND_CAST(paddrp, optval, struct sctp_paddrparams, optsize); |
|
5519 SCTP_FIND_STCB(inp, stcb, paddrp->spp_assoc_id); |
|
5520 net = NULL; |
|
5521 if (stcb) { |
|
5522 net = sctp_findnet(stcb, (struct sockaddr *)&paddrp->spp_address); |
|
5523 } else { |
|
5524 /* We increment here since sctp_findassociation_ep_addr() wil |
|
5525 * do a decrement if it finds the stcb as long as the locked |
|
5526 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
5527 */ |
|
5528 SCTP_INP_INCR_REF(inp); |
|
5529 stcb = sctp_findassociation_ep_addr(&inp, |
|
5530 (struct sockaddr *)&paddrp->spp_address, |
|
5531 &net, NULL, NULL); |
|
5532 if (stcb == NULL) { |
|
5533 SCTP_INP_DECR_REF(inp); |
|
5534 } |
|
5535 } |
|
5536 if (stcb && (net == NULL)) { |
|
5537 struct sockaddr *sa; |
|
5538 |
|
5539 sa = (struct sockaddr *)&paddrp->spp_address; |
|
5540 #ifdef INET |
|
5541 if (sa->sa_family == AF_INET) { |
|
5542 |
|
5543 struct sockaddr_in *sin; |
|
5544 sin = (struct sockaddr_in *)sa; |
|
5545 if (sin->sin_addr.s_addr) { |
|
5546 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5547 SCTP_TCB_UNLOCK(stcb); |
|
5548 error = EINVAL; |
|
5549 break; |
|
5550 } |
|
5551 } else |
|
5552 #endif |
|
5553 #ifdef INET6 |
|
5554 if (sa->sa_family == AF_INET6) { |
|
5555 struct sockaddr_in6 *sin6; |
|
5556 |
|
5557 sin6 = (struct sockaddr_in6 *)sa; |
|
5558 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
5559 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5560 SCTP_TCB_UNLOCK(stcb); |
|
5561 error = EINVAL; |
|
5562 break; |
|
5563 } |
|
5564 } else |
|
5565 #endif |
|
5566 #if defined(__Userspace__) |
|
5567 if (sa->sa_family == AF_CONN) { |
|
5568 struct sockaddr_conn *sconn; |
|
5569 |
|
5570 sconn = (struct sockaddr_conn *)sa; |
|
5571 if (sconn->sconn_addr != NULL) { |
|
5572 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5573 SCTP_TCB_UNLOCK(stcb); |
|
5574 error = EINVAL; |
|
5575 break; |
|
5576 } |
|
5577 } else |
|
5578 #endif |
|
5579 { |
|
5580 error = EAFNOSUPPORT; |
|
5581 SCTP_TCB_UNLOCK(stcb); |
|
5582 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
5583 break; |
|
5584 } |
|
5585 } |
|
5586 /* sanity checks */ |
|
5587 if ((paddrp->spp_flags & SPP_HB_ENABLE) && (paddrp->spp_flags & SPP_HB_DISABLE)) { |
|
5588 if (stcb) |
|
5589 SCTP_TCB_UNLOCK(stcb); |
|
5590 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5591 return (EINVAL); |
|
5592 } |
|
5593 |
|
5594 if ((paddrp->spp_flags & SPP_PMTUD_ENABLE) && (paddrp->spp_flags & SPP_PMTUD_DISABLE)) { |
|
5595 if (stcb) |
|
5596 SCTP_TCB_UNLOCK(stcb); |
|
5597 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5598 return (EINVAL); |
|
5599 } |
|
5600 |
|
5601 if (stcb) { |
|
5602 /************************TCB SPECIFIC SET ******************/ |
|
5603 /* |
|
5604 * do we change the timer for HB, we run |
|
5605 * only one? |
|
5606 */ |
|
5607 int ovh = 0; |
|
5608 |
|
5609 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
5610 ovh = SCTP_MED_OVERHEAD; |
|
5611 } else { |
|
5612 ovh = SCTP_MED_V4_OVERHEAD; |
|
5613 } |
|
5614 |
|
5615 /* network sets ? */ |
|
5616 if (net) { |
|
5617 /************************NET SPECIFIC SET ******************/ |
|
5618 if (paddrp->spp_flags & SPP_HB_DISABLE) { |
|
5619 if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED) && |
|
5620 !(net->dest_state & SCTP_ADDR_NOHB)) { |
|
5621 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, |
|
5622 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5623 } |
|
5624 net->dest_state |= SCTP_ADDR_NOHB; |
|
5625 } |
|
5626 if (paddrp->spp_flags & SPP_HB_ENABLE) { |
|
5627 if (paddrp->spp_hbinterval) { |
|
5628 net->heart_beat_delay = paddrp->spp_hbinterval; |
|
5629 } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { |
|
5630 net->heart_beat_delay = 0; |
|
5631 } |
|
5632 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, |
|
5633 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5634 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); |
|
5635 net->dest_state &= ~SCTP_ADDR_NOHB; |
|
5636 } |
|
5637 if (paddrp->spp_flags & SPP_HB_DEMAND) { |
|
5638 /* on demand HB */ |
|
5639 sctp_send_hb(stcb, net, SCTP_SO_LOCKED); |
|
5640 sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_SOCKOPT, SCTP_SO_LOCKED); |
|
5641 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); |
|
5642 } |
|
5643 if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { |
|
5644 if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { |
|
5645 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, |
|
5646 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5647 } |
|
5648 net->dest_state |= SCTP_ADDR_NO_PMTUD; |
|
5649 net->mtu = paddrp->spp_pathmtu + ovh; |
|
5650 if (net->mtu < stcb->asoc.smallest_mtu) { |
|
5651 sctp_pathmtu_adjustment(stcb, net->mtu); |
|
5652 } |
|
5653 } |
|
5654 if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { |
|
5655 if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { |
|
5656 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); |
|
5657 } |
|
5658 net->dest_state &= ~SCTP_ADDR_NO_PMTUD; |
|
5659 } |
|
5660 if (paddrp->spp_pathmaxrxt) { |
|
5661 if (net->dest_state & SCTP_ADDR_PF) { |
|
5662 if (net->error_count > paddrp->spp_pathmaxrxt) { |
|
5663 net->dest_state &= ~SCTP_ADDR_PF; |
|
5664 } |
|
5665 } else { |
|
5666 if ((net->error_count <= paddrp->spp_pathmaxrxt) && |
|
5667 (net->error_count > net->pf_threshold)) { |
|
5668 net->dest_state |= SCTP_ADDR_PF; |
|
5669 sctp_send_hb(stcb, net, SCTP_SO_LOCKED); |
|
5670 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); |
|
5671 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); |
|
5672 } |
|
5673 } |
|
5674 if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
5675 if (net->error_count > paddrp->spp_pathmaxrxt) { |
|
5676 net->dest_state &= ~SCTP_ADDR_REACHABLE; |
|
5677 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); |
|
5678 } |
|
5679 } else { |
|
5680 if (net->error_count <= paddrp->spp_pathmaxrxt) { |
|
5681 net->dest_state |= SCTP_ADDR_REACHABLE; |
|
5682 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); |
|
5683 } |
|
5684 } |
|
5685 net->failure_threshold = paddrp->spp_pathmaxrxt; |
|
5686 } |
|
5687 if (paddrp->spp_flags & SPP_DSCP) { |
|
5688 net->dscp = paddrp->spp_dscp & 0xfc; |
|
5689 net->dscp |= 0x01; |
|
5690 } |
|
5691 #ifdef INET6 |
|
5692 if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { |
|
5693 if (net->ro._l_addr.sa.sa_family == AF_INET6) { |
|
5694 net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; |
|
5695 net->flowlabel |= 0x80000000; |
|
5696 } |
|
5697 } |
|
5698 #endif |
|
5699 } else { |
|
5700 /************************ASSOC ONLY -- NO NET SPECIFIC SET ******************/ |
|
5701 if (paddrp->spp_pathmaxrxt) { |
|
5702 stcb->asoc.def_net_failure = paddrp->spp_pathmaxrxt; |
|
5703 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5704 if (net->dest_state & SCTP_ADDR_PF) { |
|
5705 if (net->error_count > paddrp->spp_pathmaxrxt) { |
|
5706 net->dest_state &= ~SCTP_ADDR_PF; |
|
5707 } |
|
5708 } else { |
|
5709 if ((net->error_count <= paddrp->spp_pathmaxrxt) && |
|
5710 (net->error_count > net->pf_threshold)) { |
|
5711 net->dest_state |= SCTP_ADDR_PF; |
|
5712 sctp_send_hb(stcb, net, SCTP_SO_LOCKED); |
|
5713 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); |
|
5714 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); |
|
5715 } |
|
5716 } |
|
5717 if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
5718 if (net->error_count > paddrp->spp_pathmaxrxt) { |
|
5719 net->dest_state &= ~SCTP_ADDR_REACHABLE; |
|
5720 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); |
|
5721 } |
|
5722 } else { |
|
5723 if (net->error_count <= paddrp->spp_pathmaxrxt) { |
|
5724 net->dest_state |= SCTP_ADDR_REACHABLE; |
|
5725 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); |
|
5726 } |
|
5727 } |
|
5728 net->failure_threshold = paddrp->spp_pathmaxrxt; |
|
5729 } |
|
5730 } |
|
5731 |
|
5732 if (paddrp->spp_flags & SPP_HB_ENABLE) { |
|
5733 if (paddrp->spp_hbinterval) { |
|
5734 stcb->asoc.heart_beat_delay = paddrp->spp_hbinterval; |
|
5735 } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { |
|
5736 stcb->asoc.heart_beat_delay = 0; |
|
5737 } |
|
5738 /* Turn back on the timer */ |
|
5739 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5740 if (paddrp->spp_hbinterval) { |
|
5741 net->heart_beat_delay = paddrp->spp_hbinterval; |
|
5742 } else if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { |
|
5743 net->heart_beat_delay = 0; |
|
5744 } |
|
5745 if (net->dest_state & SCTP_ADDR_NOHB) { |
|
5746 net->dest_state &= ~SCTP_ADDR_NOHB; |
|
5747 } |
|
5748 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, |
|
5749 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5750 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net); |
|
5751 } |
|
5752 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); |
|
5753 } |
|
5754 if (paddrp->spp_flags & SPP_HB_DISABLE) { |
|
5755 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5756 if (!(net->dest_state & SCTP_ADDR_NOHB)) { |
|
5757 net->dest_state |= SCTP_ADDR_NOHB; |
|
5758 if (!(net->dest_state & SCTP_ADDR_UNCONFIRMED)) { |
|
5759 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, inp, stcb, net, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5760 } |
|
5761 } |
|
5762 } |
|
5763 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); |
|
5764 } |
|
5765 if ((paddrp->spp_flags & SPP_PMTUD_DISABLE) && (paddrp->spp_pathmtu >= SCTP_SMALLEST_PMTU)) { |
|
5766 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5767 if (SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { |
|
5768 sctp_timer_stop(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net, |
|
5769 SCTP_FROM_SCTP_USRREQ+SCTP_LOC_10); |
|
5770 } |
|
5771 net->dest_state |= SCTP_ADDR_NO_PMTUD; |
|
5772 net->mtu = paddrp->spp_pathmtu + ovh; |
|
5773 if (net->mtu < stcb->asoc.smallest_mtu) { |
|
5774 sctp_pathmtu_adjustment(stcb, net->mtu); |
|
5775 } |
|
5776 } |
|
5777 sctp_stcb_feature_on(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); |
|
5778 } |
|
5779 if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { |
|
5780 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5781 if (!SCTP_OS_TIMER_PENDING(&net->pmtu_timer.timer)) { |
|
5782 sctp_timer_start(SCTP_TIMER_TYPE_PATHMTURAISE, inp, stcb, net); |
|
5783 } |
|
5784 net->dest_state &= ~SCTP_ADDR_NO_PMTUD; |
|
5785 } |
|
5786 sctp_stcb_feature_off(inp, stcb, SCTP_PCB_FLAGS_DO_NOT_PMTUD); |
|
5787 } |
|
5788 if (paddrp->spp_flags & SPP_DSCP) { |
|
5789 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5790 net->dscp = paddrp->spp_dscp & 0xfc; |
|
5791 net->dscp |= 0x01; |
|
5792 } |
|
5793 stcb->asoc.default_dscp = paddrp->spp_dscp & 0xfc; |
|
5794 stcb->asoc.default_dscp |= 0x01; |
|
5795 } |
|
5796 #ifdef INET6 |
|
5797 if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { |
|
5798 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
5799 if (net->ro._l_addr.sa.sa_family == AF_INET6) { |
|
5800 net->flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; |
|
5801 net->flowlabel |= 0x80000000; |
|
5802 } |
|
5803 } |
|
5804 stcb->asoc.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; |
|
5805 stcb->asoc.default_flowlabel |= 0x80000000; |
|
5806 } |
|
5807 #endif |
|
5808 } |
|
5809 SCTP_TCB_UNLOCK(stcb); |
|
5810 } else { |
|
5811 /************************NO TCB, SET TO default stuff ******************/ |
|
5812 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5813 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5814 (paddrp->spp_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
5815 SCTP_INP_WLOCK(inp); |
|
5816 /* |
|
5817 * For the TOS/FLOWLABEL stuff you set it |
|
5818 * with the options on the socket |
|
5819 */ |
|
5820 if (paddrp->spp_pathmaxrxt) { |
|
5821 inp->sctp_ep.def_net_failure = paddrp->spp_pathmaxrxt; |
|
5822 } |
|
5823 |
|
5824 if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) |
|
5825 inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; |
|
5826 else if (paddrp->spp_hbinterval) { |
|
5827 if (paddrp->spp_hbinterval > SCTP_MAX_HB_INTERVAL) |
|
5828 paddrp->spp_hbinterval= SCTP_MAX_HB_INTERVAL; |
|
5829 inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); |
|
5830 } |
|
5831 |
|
5832 if (paddrp->spp_flags & SPP_HB_ENABLE) { |
|
5833 if (paddrp->spp_flags & SPP_HB_TIME_IS_ZERO) { |
|
5834 inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = 0; |
|
5835 } else if (paddrp->spp_hbinterval) { |
|
5836 inp->sctp_ep.sctp_timeoutticks[SCTP_TIMER_HEARTBEAT] = MSEC_TO_TICKS(paddrp->spp_hbinterval); |
|
5837 } |
|
5838 sctp_feature_off(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); |
|
5839 } else if (paddrp->spp_flags & SPP_HB_DISABLE) { |
|
5840 sctp_feature_on(inp, SCTP_PCB_FLAGS_DONOT_HEARTBEAT); |
|
5841 } |
|
5842 if (paddrp->spp_flags & SPP_PMTUD_ENABLE) { |
|
5843 sctp_feature_off(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); |
|
5844 } else if (paddrp->spp_flags & SPP_PMTUD_DISABLE) { |
|
5845 sctp_feature_on(inp, SCTP_PCB_FLAGS_DO_NOT_PMTUD); |
|
5846 } |
|
5847 if (paddrp->spp_flags & SPP_DSCP) { |
|
5848 inp->sctp_ep.default_dscp = paddrp->spp_dscp & 0xfc; |
|
5849 inp->sctp_ep.default_dscp |= 0x01; |
|
5850 } |
|
5851 #ifdef INET6 |
|
5852 if (paddrp->spp_flags & SPP_IPV6_FLOWLABEL) { |
|
5853 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
5854 inp->sctp_ep.default_flowlabel = paddrp->spp_ipv6_flowlabel & 0x000fffff; |
|
5855 inp->sctp_ep.default_flowlabel |= 0x80000000; |
|
5856 } |
|
5857 } |
|
5858 #endif |
|
5859 SCTP_INP_WUNLOCK(inp); |
|
5860 } else { |
|
5861 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5862 error = EINVAL; |
|
5863 } |
|
5864 } |
|
5865 break; |
|
5866 } |
|
5867 case SCTP_RTOINFO: |
|
5868 { |
|
5869 struct sctp_rtoinfo *srto; |
|
5870 uint32_t new_init, new_min, new_max; |
|
5871 |
|
5872 SCTP_CHECK_AND_CAST(srto, optval, struct sctp_rtoinfo, optsize); |
|
5873 SCTP_FIND_STCB(inp, stcb, srto->srto_assoc_id); |
|
5874 |
|
5875 if (stcb) { |
|
5876 if (srto->srto_initial) |
|
5877 new_init = srto->srto_initial; |
|
5878 else |
|
5879 new_init = stcb->asoc.initial_rto; |
|
5880 if (srto->srto_max) |
|
5881 new_max = srto->srto_max; |
|
5882 else |
|
5883 new_max = stcb->asoc.maxrto; |
|
5884 if (srto->srto_min) |
|
5885 new_min = srto->srto_min; |
|
5886 else |
|
5887 new_min = stcb->asoc.minrto; |
|
5888 if ((new_min <= new_init) && (new_init <= new_max)) { |
|
5889 stcb->asoc.initial_rto = new_init; |
|
5890 stcb->asoc.maxrto = new_max; |
|
5891 stcb->asoc.minrto = new_min; |
|
5892 } else { |
|
5893 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5894 error = EINVAL; |
|
5895 } |
|
5896 SCTP_TCB_UNLOCK(stcb); |
|
5897 } else { |
|
5898 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5899 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5900 (srto->srto_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
5901 SCTP_INP_WLOCK(inp); |
|
5902 if (srto->srto_initial) |
|
5903 new_init = srto->srto_initial; |
|
5904 else |
|
5905 new_init = inp->sctp_ep.initial_rto; |
|
5906 if (srto->srto_max) |
|
5907 new_max = srto->srto_max; |
|
5908 else |
|
5909 new_max = inp->sctp_ep.sctp_maxrto; |
|
5910 if (srto->srto_min) |
|
5911 new_min = srto->srto_min; |
|
5912 else |
|
5913 new_min = inp->sctp_ep.sctp_minrto; |
|
5914 if ((new_min <= new_init) && (new_init <= new_max)) { |
|
5915 inp->sctp_ep.initial_rto = new_init; |
|
5916 inp->sctp_ep.sctp_maxrto = new_max; |
|
5917 inp->sctp_ep.sctp_minrto = new_min; |
|
5918 } else { |
|
5919 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5920 error = EINVAL; |
|
5921 } |
|
5922 SCTP_INP_WUNLOCK(inp); |
|
5923 } else { |
|
5924 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5925 error = EINVAL; |
|
5926 } |
|
5927 } |
|
5928 break; |
|
5929 } |
|
5930 case SCTP_ASSOCINFO: |
|
5931 { |
|
5932 struct sctp_assocparams *sasoc; |
|
5933 |
|
5934 SCTP_CHECK_AND_CAST(sasoc, optval, struct sctp_assocparams, optsize); |
|
5935 SCTP_FIND_STCB(inp, stcb, sasoc->sasoc_assoc_id); |
|
5936 if (sasoc->sasoc_cookie_life) { |
|
5937 /* boundary check the cookie life */ |
|
5938 if (sasoc->sasoc_cookie_life < 1000) |
|
5939 sasoc->sasoc_cookie_life = 1000; |
|
5940 if (sasoc->sasoc_cookie_life > SCTP_MAX_COOKIE_LIFE) { |
|
5941 sasoc->sasoc_cookie_life = SCTP_MAX_COOKIE_LIFE; |
|
5942 } |
|
5943 } |
|
5944 if (stcb) { |
|
5945 if (sasoc->sasoc_asocmaxrxt) |
|
5946 stcb->asoc.max_send_times = sasoc->sasoc_asocmaxrxt; |
|
5947 if (sasoc->sasoc_cookie_life) { |
|
5948 stcb->asoc.cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); |
|
5949 } |
|
5950 SCTP_TCB_UNLOCK(stcb); |
|
5951 } else { |
|
5952 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
5953 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
5954 (sasoc->sasoc_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
5955 SCTP_INP_WLOCK(inp); |
|
5956 if (sasoc->sasoc_asocmaxrxt) |
|
5957 inp->sctp_ep.max_send_times = sasoc->sasoc_asocmaxrxt; |
|
5958 if (sasoc->sasoc_cookie_life) { |
|
5959 inp->sctp_ep.def_cookie_life = MSEC_TO_TICKS(sasoc->sasoc_cookie_life); |
|
5960 } |
|
5961 SCTP_INP_WUNLOCK(inp); |
|
5962 } else { |
|
5963 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
5964 error = EINVAL; |
|
5965 } |
|
5966 } |
|
5967 break; |
|
5968 } |
|
5969 case SCTP_INITMSG: |
|
5970 { |
|
5971 struct sctp_initmsg *sinit; |
|
5972 |
|
5973 SCTP_CHECK_AND_CAST(sinit, optval, struct sctp_initmsg, optsize); |
|
5974 SCTP_INP_WLOCK(inp); |
|
5975 if (sinit->sinit_num_ostreams) |
|
5976 inp->sctp_ep.pre_open_stream_count = sinit->sinit_num_ostreams; |
|
5977 |
|
5978 if (sinit->sinit_max_instreams) |
|
5979 inp->sctp_ep.max_open_streams_intome = sinit->sinit_max_instreams; |
|
5980 |
|
5981 if (sinit->sinit_max_attempts) |
|
5982 inp->sctp_ep.max_init_times = sinit->sinit_max_attempts; |
|
5983 |
|
5984 if (sinit->sinit_max_init_timeo) |
|
5985 inp->sctp_ep.initial_init_rto_max = sinit->sinit_max_init_timeo; |
|
5986 SCTP_INP_WUNLOCK(inp); |
|
5987 break; |
|
5988 } |
|
5989 case SCTP_PRIMARY_ADDR: |
|
5990 { |
|
5991 struct sctp_setprim *spa; |
|
5992 struct sctp_nets *net; |
|
5993 |
|
5994 SCTP_CHECK_AND_CAST(spa, optval, struct sctp_setprim, optsize); |
|
5995 SCTP_FIND_STCB(inp, stcb, spa->ssp_assoc_id); |
|
5996 |
|
5997 net = NULL; |
|
5998 if (stcb) { |
|
5999 net = sctp_findnet(stcb, (struct sockaddr *)&spa->ssp_addr); |
|
6000 } else { |
|
6001 /* We increment here since sctp_findassociation_ep_addr() wil |
|
6002 * do a decrement if it finds the stcb as long as the locked |
|
6003 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
6004 */ |
|
6005 SCTP_INP_INCR_REF(inp); |
|
6006 stcb = sctp_findassociation_ep_addr(&inp, |
|
6007 (struct sockaddr *)&spa->ssp_addr, |
|
6008 &net, NULL, NULL); |
|
6009 if (stcb == NULL) { |
|
6010 SCTP_INP_DECR_REF(inp); |
|
6011 } |
|
6012 } |
|
6013 |
|
6014 if ((stcb) && (net)) { |
|
6015 if ((net != stcb->asoc.primary_destination) && |
|
6016 (!(net->dest_state & SCTP_ADDR_UNCONFIRMED))) { |
|
6017 /* Ok we need to set it */ |
|
6018 if (sctp_set_primary_addr(stcb, (struct sockaddr *)NULL, net) == 0) { |
|
6019 if ((stcb->asoc.alternate) && |
|
6020 (!(net->dest_state & SCTP_ADDR_PF)) && |
|
6021 (net->dest_state & SCTP_ADDR_REACHABLE)) { |
|
6022 sctp_free_remote_addr(stcb->asoc.alternate); |
|
6023 stcb->asoc.alternate = NULL; |
|
6024 } |
|
6025 } |
|
6026 } |
|
6027 } else { |
|
6028 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6029 error = EINVAL; |
|
6030 } |
|
6031 if (stcb) { |
|
6032 SCTP_TCB_UNLOCK(stcb); |
|
6033 } |
|
6034 break; |
|
6035 } |
|
6036 case SCTP_SET_DYNAMIC_PRIMARY: |
|
6037 { |
|
6038 union sctp_sockstore *ss; |
|
6039 #ifdef SCTP_MVRF |
|
6040 int i, fnd = 0; |
|
6041 #endif |
|
6042 #if !defined(__Windows__) && !defined(__Userspace__) |
|
6043 #if defined(__APPLE__) |
|
6044 struct proc *proc; |
|
6045 #endif |
|
6046 #ifdef __FreeBSD__ |
|
6047 #if __FreeBSD_version > 602000 |
|
6048 error = priv_check(curthread, |
|
6049 PRIV_NETINET_RESERVEDPORT); |
|
6050 #elif __FreeBSD_version >= 500000 |
|
6051 error = suser((struct thread *)p); |
|
6052 #else |
|
6053 error = suser(p); |
|
6054 #endif |
|
6055 #elif defined(__APPLE__) |
|
6056 proc = (struct proc *)p; |
|
6057 if (p) { |
|
6058 error = suser(proc->p_ucred, &proc->p_acflag); |
|
6059 } else { |
|
6060 break; |
|
6061 } |
|
6062 #else |
|
6063 error = suser(p, 0); |
|
6064 #endif |
|
6065 #endif |
|
6066 if (error) |
|
6067 break; |
|
6068 |
|
6069 SCTP_CHECK_AND_CAST(ss, optval, union sctp_sockstore, optsize); |
|
6070 /* SUPER USER CHECK? */ |
|
6071 #ifdef SCTP_MVRF |
|
6072 for (i = 0; i < inp->num_vrfs; i++) { |
|
6073 if (vrf_id == inp->m_vrf_ids[i]) { |
|
6074 fnd = 1; |
|
6075 break; |
|
6076 } |
|
6077 } |
|
6078 if (!fnd) { |
|
6079 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6080 error = EINVAL; |
|
6081 break; |
|
6082 } |
|
6083 #endif |
|
6084 error = sctp_dynamic_set_primary(&ss->sa, vrf_id); |
|
6085 break; |
|
6086 } |
|
6087 case SCTP_SET_PEER_PRIMARY_ADDR: |
|
6088 { |
|
6089 struct sctp_setpeerprim *sspp; |
|
6090 |
|
6091 SCTP_CHECK_AND_CAST(sspp, optval, struct sctp_setpeerprim, optsize); |
|
6092 SCTP_FIND_STCB(inp, stcb, sspp->sspp_assoc_id); |
|
6093 if (stcb != NULL) { |
|
6094 struct sctp_ifa *ifa; |
|
6095 ifa = sctp_find_ifa_by_addr((struct sockaddr *)&sspp->sspp_addr, |
|
6096 stcb->asoc.vrf_id, SCTP_ADDR_NOT_LOCKED); |
|
6097 if (ifa == NULL) { |
|
6098 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6099 error = EINVAL; |
|
6100 goto out_of_it; |
|
6101 } |
|
6102 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { |
|
6103 /* Must validate the ifa found is in our ep */ |
|
6104 struct sctp_laddr *laddr; |
|
6105 int found = 0; |
|
6106 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
|
6107 if (laddr->ifa == NULL) { |
|
6108 SCTPDBG(SCTP_DEBUG_OUTPUT1, "%s: NULL ifa\n", |
|
6109 __FUNCTION__); |
|
6110 continue; |
|
6111 } |
|
6112 if (laddr->ifa == ifa) { |
|
6113 found = 1; |
|
6114 break; |
|
6115 } |
|
6116 } |
|
6117 if (!found) { |
|
6118 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6119 error = EINVAL; |
|
6120 goto out_of_it; |
|
6121 } |
|
6122 } |
|
6123 if (sctp_set_primary_ip_address_sa(stcb, |
|
6124 (struct sockaddr *)&sspp->sspp_addr) != 0) { |
|
6125 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6126 error = EINVAL; |
|
6127 } |
|
6128 out_of_it: |
|
6129 SCTP_TCB_UNLOCK(stcb); |
|
6130 } else { |
|
6131 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6132 error = EINVAL; |
|
6133 } |
|
6134 break; |
|
6135 } |
|
6136 case SCTP_BINDX_ADD_ADDR: |
|
6137 { |
|
6138 struct sctp_getaddresses *addrs; |
|
6139 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
6140 struct thread *td; |
|
6141 |
|
6142 td = (struct thread *)p; |
|
6143 #endif |
|
6144 SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, |
|
6145 optsize); |
|
6146 #ifdef INET |
|
6147 if (addrs->addr->sa_family == AF_INET) { |
|
6148 if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { |
|
6149 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6150 error = EINVAL; |
|
6151 break; |
|
6152 } |
|
6153 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6154 if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { |
|
6155 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6156 break; |
|
6157 } |
|
6158 #endif |
|
6159 } else |
|
6160 #endif |
|
6161 #ifdef INET6 |
|
6162 if (addrs->addr->sa_family == AF_INET6) { |
|
6163 if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { |
|
6164 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6165 error = EINVAL; |
|
6166 break; |
|
6167 } |
|
6168 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6169 if (td != NULL && (error = prison_local_ip6(td->td_ucred, &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), |
|
6170 (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { |
|
6171 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6172 break; |
|
6173 } |
|
6174 #endif |
|
6175 } else |
|
6176 #endif |
|
6177 { |
|
6178 error = EAFNOSUPPORT; |
|
6179 break; |
|
6180 } |
|
6181 sctp_bindx_add_address(so, inp, addrs->addr, |
|
6182 addrs->sget_assoc_id, vrf_id, |
|
6183 &error, p); |
|
6184 break; |
|
6185 } |
|
6186 case SCTP_BINDX_REM_ADDR: |
|
6187 { |
|
6188 struct sctp_getaddresses *addrs; |
|
6189 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
6190 struct thread *td; |
|
6191 td = (struct thread *)p; |
|
6192 |
|
6193 #endif |
|
6194 SCTP_CHECK_AND_CAST(addrs, optval, struct sctp_getaddresses, optsize); |
|
6195 #ifdef INET |
|
6196 if (addrs->addr->sa_family == AF_INET) { |
|
6197 if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in)) { |
|
6198 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6199 error = EINVAL; |
|
6200 break; |
|
6201 } |
|
6202 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6203 if (td != NULL && (error = prison_local_ip4(td->td_ucred, &(((struct sockaddr_in *)(addrs->addr))->sin_addr)))) { |
|
6204 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6205 break; |
|
6206 } |
|
6207 #endif |
|
6208 } else |
|
6209 #endif |
|
6210 #ifdef INET6 |
|
6211 if (addrs->addr->sa_family == AF_INET6) { |
|
6212 if (optsize < sizeof(struct sctp_getaddresses) - sizeof(struct sockaddr) + sizeof(struct sockaddr_in6)) { |
|
6213 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6214 error = EINVAL; |
|
6215 break; |
|
6216 } |
|
6217 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6218 if (td != NULL && |
|
6219 (error = prison_local_ip6(td->td_ucred, |
|
6220 &(((struct sockaddr_in6 *)(addrs->addr))->sin6_addr), |
|
6221 (SCTP_IPV6_V6ONLY(inp) != 0))) != 0) { |
|
6222 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6223 break; |
|
6224 } |
|
6225 #endif |
|
6226 } else |
|
6227 #endif |
|
6228 { |
|
6229 error = EAFNOSUPPORT; |
|
6230 break; |
|
6231 } |
|
6232 sctp_bindx_delete_address(inp, addrs->addr, |
|
6233 addrs->sget_assoc_id, vrf_id, |
|
6234 &error); |
|
6235 break; |
|
6236 } |
|
6237 #ifdef __APPLE__ |
|
6238 case SCTP_LISTEN_FIX: |
|
6239 /* only applies to one-to-many sockets */ |
|
6240 if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { |
|
6241 /* make sure the ACCEPTCONN flag is OFF */ |
|
6242 so->so_options &= ~SO_ACCEPTCONN; |
|
6243 } else { |
|
6244 /* otherwise, not allowed */ |
|
6245 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6246 error = EINVAL; |
|
6247 } |
|
6248 break; |
|
6249 #endif /* __APPLE__ */ |
|
6250 case SCTP_EVENT: |
|
6251 { |
|
6252 struct sctp_event *event; |
|
6253 uint32_t event_type; |
|
6254 |
|
6255 SCTP_CHECK_AND_CAST(event, optval, struct sctp_event, optsize); |
|
6256 SCTP_FIND_STCB(inp, stcb, event->se_assoc_id); |
|
6257 switch (event->se_type) { |
|
6258 case SCTP_ASSOC_CHANGE: |
|
6259 event_type = SCTP_PCB_FLAGS_RECVASSOCEVNT; |
|
6260 break; |
|
6261 case SCTP_PEER_ADDR_CHANGE: |
|
6262 event_type = SCTP_PCB_FLAGS_RECVPADDREVNT; |
|
6263 break; |
|
6264 case SCTP_REMOTE_ERROR: |
|
6265 event_type = SCTP_PCB_FLAGS_RECVPEERERR; |
|
6266 break; |
|
6267 case SCTP_SEND_FAILED: |
|
6268 event_type = SCTP_PCB_FLAGS_RECVSENDFAILEVNT; |
|
6269 break; |
|
6270 case SCTP_SHUTDOWN_EVENT: |
|
6271 event_type = SCTP_PCB_FLAGS_RECVSHUTDOWNEVNT; |
|
6272 break; |
|
6273 case SCTP_ADAPTATION_INDICATION: |
|
6274 event_type = SCTP_PCB_FLAGS_ADAPTATIONEVNT; |
|
6275 break; |
|
6276 case SCTP_PARTIAL_DELIVERY_EVENT: |
|
6277 event_type = SCTP_PCB_FLAGS_PDAPIEVNT; |
|
6278 break; |
|
6279 case SCTP_AUTHENTICATION_EVENT: |
|
6280 event_type = SCTP_PCB_FLAGS_AUTHEVNT; |
|
6281 break; |
|
6282 case SCTP_STREAM_RESET_EVENT: |
|
6283 event_type = SCTP_PCB_FLAGS_STREAM_RESETEVNT; |
|
6284 break; |
|
6285 case SCTP_SENDER_DRY_EVENT: |
|
6286 event_type = SCTP_PCB_FLAGS_DRYEVNT; |
|
6287 break; |
|
6288 case SCTP_NOTIFICATIONS_STOPPED_EVENT: |
|
6289 event_type = 0; |
|
6290 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); |
|
6291 error = ENOTSUP; |
|
6292 break; |
|
6293 case SCTP_ASSOC_RESET_EVENT: |
|
6294 event_type = SCTP_PCB_FLAGS_ASSOC_RESETEVNT; |
|
6295 break; |
|
6296 case SCTP_STREAM_CHANGE_EVENT: |
|
6297 event_type = SCTP_PCB_FLAGS_STREAM_CHANGEEVNT; |
|
6298 break; |
|
6299 case SCTP_SEND_FAILED_EVENT: |
|
6300 event_type = SCTP_PCB_FLAGS_RECVNSENDFAILEVNT; |
|
6301 break; |
|
6302 default: |
|
6303 event_type = 0; |
|
6304 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6305 error = EINVAL; |
|
6306 break; |
|
6307 } |
|
6308 if (event_type > 0) { |
|
6309 if (stcb) { |
|
6310 if (event->se_on) { |
|
6311 sctp_stcb_feature_on(inp, stcb, event_type); |
|
6312 if (event_type == SCTP_PCB_FLAGS_DRYEVNT) { |
|
6313 if (TAILQ_EMPTY(&stcb->asoc.send_queue) && |
|
6314 TAILQ_EMPTY(&stcb->asoc.sent_queue) && |
|
6315 (stcb->asoc.stream_queue_cnt == 0)) { |
|
6316 sctp_ulp_notify(SCTP_NOTIFY_SENDER_DRY, stcb, 0, NULL, SCTP_SO_LOCKED); |
|
6317 } |
|
6318 } |
|
6319 } else { |
|
6320 sctp_stcb_feature_off(inp, stcb, event_type); |
|
6321 } |
|
6322 SCTP_TCB_UNLOCK(stcb); |
|
6323 } else { |
|
6324 /* |
|
6325 * We don't want to send up a storm of events, |
|
6326 * so return an error for sender dry events |
|
6327 */ |
|
6328 if ((event_type == SCTP_PCB_FLAGS_DRYEVNT) && |
|
6329 ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) == 0) && |
|
6330 ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) == 0) && |
|
6331 ((event->se_assoc_id == SCTP_ALL_ASSOC) || |
|
6332 (event->se_assoc_id == SCTP_CURRENT_ASSOC))) { |
|
6333 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTSUP); |
|
6334 error = ENOTSUP; |
|
6335 break; |
|
6336 } |
|
6337 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
6338 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
6339 (event->se_assoc_id == SCTP_FUTURE_ASSOC) || |
|
6340 (event->se_assoc_id == SCTP_ALL_ASSOC)) { |
|
6341 SCTP_INP_WLOCK(inp); |
|
6342 if (event->se_on) { |
|
6343 sctp_feature_on(inp, event_type); |
|
6344 } else { |
|
6345 sctp_feature_off(inp, event_type); |
|
6346 } |
|
6347 SCTP_INP_WUNLOCK(inp); |
|
6348 } |
|
6349 if ((event->se_assoc_id == SCTP_CURRENT_ASSOC) || |
|
6350 (event->se_assoc_id == SCTP_ALL_ASSOC)) { |
|
6351 SCTP_INP_RLOCK(inp); |
|
6352 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
6353 SCTP_TCB_LOCK(stcb); |
|
6354 if (event->se_on) { |
|
6355 sctp_stcb_feature_on(inp, stcb, event_type); |
|
6356 } else { |
|
6357 sctp_stcb_feature_off(inp, stcb, event_type); |
|
6358 } |
|
6359 SCTP_TCB_UNLOCK(stcb); |
|
6360 } |
|
6361 SCTP_INP_RUNLOCK(inp); |
|
6362 } |
|
6363 } |
|
6364 } |
|
6365 break; |
|
6366 } |
|
6367 case SCTP_RECVRCVINFO: |
|
6368 { |
|
6369 int *onoff; |
|
6370 |
|
6371 SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); |
|
6372 SCTP_INP_WLOCK(inp); |
|
6373 if (*onoff != 0) { |
|
6374 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVRCVINFO); |
|
6375 } else { |
|
6376 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVRCVINFO); |
|
6377 } |
|
6378 SCTP_INP_WUNLOCK(inp); |
|
6379 break; |
|
6380 } |
|
6381 case SCTP_RECVNXTINFO: |
|
6382 { |
|
6383 int *onoff; |
|
6384 |
|
6385 SCTP_CHECK_AND_CAST(onoff, optval, int, optsize); |
|
6386 SCTP_INP_WLOCK(inp); |
|
6387 if (*onoff != 0) { |
|
6388 sctp_feature_on(inp, SCTP_PCB_FLAGS_RECVNXTINFO); |
|
6389 } else { |
|
6390 sctp_feature_off(inp, SCTP_PCB_FLAGS_RECVNXTINFO); |
|
6391 } |
|
6392 SCTP_INP_WUNLOCK(inp); |
|
6393 break; |
|
6394 } |
|
6395 case SCTP_DEFAULT_SNDINFO: |
|
6396 { |
|
6397 struct sctp_sndinfo *info; |
|
6398 uint16_t policy; |
|
6399 |
|
6400 SCTP_CHECK_AND_CAST(info, optval, struct sctp_sndinfo, optsize); |
|
6401 SCTP_FIND_STCB(inp, stcb, info->snd_assoc_id); |
|
6402 |
|
6403 if (stcb) { |
|
6404 if (info->snd_sid < stcb->asoc.streamoutcnt) { |
|
6405 stcb->asoc.def_send.sinfo_stream = info->snd_sid; |
|
6406 policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); |
|
6407 stcb->asoc.def_send.sinfo_flags = info->snd_flags; |
|
6408 stcb->asoc.def_send.sinfo_flags |= policy; |
|
6409 stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; |
|
6410 stcb->asoc.def_send.sinfo_context = info->snd_context; |
|
6411 } else { |
|
6412 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6413 error = EINVAL; |
|
6414 } |
|
6415 SCTP_TCB_UNLOCK(stcb); |
|
6416 } else { |
|
6417 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
6418 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
6419 (info->snd_assoc_id == SCTP_FUTURE_ASSOC) || |
|
6420 (info->snd_assoc_id == SCTP_ALL_ASSOC)) { |
|
6421 SCTP_INP_WLOCK(inp); |
|
6422 inp->def_send.sinfo_stream = info->snd_sid; |
|
6423 policy = PR_SCTP_POLICY(inp->def_send.sinfo_flags); |
|
6424 inp->def_send.sinfo_flags = info->snd_flags; |
|
6425 inp->def_send.sinfo_flags |= policy; |
|
6426 inp->def_send.sinfo_ppid = info->snd_ppid; |
|
6427 inp->def_send.sinfo_context = info->snd_context; |
|
6428 SCTP_INP_WUNLOCK(inp); |
|
6429 } |
|
6430 if ((info->snd_assoc_id == SCTP_CURRENT_ASSOC) || |
|
6431 (info->snd_assoc_id == SCTP_ALL_ASSOC)) { |
|
6432 SCTP_INP_RLOCK(inp); |
|
6433 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
6434 SCTP_TCB_LOCK(stcb); |
|
6435 if (info->snd_sid < stcb->asoc.streamoutcnt) { |
|
6436 stcb->asoc.def_send.sinfo_stream = info->snd_sid; |
|
6437 policy = PR_SCTP_POLICY(stcb->asoc.def_send.sinfo_flags); |
|
6438 stcb->asoc.def_send.sinfo_flags = info->snd_flags; |
|
6439 stcb->asoc.def_send.sinfo_flags |= policy; |
|
6440 stcb->asoc.def_send.sinfo_ppid = info->snd_ppid; |
|
6441 stcb->asoc.def_send.sinfo_context = info->snd_context; |
|
6442 } |
|
6443 SCTP_TCB_UNLOCK(stcb); |
|
6444 } |
|
6445 SCTP_INP_RUNLOCK(inp); |
|
6446 } |
|
6447 } |
|
6448 break; |
|
6449 } |
|
6450 case SCTP_DEFAULT_PRINFO: |
|
6451 { |
|
6452 struct sctp_default_prinfo *info; |
|
6453 |
|
6454 SCTP_CHECK_AND_CAST(info, optval, struct sctp_default_prinfo, optsize); |
|
6455 SCTP_FIND_STCB(inp, stcb, info->pr_assoc_id); |
|
6456 |
|
6457 if (PR_SCTP_INVALID_POLICY(info->pr_policy)) { |
|
6458 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6459 error = EINVAL; |
|
6460 break; |
|
6461 } |
|
6462 if (stcb) { |
|
6463 stcb->asoc.def_send.sinfo_flags &= 0xfff0; |
|
6464 stcb->asoc.def_send.sinfo_flags |= info->pr_policy; |
|
6465 stcb->asoc.def_send.sinfo_timetolive = info->pr_value; |
|
6466 SCTP_TCB_UNLOCK(stcb); |
|
6467 } else { |
|
6468 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
6469 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
6470 (info->pr_assoc_id == SCTP_FUTURE_ASSOC) || |
|
6471 (info->pr_assoc_id == SCTP_ALL_ASSOC)) { |
|
6472 SCTP_INP_WLOCK(inp); |
|
6473 inp->def_send.sinfo_flags &= 0xfff0; |
|
6474 inp->def_send.sinfo_flags |= info->pr_policy; |
|
6475 inp->def_send.sinfo_timetolive = info->pr_value; |
|
6476 SCTP_INP_WUNLOCK(inp); |
|
6477 } |
|
6478 if ((info->pr_assoc_id == SCTP_CURRENT_ASSOC) || |
|
6479 (info->pr_assoc_id == SCTP_ALL_ASSOC)) { |
|
6480 SCTP_INP_RLOCK(inp); |
|
6481 LIST_FOREACH(stcb, &inp->sctp_asoc_list, sctp_tcblist) { |
|
6482 SCTP_TCB_LOCK(stcb); |
|
6483 stcb->asoc.def_send.sinfo_flags &= 0xfff0; |
|
6484 stcb->asoc.def_send.sinfo_flags |= info->pr_policy; |
|
6485 stcb->asoc.def_send.sinfo_timetolive = info->pr_value; |
|
6486 SCTP_TCB_UNLOCK(stcb); |
|
6487 } |
|
6488 SCTP_INP_RUNLOCK(inp); |
|
6489 } |
|
6490 } |
|
6491 break; |
|
6492 } |
|
6493 case SCTP_PEER_ADDR_THLDS: |
|
6494 /* Applies to the specific association */ |
|
6495 { |
|
6496 struct sctp_paddrthlds *thlds; |
|
6497 struct sctp_nets *net; |
|
6498 |
|
6499 SCTP_CHECK_AND_CAST(thlds, optval, struct sctp_paddrthlds, optsize); |
|
6500 SCTP_FIND_STCB(inp, stcb, thlds->spt_assoc_id); |
|
6501 net = NULL; |
|
6502 if (stcb) { |
|
6503 net = sctp_findnet(stcb, (struct sockaddr *)&thlds->spt_assoc_id); |
|
6504 } else { |
|
6505 /* We increment here since sctp_findassociation_ep_addr() wil |
|
6506 * do a decrement if it finds the stcb as long as the locked |
|
6507 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
6508 */ |
|
6509 SCTP_INP_INCR_REF(inp); |
|
6510 stcb = sctp_findassociation_ep_addr(&inp, |
|
6511 (struct sockaddr *)&thlds->spt_assoc_id, |
|
6512 &net, NULL, NULL); |
|
6513 if (stcb == NULL) { |
|
6514 SCTP_INP_DECR_REF(inp); |
|
6515 } |
|
6516 } |
|
6517 if (stcb && (net == NULL)) { |
|
6518 struct sockaddr *sa; |
|
6519 |
|
6520 sa = (struct sockaddr *)&thlds->spt_assoc_id; |
|
6521 #ifdef INET |
|
6522 if (sa->sa_family == AF_INET) { |
|
6523 |
|
6524 struct sockaddr_in *sin; |
|
6525 sin = (struct sockaddr_in *)sa; |
|
6526 if (sin->sin_addr.s_addr) { |
|
6527 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6528 SCTP_TCB_UNLOCK(stcb); |
|
6529 error = EINVAL; |
|
6530 break; |
|
6531 } |
|
6532 } else |
|
6533 #endif |
|
6534 #ifdef INET6 |
|
6535 if (sa->sa_family == AF_INET6) { |
|
6536 struct sockaddr_in6 *sin6; |
|
6537 |
|
6538 sin6 = (struct sockaddr_in6 *)sa; |
|
6539 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
6540 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6541 SCTP_TCB_UNLOCK(stcb); |
|
6542 error = EINVAL; |
|
6543 break; |
|
6544 } |
|
6545 } else |
|
6546 #endif |
|
6547 #if defined(__Userspace__) |
|
6548 if (sa->sa_family == AF_CONN) { |
|
6549 struct sockaddr_conn *sconn; |
|
6550 |
|
6551 sconn = (struct sockaddr_conn *)sa; |
|
6552 if (sconn->sconn_addr != NULL) { |
|
6553 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6554 SCTP_TCB_UNLOCK(stcb); |
|
6555 error = EINVAL; |
|
6556 break; |
|
6557 } |
|
6558 } else |
|
6559 #endif |
|
6560 { |
|
6561 error = EAFNOSUPPORT; |
|
6562 SCTP_TCB_UNLOCK(stcb); |
|
6563 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6564 break; |
|
6565 } |
|
6566 } |
|
6567 if (stcb) { |
|
6568 if (net) { |
|
6569 if (net->dest_state & SCTP_ADDR_PF) { |
|
6570 if ((net->failure_threshold > thlds->spt_pathmaxrxt) || |
|
6571 (net->failure_threshold <= thlds->spt_pathpfthld)) { |
|
6572 net->dest_state &= ~SCTP_ADDR_PF; |
|
6573 } |
|
6574 } else { |
|
6575 if ((net->failure_threshold > thlds->spt_pathpfthld) && |
|
6576 (net->failure_threshold <= thlds->spt_pathmaxrxt)) { |
|
6577 net->dest_state |= SCTP_ADDR_PF; |
|
6578 sctp_send_hb(stcb, net, SCTP_SO_LOCKED); |
|
6579 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); |
|
6580 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); |
|
6581 } |
|
6582 } |
|
6583 if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
6584 if (net->failure_threshold > thlds->spt_pathmaxrxt) { |
|
6585 net->dest_state &= ~SCTP_ADDR_REACHABLE; |
|
6586 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); |
|
6587 } |
|
6588 } else { |
|
6589 if (net->failure_threshold <= thlds->spt_pathmaxrxt) { |
|
6590 net->dest_state |= SCTP_ADDR_REACHABLE; |
|
6591 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); |
|
6592 } |
|
6593 } |
|
6594 net->failure_threshold = thlds->spt_pathmaxrxt; |
|
6595 net->pf_threshold = thlds->spt_pathpfthld; |
|
6596 } else { |
|
6597 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
6598 if (net->dest_state & SCTP_ADDR_PF) { |
|
6599 if ((net->failure_threshold > thlds->spt_pathmaxrxt) || |
|
6600 (net->failure_threshold <= thlds->spt_pathpfthld)) { |
|
6601 net->dest_state &= ~SCTP_ADDR_PF; |
|
6602 } |
|
6603 } else { |
|
6604 if ((net->failure_threshold > thlds->spt_pathpfthld) && |
|
6605 (net->failure_threshold <= thlds->spt_pathmaxrxt)) { |
|
6606 net->dest_state |= SCTP_ADDR_PF; |
|
6607 sctp_send_hb(stcb, net, SCTP_SO_LOCKED); |
|
6608 sctp_timer_stop(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net, SCTP_FROM_SCTP_TIMER + SCTP_LOC_3); |
|
6609 sctp_timer_start(SCTP_TIMER_TYPE_HEARTBEAT, stcb->sctp_ep, stcb, net); |
|
6610 } |
|
6611 } |
|
6612 if (net->dest_state & SCTP_ADDR_REACHABLE) { |
|
6613 if (net->failure_threshold > thlds->spt_pathmaxrxt) { |
|
6614 net->dest_state &= ~SCTP_ADDR_REACHABLE; |
|
6615 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_DOWN, stcb, 0, net, SCTP_SO_LOCKED); |
|
6616 } |
|
6617 } else { |
|
6618 if (net->failure_threshold <= thlds->spt_pathmaxrxt) { |
|
6619 net->dest_state |= SCTP_ADDR_REACHABLE; |
|
6620 sctp_ulp_notify(SCTP_NOTIFY_INTERFACE_UP, stcb, 0, net, SCTP_SO_LOCKED); |
|
6621 } |
|
6622 } |
|
6623 net->failure_threshold = thlds->spt_pathmaxrxt; |
|
6624 net->pf_threshold = thlds->spt_pathpfthld; |
|
6625 } |
|
6626 stcb->asoc.def_net_failure = thlds->spt_pathmaxrxt; |
|
6627 stcb->asoc.def_net_pf_threshold = thlds->spt_pathpfthld; |
|
6628 } |
|
6629 } else { |
|
6630 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
6631 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
6632 (thlds->spt_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
6633 SCTP_INP_WLOCK(inp); |
|
6634 inp->sctp_ep.def_net_failure = thlds->spt_pathmaxrxt; |
|
6635 inp->sctp_ep.def_net_pf_threshold = thlds->spt_pathpfthld; |
|
6636 SCTP_INP_WUNLOCK(inp); |
|
6637 } else { |
|
6638 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6639 error = EINVAL; |
|
6640 } |
|
6641 } |
|
6642 break; |
|
6643 } |
|
6644 case SCTP_REMOTE_UDP_ENCAPS_PORT: |
|
6645 { |
|
6646 struct sctp_udpencaps *encaps; |
|
6647 struct sctp_nets *net; |
|
6648 |
|
6649 SCTP_CHECK_AND_CAST(encaps, optval, struct sctp_udpencaps, optsize); |
|
6650 SCTP_FIND_STCB(inp, stcb, encaps->sue_assoc_id); |
|
6651 if (stcb) { |
|
6652 net = sctp_findnet(stcb, (struct sockaddr *)&encaps->sue_address); |
|
6653 } else { |
|
6654 /* We increment here since sctp_findassociation_ep_addr() wil |
|
6655 * do a decrement if it finds the stcb as long as the locked |
|
6656 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
6657 */ |
|
6658 net = NULL; |
|
6659 SCTP_INP_INCR_REF(inp); |
|
6660 stcb = sctp_findassociation_ep_addr(&inp, (struct sockaddr *)&encaps->sue_address, &net, NULL, NULL); |
|
6661 if (stcb == NULL) { |
|
6662 SCTP_INP_DECR_REF(inp); |
|
6663 } |
|
6664 } |
|
6665 if (stcb && (net == NULL)) { |
|
6666 struct sockaddr *sa; |
|
6667 |
|
6668 sa = (struct sockaddr *)&encaps->sue_address; |
|
6669 #ifdef INET |
|
6670 if (sa->sa_family == AF_INET) { |
|
6671 |
|
6672 struct sockaddr_in *sin; |
|
6673 sin = (struct sockaddr_in *)sa; |
|
6674 if (sin->sin_addr.s_addr) { |
|
6675 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6676 SCTP_TCB_UNLOCK(stcb); |
|
6677 error = EINVAL; |
|
6678 break; |
|
6679 } |
|
6680 } else |
|
6681 #endif |
|
6682 #ifdef INET6 |
|
6683 if (sa->sa_family == AF_INET6) { |
|
6684 struct sockaddr_in6 *sin6; |
|
6685 |
|
6686 sin6 = (struct sockaddr_in6 *)sa; |
|
6687 if (!IN6_IS_ADDR_UNSPECIFIED(&sin6->sin6_addr)) { |
|
6688 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6689 SCTP_TCB_UNLOCK(stcb); |
|
6690 error = EINVAL; |
|
6691 break; |
|
6692 } |
|
6693 } else |
|
6694 #endif |
|
6695 #if defined(__Userspace__) |
|
6696 if (sa->sa_family == AF_CONN) { |
|
6697 struct sockaddr_conn *sconn; |
|
6698 |
|
6699 sconn = (struct sockaddr_conn *)sa; |
|
6700 if (sconn->sconn_addr != NULL) { |
|
6701 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6702 SCTP_TCB_UNLOCK(stcb); |
|
6703 error = EINVAL; |
|
6704 break; |
|
6705 } |
|
6706 } else |
|
6707 #endif |
|
6708 { |
|
6709 error = EAFNOSUPPORT; |
|
6710 SCTP_TCB_UNLOCK(stcb); |
|
6711 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6712 break; |
|
6713 } |
|
6714 } |
|
6715 |
|
6716 if (stcb) { |
|
6717 if (net) { |
|
6718 net->port = encaps->sue_port; |
|
6719 } else { |
|
6720 stcb->asoc.port = encaps->sue_port; |
|
6721 } |
|
6722 SCTP_TCB_UNLOCK(stcb); |
|
6723 } else { |
|
6724 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || |
|
6725 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) || |
|
6726 (encaps->sue_assoc_id == SCTP_FUTURE_ASSOC)) { |
|
6727 SCTP_INP_WLOCK(inp); |
|
6728 inp->sctp_ep.port = encaps->sue_port; |
|
6729 SCTP_INP_WUNLOCK(inp); |
|
6730 } else { |
|
6731 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6732 error = EINVAL; |
|
6733 } |
|
6734 } |
|
6735 break; |
|
6736 } |
|
6737 default: |
|
6738 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOPROTOOPT); |
|
6739 error = ENOPROTOOPT; |
|
6740 break; |
|
6741 } /* end switch (opt) */ |
|
6742 return (error); |
|
6743 } |
|
6744 |
|
6745 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
6746 int |
|
6747 sctp_ctloutput(struct socket *so, struct sockopt *sopt) |
|
6748 { |
|
6749 void *optval = NULL; |
|
6750 size_t optsize = 0; |
|
6751 void *p; |
|
6752 int error = 0; |
|
6753 |
|
6754 if (sopt->sopt_level != IPPROTO_SCTP) { |
|
6755 /* wrong proto level... send back up to IP */ |
|
6756 #ifdef INET6 |
|
6757 if (INP_CHECK_SOCKAF(so, AF_INET6)) |
|
6758 error = ip6_ctloutput(so, sopt); |
|
6759 #endif /* INET6 */ |
|
6760 #if defined(INET) && defined(INET6) |
|
6761 else |
|
6762 #endif |
|
6763 #ifdef INET |
|
6764 error = ip_ctloutput(so, sopt); |
|
6765 #endif |
|
6766 return (error); |
|
6767 } |
|
6768 optsize = sopt->sopt_valsize; |
|
6769 if (optsize) { |
|
6770 SCTP_MALLOC(optval, void *, optsize, SCTP_M_SOCKOPT); |
|
6771 if (optval == NULL) { |
|
6772 SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOBUFS); |
|
6773 return (ENOBUFS); |
|
6774 } |
|
6775 error = sooptcopyin(sopt, optval, optsize, optsize); |
|
6776 if (error) { |
|
6777 SCTP_FREE(optval, SCTP_M_SOCKOPT); |
|
6778 goto out; |
|
6779 } |
|
6780 } |
|
6781 #if (defined(__FreeBSD__) && __FreeBSD_version >= 500000) || defined(__Windows__) |
|
6782 p = (void *)sopt->sopt_td; |
|
6783 #else |
|
6784 p = (void *)sopt->sopt_p; |
|
6785 #endif |
|
6786 if (sopt->sopt_dir == SOPT_SET) { |
|
6787 error = sctp_setopt(so, sopt->sopt_name, optval, optsize, p); |
|
6788 } else if (sopt->sopt_dir == SOPT_GET) { |
|
6789 error = sctp_getopt(so, sopt->sopt_name, optval, &optsize, p); |
|
6790 } else { |
|
6791 SCTP_LTRACE_ERR_RET(so->so_pcb, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6792 error = EINVAL; |
|
6793 } |
|
6794 if ((error == 0) && (optval != NULL)) { |
|
6795 error = sooptcopyout(sopt, optval, optsize); |
|
6796 SCTP_FREE(optval, SCTP_M_SOCKOPT); |
|
6797 } else if (optval != NULL) { |
|
6798 SCTP_FREE(optval, SCTP_M_SOCKOPT); |
|
6799 } |
|
6800 out: |
|
6801 return (error); |
|
6802 } |
|
6803 #endif |
|
6804 |
|
6805 #ifdef INET |
|
6806 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
6807 static int |
|
6808 sctp_connect(struct socket *so, struct sockaddr *addr, struct thread *p) |
|
6809 { |
|
6810 #else |
|
6811 #if defined(__FreeBSD__) || defined(__APPLE__) |
|
6812 static int |
|
6813 sctp_connect(struct socket *so, struct sockaddr *addr, struct proc *p) |
|
6814 { |
|
6815 #elif defined(__Panda__) || defined(__Userspace__) |
|
6816 int |
|
6817 sctp_connect(struct socket *so, struct sockaddr *addr) |
|
6818 { |
|
6819 void *p = NULL; |
|
6820 #elif defined(__Windows__) |
|
6821 static int |
|
6822 sctp_connect(struct socket *so, struct sockaddr *addr, PKTHREAD p) |
|
6823 { |
|
6824 #else |
|
6825 static int |
|
6826 sctp_connect(struct socket *so, struct mbuf *nam, struct proc *p) |
|
6827 { |
|
6828 struct sockaddr *addr = mtod(nam, struct sockaddr *); |
|
6829 |
|
6830 #endif |
|
6831 #endif |
|
6832 #ifdef SCTP_MVRF |
|
6833 int i, fnd = 0; |
|
6834 #endif |
|
6835 int error = 0; |
|
6836 int create_lock_on = 0; |
|
6837 uint32_t vrf_id; |
|
6838 struct sctp_inpcb *inp; |
|
6839 struct sctp_tcb *stcb = NULL; |
|
6840 |
|
6841 inp = (struct sctp_inpcb *)so->so_pcb; |
|
6842 if (inp == NULL) { |
|
6843 /* I made the same as TCP since we are not setup? */ |
|
6844 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6845 return (ECONNRESET); |
|
6846 } |
|
6847 if (addr == NULL) { |
|
6848 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6849 return EINVAL; |
|
6850 } |
|
6851 |
|
6852 #if defined(__Userspace__) |
|
6853 /* TODO __Userspace__ falls into this code for IPv6 stuff at the moment... */ |
|
6854 #endif |
|
6855 #if !defined(__Windows__) && !defined(__Userspace_os_Linux) && !defined(__Userspace_os_Windows) |
|
6856 switch (addr->sa_family) { |
|
6857 #ifdef INET6 |
|
6858 case AF_INET6: |
|
6859 { |
|
6860 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6861 struct sockaddr_in6 *sin6p; |
|
6862 |
|
6863 #endif |
|
6864 if (addr->sa_len != sizeof(struct sockaddr_in6)) { |
|
6865 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6866 return (EINVAL); |
|
6867 } |
|
6868 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6869 sin6p = (struct sockaddr_in6 *)addr; |
|
6870 if (p != NULL && (error = prison_remote_ip6(p->td_ucred, &sin6p->sin6_addr)) != 0) { |
|
6871 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6872 return (error); |
|
6873 } |
|
6874 #endif |
|
6875 break; |
|
6876 } |
|
6877 #endif |
|
6878 #ifdef INET |
|
6879 case AF_INET: |
|
6880 { |
|
6881 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6882 struct sockaddr_in *sinp; |
|
6883 |
|
6884 #endif |
|
6885 #if !defined(__Userspace_os_Windows) |
|
6886 if (addr->sa_len != sizeof(struct sockaddr_in)) { |
|
6887 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6888 return (EINVAL); |
|
6889 } |
|
6890 #endif |
|
6891 #if defined(__FreeBSD__) && __FreeBSD_version >= 800000 |
|
6892 sinp = (struct sockaddr_in *)addr; |
|
6893 if (p != NULL && (error = prison_remote_ip4(p->td_ucred, &sinp->sin_addr)) != 0) { |
|
6894 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, error); |
|
6895 return (error); |
|
6896 } |
|
6897 #endif |
|
6898 break; |
|
6899 } |
|
6900 #endif |
|
6901 default: |
|
6902 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); |
|
6903 return (EAFNOSUPPORT); |
|
6904 } |
|
6905 #endif |
|
6906 SCTP_INP_INCR_REF(inp); |
|
6907 SCTP_ASOC_CREATE_LOCK(inp); |
|
6908 create_lock_on = 1; |
|
6909 |
|
6910 |
|
6911 if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || |
|
6912 (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { |
|
6913 /* Should I really unlock ? */ |
|
6914 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); |
|
6915 error = EFAULT; |
|
6916 goto out_now; |
|
6917 } |
|
6918 #ifdef INET6 |
|
6919 if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && |
|
6920 (addr->sa_family == AF_INET6)) { |
|
6921 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6922 error = EINVAL; |
|
6923 goto out_now; |
|
6924 } |
|
6925 #endif |
|
6926 #if defined(__Userspace__) |
|
6927 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_CONN) && |
|
6928 (addr->sa_family != AF_CONN)) { |
|
6929 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6930 error = EINVAL; |
|
6931 goto out_now; |
|
6932 } |
|
6933 #endif |
|
6934 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == |
|
6935 SCTP_PCB_FLAGS_UNBOUND) { |
|
6936 /* Bind a ephemeral port */ |
|
6937 error = sctp_inpcb_bind(so, NULL, NULL, p); |
|
6938 if (error) { |
|
6939 goto out_now; |
|
6940 } |
|
6941 } |
|
6942 /* Now do we connect? */ |
|
6943 if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && |
|
6944 (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { |
|
6945 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6946 error = EINVAL; |
|
6947 goto out_now; |
|
6948 } |
|
6949 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
6950 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { |
|
6951 /* We are already connected AND the TCP model */ |
|
6952 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); |
|
6953 error = EADDRINUSE; |
|
6954 goto out_now; |
|
6955 } |
|
6956 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { |
|
6957 SCTP_INP_RLOCK(inp); |
|
6958 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
6959 SCTP_INP_RUNLOCK(inp); |
|
6960 } else { |
|
6961 /* We increment here since sctp_findassociation_ep_addr() will |
|
6962 * do a decrement if it finds the stcb as long as the locked |
|
6963 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
6964 */ |
|
6965 SCTP_INP_INCR_REF(inp); |
|
6966 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); |
|
6967 if (stcb == NULL) { |
|
6968 SCTP_INP_DECR_REF(inp); |
|
6969 } else { |
|
6970 SCTP_TCB_UNLOCK(stcb); |
|
6971 } |
|
6972 } |
|
6973 if (stcb != NULL) { |
|
6974 /* Already have or am bring up an association */ |
|
6975 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
6976 error = EALREADY; |
|
6977 goto out_now; |
|
6978 } |
|
6979 |
|
6980 vrf_id = inp->def_vrf_id; |
|
6981 #ifdef SCTP_MVRF |
|
6982 for (i = 0; i < inp->num_vrfs; i++) { |
|
6983 if (vrf_id == inp->m_vrf_ids[i]) { |
|
6984 fnd = 1; |
|
6985 break; |
|
6986 } |
|
6987 } |
|
6988 if (!fnd) { |
|
6989 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
6990 error = EINVAL; |
|
6991 goto out_now; |
|
6992 } |
|
6993 #endif |
|
6994 /* We are GOOD to go */ |
|
6995 stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); |
|
6996 if (stcb == NULL) { |
|
6997 /* Gak! no memory */ |
|
6998 goto out_now; |
|
6999 } |
|
7000 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { |
|
7001 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
7002 /* Set the connected flag so we can queue data */ |
|
7003 soisconnecting(so); |
|
7004 } |
|
7005 SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); |
|
7006 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
7007 |
|
7008 /* initialize authentication parameters for the assoc */ |
|
7009 sctp_initialize_auth_params(inp, stcb); |
|
7010 |
|
7011 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
|
7012 SCTP_TCB_UNLOCK(stcb); |
|
7013 out_now: |
|
7014 if (create_lock_on) { |
|
7015 SCTP_ASOC_CREATE_UNLOCK(inp); |
|
7016 } |
|
7017 |
|
7018 SCTP_INP_DECR_REF(inp); |
|
7019 return (error); |
|
7020 } |
|
7021 #endif |
|
7022 |
|
7023 #if defined(__Userspace__) |
|
7024 int |
|
7025 sctpconn_connect(struct socket *so, struct sockaddr *addr) |
|
7026 { |
|
7027 #ifdef SCTP_MVRF |
|
7028 int i, fnd = 0; |
|
7029 #endif |
|
7030 void *p = NULL; |
|
7031 int error = 0; |
|
7032 int create_lock_on = 0; |
|
7033 uint32_t vrf_id; |
|
7034 struct sctp_inpcb *inp; |
|
7035 struct sctp_tcb *stcb = NULL; |
|
7036 |
|
7037 inp = (struct sctp_inpcb *)so->so_pcb; |
|
7038 if (inp == NULL) { |
|
7039 /* I made the same as TCP since we are not setup? */ |
|
7040 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7041 return (ECONNRESET); |
|
7042 } |
|
7043 if (addr == NULL) { |
|
7044 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7045 return EINVAL; |
|
7046 } |
|
7047 switch (addr->sa_family) { |
|
7048 #ifdef INET |
|
7049 case AF_INET: |
|
7050 #ifdef HAVE_SA_LEN |
|
7051 if (addr->sa_len != sizeof(struct sockaddr_in)) { |
|
7052 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7053 return (EINVAL); |
|
7054 } |
|
7055 #endif |
|
7056 break; |
|
7057 #endif |
|
7058 #ifdef INET6 |
|
7059 case AF_INET6: |
|
7060 #ifdef HAVE_SA_LEN |
|
7061 if (addr->sa_len != sizeof(struct sockaddr_in6)) { |
|
7062 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7063 return (EINVAL); |
|
7064 } |
|
7065 #endif |
|
7066 break; |
|
7067 #endif |
|
7068 case AF_CONN: |
|
7069 #ifdef HAVE_SA_LEN |
|
7070 if (addr->sa_len != sizeof(struct sockaddr_conn)) { |
|
7071 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7072 return (EINVAL); |
|
7073 } |
|
7074 #endif |
|
7075 break; |
|
7076 default: |
|
7077 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); |
|
7078 return (EAFNOSUPPORT); |
|
7079 } |
|
7080 SCTP_INP_INCR_REF(inp); |
|
7081 SCTP_ASOC_CREATE_LOCK(inp); |
|
7082 create_lock_on = 1; |
|
7083 |
|
7084 |
|
7085 if ((inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) || |
|
7086 (inp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE)) { |
|
7087 /* Should I really unlock ? */ |
|
7088 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EFAULT); |
|
7089 error = EFAULT; |
|
7090 goto out_now; |
|
7091 } |
|
7092 #ifdef INET6 |
|
7093 if (((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) && |
|
7094 (addr->sa_family == AF_INET6)) { |
|
7095 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7096 error = EINVAL; |
|
7097 goto out_now; |
|
7098 } |
|
7099 #endif |
|
7100 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) == SCTP_PCB_FLAGS_UNBOUND) { |
|
7101 /* Bind a ephemeral port */ |
|
7102 error = sctp_inpcb_bind(so, NULL, NULL, p); |
|
7103 if (error) { |
|
7104 goto out_now; |
|
7105 } |
|
7106 } |
|
7107 /* Now do we connect? */ |
|
7108 if ((inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL) && |
|
7109 (sctp_is_feature_off(inp, SCTP_PCB_FLAGS_PORTREUSE))) { |
|
7110 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7111 error = EINVAL; |
|
7112 goto out_now; |
|
7113 } |
|
7114 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
7115 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { |
|
7116 /* We are already connected AND the TCP model */ |
|
7117 SCTP_LTRACE_ERR_RET(inp, stcb, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); |
|
7118 error = EADDRINUSE; |
|
7119 goto out_now; |
|
7120 } |
|
7121 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { |
|
7122 SCTP_INP_RLOCK(inp); |
|
7123 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
7124 SCTP_INP_RUNLOCK(inp); |
|
7125 } else { |
|
7126 /* We increment here since sctp_findassociation_ep_addr() will |
|
7127 * do a decrement if it finds the stcb as long as the locked |
|
7128 * tcb (last argument) is NOT a TCB.. aka NULL. |
|
7129 */ |
|
7130 SCTP_INP_INCR_REF(inp); |
|
7131 stcb = sctp_findassociation_ep_addr(&inp, addr, NULL, NULL, NULL); |
|
7132 if (stcb == NULL) { |
|
7133 SCTP_INP_DECR_REF(inp); |
|
7134 } else { |
|
7135 SCTP_TCB_UNLOCK(stcb); |
|
7136 } |
|
7137 } |
|
7138 if (stcb != NULL) { |
|
7139 /* Already have or am bring up an association */ |
|
7140 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EALREADY); |
|
7141 error = EALREADY; |
|
7142 goto out_now; |
|
7143 } |
|
7144 |
|
7145 vrf_id = inp->def_vrf_id; |
|
7146 #ifdef SCTP_MVRF |
|
7147 for (i = 0; i < inp->num_vrfs; i++) { |
|
7148 if (vrf_id == inp->m_vrf_ids[i]) { |
|
7149 fnd = 1; |
|
7150 break; |
|
7151 } |
|
7152 } |
|
7153 if (!fnd) { |
|
7154 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7155 error = EINVAL; |
|
7156 goto out_now; |
|
7157 } |
|
7158 #endif |
|
7159 /* We are GOOD to go */ |
|
7160 stcb = sctp_aloc_assoc(inp, addr, &error, 0, vrf_id, p); |
|
7161 if (stcb == NULL) { |
|
7162 /* Gak! no memory */ |
|
7163 goto out_now; |
|
7164 } |
|
7165 if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) { |
|
7166 stcb->sctp_ep->sctp_flags |= SCTP_PCB_FLAGS_CONNECTED; |
|
7167 /* Set the connected flag so we can queue data */ |
|
7168 soisconnecting(so); |
|
7169 } |
|
7170 SCTP_SET_STATE(&stcb->asoc, SCTP_STATE_COOKIE_WAIT); |
|
7171 (void)SCTP_GETTIME_TIMEVAL(&stcb->asoc.time_entered); |
|
7172 |
|
7173 /* initialize authentication parameters for the assoc */ |
|
7174 sctp_initialize_auth_params(inp, stcb); |
|
7175 |
|
7176 sctp_send_initiate(inp, stcb, SCTP_SO_LOCKED); |
|
7177 SCTP_TCB_UNLOCK(stcb); |
|
7178 out_now: |
|
7179 if (create_lock_on) { |
|
7180 SCTP_ASOC_CREATE_UNLOCK(inp); |
|
7181 } |
|
7182 |
|
7183 SCTP_INP_DECR_REF(inp); |
|
7184 return (error); |
|
7185 } |
|
7186 #endif |
|
7187 int |
|
7188 #if defined(__FreeBSD__) && __FreeBSD_version >= 500000 |
|
7189 #if __FreeBSD_version >= 700000 |
|
7190 sctp_listen(struct socket *so, int backlog, struct thread *p) |
|
7191 #else |
|
7192 sctp_listen(struct socket *so, struct thread *p) |
|
7193 #endif |
|
7194 #elif defined(__Windows__) |
|
7195 sctp_listen(struct socket *so, int backlog, PKTHREAD p) |
|
7196 #elif defined(__Userspace__) |
|
7197 sctp_listen(struct socket *so, int backlog, struct proc *p) |
|
7198 #else |
|
7199 sctp_listen(struct socket *so, struct proc *p) |
|
7200 #endif |
|
7201 { |
|
7202 /* |
|
7203 * Note this module depends on the protocol processing being called |
|
7204 * AFTER any socket level flags and backlog are applied to the |
|
7205 * socket. The traditional way that the socket flags are applied is |
|
7206 * AFTER protocol processing. We have made a change to the |
|
7207 * sys/kern/uipc_socket.c module to reverse this but this MUST be in |
|
7208 * place if the socket API for SCTP is to work properly. |
|
7209 */ |
|
7210 |
|
7211 int error = 0; |
|
7212 struct sctp_inpcb *inp; |
|
7213 |
|
7214 inp = (struct sctp_inpcb *)so->so_pcb; |
|
7215 if (inp == NULL) { |
|
7216 /* I made the same as TCP since we are not setup? */ |
|
7217 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7218 return (ECONNRESET); |
|
7219 } |
|
7220 if (sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) { |
|
7221 /* See if we have a listener */ |
|
7222 struct sctp_inpcb *tinp; |
|
7223 union sctp_sockstore store, *sp; |
|
7224 |
|
7225 sp = &store; |
|
7226 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) == 0) { |
|
7227 /* not bound all */ |
|
7228 struct sctp_laddr *laddr; |
|
7229 |
|
7230 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
|
7231 memcpy(&store, &laddr->ifa->address, sizeof(store)); |
|
7232 switch (sp->sa.sa_family) { |
|
7233 #ifdef INET |
|
7234 case AF_INET: |
|
7235 sp->sin.sin_port = inp->sctp_lport; |
|
7236 break; |
|
7237 #endif |
|
7238 #ifdef INET6 |
|
7239 case AF_INET6: |
|
7240 sp->sin6.sin6_port = inp->sctp_lport; |
|
7241 break; |
|
7242 #endif |
|
7243 #if defined(__Userspace__) |
|
7244 case AF_CONN: |
|
7245 sp->sconn.sconn_port = inp->sctp_lport; |
|
7246 break; |
|
7247 #endif |
|
7248 default: |
|
7249 break; |
|
7250 } |
|
7251 tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); |
|
7252 if (tinp && (tinp != inp) && |
|
7253 ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && |
|
7254 ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
7255 (tinp->sctp_socket->so_qlimit)) { |
|
7256 /* we have a listener already and its not this inp. */ |
|
7257 SCTP_INP_DECR_REF(tinp); |
|
7258 return (EADDRINUSE); |
|
7259 } else if (tinp) { |
|
7260 SCTP_INP_DECR_REF(tinp); |
|
7261 } |
|
7262 } |
|
7263 } else { |
|
7264 /* Setup a local addr bound all */ |
|
7265 memset(&store, 0, sizeof(store)); |
|
7266 switch (sp->sa.sa_family) { |
|
7267 #ifdef INET |
|
7268 case AF_INET: |
|
7269 store.sin.sin_port = inp->sctp_lport; |
|
7270 break; |
|
7271 #endif |
|
7272 #ifdef INET6 |
|
7273 case AF_INET6: |
|
7274 sp->sin6.sin6_port = inp->sctp_lport; |
|
7275 break; |
|
7276 #endif |
|
7277 #if defined(__Userspace__) |
|
7278 case AF_CONN: |
|
7279 sp->sconn.sconn_port = inp->sctp_lport; |
|
7280 break; |
|
7281 #endif |
|
7282 default: |
|
7283 break; |
|
7284 } |
|
7285 #ifdef INET6 |
|
7286 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { |
|
7287 store.sa.sa_family = AF_INET6; |
|
7288 #ifdef HAVE_SA_LEN |
|
7289 store.sa.sa_len = sizeof(struct sockaddr_in6); |
|
7290 #endif |
|
7291 } |
|
7292 #endif |
|
7293 #ifdef INET |
|
7294 if ((inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) == 0) { |
|
7295 store.sa.sa_family = AF_INET; |
|
7296 #ifdef HAVE_SA_LEN |
|
7297 store.sa.sa_len = sizeof(struct sockaddr_in); |
|
7298 #endif |
|
7299 } |
|
7300 #endif |
|
7301 tinp = sctp_pcb_findep(&sp->sa, 0, 0, inp->def_vrf_id); |
|
7302 if (tinp && (tinp != inp) && |
|
7303 ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_ALLGONE) == 0) && |
|
7304 ((tinp->sctp_flags & SCTP_PCB_FLAGS_SOCKET_GONE) == 0) && |
|
7305 (tinp->sctp_socket->so_qlimit)) { |
|
7306 /* we have a listener already and its not this inp. */ |
|
7307 SCTP_INP_DECR_REF(tinp); |
|
7308 return (EADDRINUSE); |
|
7309 } else if (tinp) { |
|
7310 SCTP_INP_DECR_REF(inp); |
|
7311 } |
|
7312 } |
|
7313 } |
|
7314 SCTP_INP_RLOCK(inp); |
|
7315 #ifdef SCTP_LOCK_LOGGING |
|
7316 if (SCTP_BASE_SYSCTL(sctp_logging_level) & SCTP_LOCK_LOGGING_ENABLE) { |
|
7317 sctp_log_lock(inp, (struct sctp_tcb *)NULL, SCTP_LOG_LOCK_SOCK); |
|
7318 } |
|
7319 #endif |
|
7320 SOCK_LOCK(so); |
|
7321 #if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Userspace__) |
|
7322 error = solisten_proto_check(so); |
|
7323 if (error) { |
|
7324 SOCK_UNLOCK(so); |
|
7325 SCTP_INP_RUNLOCK(inp); |
|
7326 return (error); |
|
7327 } |
|
7328 #endif |
|
7329 if ((sctp_is_feature_on(inp, SCTP_PCB_FLAGS_PORTREUSE)) && |
|
7330 (inp->sctp_flags & SCTP_PCB_FLAGS_IN_TCPPOOL)) { |
|
7331 /* The unlucky case |
|
7332 * - We are in the tcp pool with this guy. |
|
7333 * - Someone else is in the main inp slot. |
|
7334 * - We must move this guy (the listener) to the main slot |
|
7335 * - We must then move the guy that was listener to the TCP Pool. |
|
7336 */ |
|
7337 if (sctp_swap_inpcb_for_listen(inp)) { |
|
7338 goto in_use; |
|
7339 } |
|
7340 } |
|
7341 |
|
7342 if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) && |
|
7343 (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED)) { |
|
7344 /* We are already connected AND the TCP model */ |
|
7345 in_use: |
|
7346 SCTP_INP_RUNLOCK(inp); |
|
7347 SOCK_UNLOCK(so); |
|
7348 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EADDRINUSE); |
|
7349 return (EADDRINUSE); |
|
7350 } |
|
7351 SCTP_INP_RUNLOCK(inp); |
|
7352 if (inp->sctp_flags & SCTP_PCB_FLAGS_UNBOUND) { |
|
7353 /* We must do a bind. */ |
|
7354 SOCK_UNLOCK(so); |
|
7355 if ((error = sctp_inpcb_bind(so, NULL, NULL, p))) { |
|
7356 /* bind error, probably perm */ |
|
7357 return (error); |
|
7358 } |
|
7359 SOCK_LOCK(so); |
|
7360 } |
|
7361 #if (defined(__FreeBSD__) && __FreeBSD_version > 500000) || defined(__Windows__) || defined(__Userspace__) |
|
7362 #if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__) |
|
7363 /* It appears for 7.0 and on, we must always call this. */ |
|
7364 solisten_proto(so, backlog); |
|
7365 #else |
|
7366 if ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) == 0) { |
|
7367 solisten_proto(so); |
|
7368 } |
|
7369 #endif |
|
7370 #endif |
|
7371 if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { |
|
7372 /* remove the ACCEPTCONN flag for one-to-many sockets */ |
|
7373 #if defined(__Userspace__) |
|
7374 so->so_options &= ~SCTP_SO_ACCEPTCONN; |
|
7375 #else |
|
7376 so->so_options &= ~SO_ACCEPTCONN; |
|
7377 #endif |
|
7378 } |
|
7379 |
|
7380 #if __FreeBSD_version >= 700000 || defined(__Windows__) || defined(__Userspace__) |
|
7381 if (backlog == 0) { |
|
7382 /* turning off listen */ |
|
7383 #if defined(__Userspace__) |
|
7384 so->so_options &= ~SCTP_SO_ACCEPTCONN; |
|
7385 #else |
|
7386 so->so_options &= ~SO_ACCEPTCONN; |
|
7387 #endif |
|
7388 } |
|
7389 #endif |
|
7390 SOCK_UNLOCK(so); |
|
7391 return (error); |
|
7392 } |
|
7393 |
|
7394 static int sctp_defered_wakeup_cnt = 0; |
|
7395 |
|
7396 int |
|
7397 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) |
|
7398 sctp_accept(struct socket *so, struct sockaddr **addr) |
|
7399 { |
|
7400 #elif defined(__Panda__) |
|
7401 sctp_accept(struct socket *so, struct sockaddr *addr, int *namelen, |
|
7402 void *accept_info, int *accept_info_len) |
|
7403 { |
|
7404 #else |
|
7405 sctp_accept(struct socket *so, struct mbuf *nam) |
|
7406 { |
|
7407 struct sockaddr *addr = mtod(nam, struct sockaddr *); |
|
7408 #endif |
|
7409 struct sctp_tcb *stcb; |
|
7410 struct sctp_inpcb *inp; |
|
7411 union sctp_sockstore store; |
|
7412 #ifdef INET6 |
|
7413 #ifdef SCTP_KAME |
|
7414 int error; |
|
7415 #endif /* SCTP_KAME */ |
|
7416 #endif |
|
7417 inp = (struct sctp_inpcb *)so->so_pcb; |
|
7418 |
|
7419 if (inp == NULL) { |
|
7420 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7421 return (ECONNRESET); |
|
7422 } |
|
7423 SCTP_INP_RLOCK(inp); |
|
7424 if (inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) { |
|
7425 SCTP_INP_RUNLOCK(inp); |
|
7426 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EOPNOTSUPP); |
|
7427 return (EOPNOTSUPP); |
|
7428 } |
|
7429 if (so->so_state & SS_ISDISCONNECTED) { |
|
7430 SCTP_INP_RUNLOCK(inp); |
|
7431 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ECONNABORTED); |
|
7432 return (ECONNABORTED); |
|
7433 } |
|
7434 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
7435 if (stcb == NULL) { |
|
7436 SCTP_INP_RUNLOCK(inp); |
|
7437 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7438 return (ECONNRESET); |
|
7439 } |
|
7440 SCTP_TCB_LOCK(stcb); |
|
7441 SCTP_INP_RUNLOCK(inp); |
|
7442 store = stcb->asoc.primary_destination->ro._l_addr; |
|
7443 stcb->asoc.state &= ~SCTP_STATE_IN_ACCEPT_QUEUE; |
|
7444 SCTP_TCB_UNLOCK(stcb); |
|
7445 switch (store.sa.sa_family) { |
|
7446 #ifdef INET |
|
7447 case AF_INET: |
|
7448 { |
|
7449 struct sockaddr_in *sin; |
|
7450 |
|
7451 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) |
|
7452 SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); |
|
7453 if (sin == NULL) |
|
7454 return (ENOMEM); |
|
7455 #else |
|
7456 sin = (struct sockaddr_in *)addr; |
|
7457 bzero((caddr_t)sin, sizeof(*sin)); |
|
7458 #endif |
|
7459 sin->sin_family = AF_INET; |
|
7460 #ifdef HAVE_SIN_LEN |
|
7461 sin->sin_len = sizeof(*sin); |
|
7462 #endif |
|
7463 sin->sin_port = store.sin.sin_port; |
|
7464 sin->sin_addr = store.sin.sin_addr; |
|
7465 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) |
|
7466 *addr = (struct sockaddr *)sin; |
|
7467 #elif !defined(__Panda__) |
|
7468 SCTP_BUF_LEN(nam) = sizeof(*sin); |
|
7469 #endif |
|
7470 break; |
|
7471 } |
|
7472 #endif |
|
7473 #ifdef INET6 |
|
7474 case AF_INET6: |
|
7475 { |
|
7476 struct sockaddr_in6 *sin6; |
|
7477 |
|
7478 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) |
|
7479 SCTP_MALLOC_SONAME(sin6, struct sockaddr_in6 *, sizeof *sin6); |
|
7480 if (sin6 == NULL) |
|
7481 return (ENOMEM); |
|
7482 #else |
|
7483 sin6 = (struct sockaddr_in6 *)addr; |
|
7484 bzero((caddr_t)sin6, sizeof(*sin6)); |
|
7485 #endif |
|
7486 sin6->sin6_family = AF_INET6; |
|
7487 #ifdef HAVE_SIN6_LEN |
|
7488 sin6->sin6_len = sizeof(*sin6); |
|
7489 #endif |
|
7490 sin6->sin6_port = store.sin6.sin6_port; |
|
7491 sin6->sin6_addr = store.sin6.sin6_addr; |
|
7492 #if defined(SCTP_EMBEDDED_V6_SCOPE) |
|
7493 #ifdef SCTP_KAME |
|
7494 if ((error = sa6_recoverscope(sin6)) != 0) { |
|
7495 SCTP_FREE_SONAME(sin6); |
|
7496 return (error); |
|
7497 } |
|
7498 #else |
|
7499 if (IN6_IS_SCOPE_LINKLOCAL(&sin6->sin6_addr)) |
|
7500 /* |
|
7501 * sin6->sin6_scope_id = |
|
7502 * ntohs(sin6->sin6_addr.s6_addr16[1]); |
|
7503 */ |
|
7504 in6_recoverscope(sin6, &sin6->sin6_addr, NULL); /* skip ifp check */ |
|
7505 else |
|
7506 sin6->sin6_scope_id = 0; /* XXX */ |
|
7507 #endif /* SCTP_KAME */ |
|
7508 #endif /* SCTP_EMBEDDED_V6_SCOPE */ |
|
7509 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) || defined(__Userspace__) |
|
7510 *addr = (struct sockaddr *)sin6; |
|
7511 #elif !defined(__Panda__) |
|
7512 SCTP_BUF_LEN(nam) = sizeof(*sin6); |
|
7513 #endif |
|
7514 break; |
|
7515 } |
|
7516 #endif |
|
7517 #if defined(__Userspace__) |
|
7518 case AF_CONN: |
|
7519 { |
|
7520 struct sockaddr_conn *sconn; |
|
7521 |
|
7522 SCTP_MALLOC_SONAME(sconn, struct sockaddr_conn *, sizeof(struct sockaddr_conn)); |
|
7523 if (sconn == NULL) { |
|
7524 return (ENOMEM); |
|
7525 } |
|
7526 sconn->sconn_family = AF_CONN; |
|
7527 #ifdef HAVE_SCONN_LEN |
|
7528 sconn->sconn_len = sizeof(struct sockaddr_conn); |
|
7529 #endif |
|
7530 sconn->sconn_port = store.sconn.sconn_port; |
|
7531 sconn->sconn_addr = store.sconn.sconn_addr; |
|
7532 *addr = (struct sockaddr *)sconn; |
|
7533 break; |
|
7534 } |
|
7535 #endif |
|
7536 default: |
|
7537 /* TSNH */ |
|
7538 break; |
|
7539 } |
|
7540 /* Wake any delayed sleep action */ |
|
7541 if (inp->sctp_flags & SCTP_PCB_FLAGS_DONT_WAKE) { |
|
7542 SCTP_INP_WLOCK(inp); |
|
7543 inp->sctp_flags &= ~SCTP_PCB_FLAGS_DONT_WAKE; |
|
7544 if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEOUTPUT) { |
|
7545 inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEOUTPUT; |
|
7546 SCTP_INP_WUNLOCK(inp); |
|
7547 SOCKBUF_LOCK(&inp->sctp_socket->so_snd); |
|
7548 if (sowriteable(inp->sctp_socket)) { |
|
7549 #if defined(__Userspace__) |
|
7550 /*__Userspace__ calling sowwakup_locked because of SOCKBUF_LOCK above. */ |
|
7551 #endif |
|
7552 #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__) |
|
7553 sowwakeup_locked(inp->sctp_socket); |
|
7554 #else |
|
7555 #if defined(__APPLE__) |
|
7556 /* socket is locked */ |
|
7557 #endif |
|
7558 sowwakeup(inp->sctp_socket); |
|
7559 #endif |
|
7560 } else { |
|
7561 SOCKBUF_UNLOCK(&inp->sctp_socket->so_snd); |
|
7562 } |
|
7563 SCTP_INP_WLOCK(inp); |
|
7564 } |
|
7565 if (inp->sctp_flags & SCTP_PCB_FLAGS_WAKEINPUT) { |
|
7566 inp->sctp_flags &= ~SCTP_PCB_FLAGS_WAKEINPUT; |
|
7567 SCTP_INP_WUNLOCK(inp); |
|
7568 SOCKBUF_LOCK(&inp->sctp_socket->so_rcv); |
|
7569 if (soreadable(inp->sctp_socket)) { |
|
7570 sctp_defered_wakeup_cnt++; |
|
7571 #if defined(__Userspace__) |
|
7572 /*__Userspace__ calling sorwakup_locked because of SOCKBUF_LOCK above */ |
|
7573 #endif |
|
7574 #if defined(__FreeBSD__) || defined(__Windows__) || defined(__Userspace__) |
|
7575 sorwakeup_locked(inp->sctp_socket); |
|
7576 #else |
|
7577 #if defined(__APPLE__) |
|
7578 /* socket is locked */ |
|
7579 #endif |
|
7580 sorwakeup(inp->sctp_socket); |
|
7581 #endif |
|
7582 } else { |
|
7583 SOCKBUF_UNLOCK(&inp->sctp_socket->so_rcv); |
|
7584 } |
|
7585 SCTP_INP_WLOCK(inp); |
|
7586 } |
|
7587 SCTP_INP_WUNLOCK(inp); |
|
7588 } |
|
7589 if (stcb->asoc.state & SCTP_STATE_ABOUT_TO_BE_FREED) { |
|
7590 SCTP_TCB_LOCK(stcb); |
|
7591 sctp_free_assoc(inp, stcb, SCTP_NORMAL_PROC, SCTP_FROM_SCTP_USRREQ+SCTP_LOC_7); |
|
7592 } |
|
7593 return (0); |
|
7594 } |
|
7595 |
|
7596 #ifdef INET |
|
7597 int |
|
7598 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7599 sctp_ingetaddr(struct socket *so, struct sockaddr **addr) |
|
7600 { |
|
7601 struct sockaddr_in *sin; |
|
7602 #elif defined(__Panda__) |
|
7603 sctp_ingetaddr(struct socket *so, struct sockaddr *addr) |
|
7604 { |
|
7605 struct sockaddr_in *sin = (struct sockaddr_in *)addr; |
|
7606 #else |
|
7607 sctp_ingetaddr(struct socket *so, struct mbuf *nam) |
|
7608 { |
|
7609 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); |
|
7610 #endif |
|
7611 uint32_t vrf_id; |
|
7612 struct sctp_inpcb *inp; |
|
7613 struct sctp_ifa *sctp_ifa; |
|
7614 |
|
7615 /* |
|
7616 * Do the malloc first in case it blocks. |
|
7617 */ |
|
7618 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7619 SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); |
|
7620 if (sin == NULL) |
|
7621 return (ENOMEM); |
|
7622 #elif defined(__Panda__) |
|
7623 bzero(sin, sizeof(*sin)); |
|
7624 #else |
|
7625 SCTP_BUF_LEN(nam) = sizeof(*sin); |
|
7626 memset(sin, 0, sizeof(*sin)); |
|
7627 #endif |
|
7628 sin->sin_family = AF_INET; |
|
7629 #ifdef HAVE_SIN_LEN |
|
7630 sin->sin_len = sizeof(*sin); |
|
7631 #endif |
|
7632 inp = (struct sctp_inpcb *)so->so_pcb; |
|
7633 if (!inp) { |
|
7634 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7635 SCTP_FREE_SONAME(sin); |
|
7636 #endif |
|
7637 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7638 return (ECONNRESET); |
|
7639 } |
|
7640 SCTP_INP_RLOCK(inp); |
|
7641 sin->sin_port = inp->sctp_lport; |
|
7642 if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUNDALL) { |
|
7643 if (inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) { |
|
7644 struct sctp_tcb *stcb; |
|
7645 struct sockaddr_in *sin_a; |
|
7646 struct sctp_nets *net; |
|
7647 int fnd; |
|
7648 |
|
7649 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
7650 if (stcb == NULL) { |
|
7651 goto notConn; |
|
7652 } |
|
7653 fnd = 0; |
|
7654 sin_a = NULL; |
|
7655 SCTP_TCB_LOCK(stcb); |
|
7656 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
7657 sin_a = (struct sockaddr_in *)&net->ro._l_addr; |
|
7658 if (sin_a == NULL) |
|
7659 /* this will make coverity happy */ |
|
7660 continue; |
|
7661 |
|
7662 if (sin_a->sin_family == AF_INET) { |
|
7663 fnd = 1; |
|
7664 break; |
|
7665 } |
|
7666 } |
|
7667 if ((!fnd) || (sin_a == NULL)) { |
|
7668 /* punt */ |
|
7669 SCTP_TCB_UNLOCK(stcb); |
|
7670 goto notConn; |
|
7671 } |
|
7672 |
|
7673 vrf_id = inp->def_vrf_id; |
|
7674 sctp_ifa = sctp_source_address_selection(inp, |
|
7675 stcb, |
|
7676 (sctp_route_t *)&net->ro, |
|
7677 net, 0, vrf_id); |
|
7678 if (sctp_ifa) { |
|
7679 sin->sin_addr = sctp_ifa->address.sin.sin_addr; |
|
7680 sctp_free_ifa(sctp_ifa); |
|
7681 } |
|
7682 SCTP_TCB_UNLOCK(stcb); |
|
7683 } else { |
|
7684 /* For the bound all case you get back 0 */ |
|
7685 notConn: |
|
7686 sin->sin_addr.s_addr = 0; |
|
7687 } |
|
7688 |
|
7689 } else { |
|
7690 /* Take the first IPv4 address in the list */ |
|
7691 struct sctp_laddr *laddr; |
|
7692 int fnd = 0; |
|
7693 |
|
7694 LIST_FOREACH(laddr, &inp->sctp_addr_list, sctp_nxt_addr) { |
|
7695 if (laddr->ifa->address.sa.sa_family == AF_INET) { |
|
7696 struct sockaddr_in *sin_a; |
|
7697 |
|
7698 sin_a = (struct sockaddr_in *)&laddr->ifa->address.sa; |
|
7699 sin->sin_addr = sin_a->sin_addr; |
|
7700 fnd = 1; |
|
7701 break; |
|
7702 } |
|
7703 } |
|
7704 if (!fnd) { |
|
7705 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7706 SCTP_FREE_SONAME(sin); |
|
7707 #endif |
|
7708 SCTP_INP_RUNLOCK(inp); |
|
7709 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
7710 return (ENOENT); |
|
7711 } |
|
7712 } |
|
7713 SCTP_INP_RUNLOCK(inp); |
|
7714 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7715 (*addr) = (struct sockaddr *)sin; |
|
7716 #endif |
|
7717 return (0); |
|
7718 } |
|
7719 |
|
7720 int |
|
7721 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7722 sctp_peeraddr(struct socket *so, struct sockaddr **addr) |
|
7723 { |
|
7724 struct sockaddr_in *sin; |
|
7725 #elif defined(__Panda__) |
|
7726 sctp_peeraddr(struct socket *so, struct sockaddr *addr) |
|
7727 { |
|
7728 struct sockaddr_in *sin = (struct sockaddr_in *)addr; |
|
7729 #else |
|
7730 sctp_peeraddr(struct socket *so, struct mbuf *nam) |
|
7731 { |
|
7732 struct sockaddr_in *sin = mtod(nam, struct sockaddr_in *); |
|
7733 |
|
7734 #endif |
|
7735 int fnd; |
|
7736 struct sockaddr_in *sin_a; |
|
7737 struct sctp_inpcb *inp; |
|
7738 struct sctp_tcb *stcb; |
|
7739 struct sctp_nets *net; |
|
7740 |
|
7741 /* Do the malloc first in case it blocks. */ |
|
7742 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7743 SCTP_MALLOC_SONAME(sin, struct sockaddr_in *, sizeof *sin); |
|
7744 if (sin == NULL) |
|
7745 return (ENOMEM); |
|
7746 #elif defined(__Panda__) |
|
7747 memset(sin, 0, sizeof(*sin)); |
|
7748 #else |
|
7749 SCTP_BUF_LEN(nam) = sizeof(*sin); |
|
7750 memset(sin, 0, sizeof(*sin)); |
|
7751 #endif |
|
7752 sin->sin_family = AF_INET; |
|
7753 #ifdef HAVE_SIN_LEN |
|
7754 sin->sin_len = sizeof(*sin); |
|
7755 #endif |
|
7756 |
|
7757 inp = (struct sctp_inpcb *)so->so_pcb; |
|
7758 if ((inp == NULL) || |
|
7759 ((inp->sctp_flags & SCTP_PCB_FLAGS_CONNECTED) == 0)) { |
|
7760 /* UDP type and listeners will drop out here */ |
|
7761 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7762 SCTP_FREE_SONAME(sin); |
|
7763 #endif |
|
7764 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOTCONN); |
|
7765 return (ENOTCONN); |
|
7766 } |
|
7767 SCTP_INP_RLOCK(inp); |
|
7768 stcb = LIST_FIRST(&inp->sctp_asoc_list); |
|
7769 if (stcb) { |
|
7770 SCTP_TCB_LOCK(stcb); |
|
7771 } |
|
7772 SCTP_INP_RUNLOCK(inp); |
|
7773 if (stcb == NULL) { |
|
7774 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7775 SCTP_FREE_SONAME(sin); |
|
7776 #endif |
|
7777 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7778 return (ECONNRESET); |
|
7779 } |
|
7780 fnd = 0; |
|
7781 TAILQ_FOREACH(net, &stcb->asoc.nets, sctp_next) { |
|
7782 sin_a = (struct sockaddr_in *)&net->ro._l_addr; |
|
7783 if (sin_a->sin_family == AF_INET) { |
|
7784 fnd = 1; |
|
7785 sin->sin_port = stcb->rport; |
|
7786 sin->sin_addr = sin_a->sin_addr; |
|
7787 break; |
|
7788 } |
|
7789 } |
|
7790 SCTP_TCB_UNLOCK(stcb); |
|
7791 if (!fnd) { |
|
7792 /* No IPv4 address */ |
|
7793 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7794 SCTP_FREE_SONAME(sin); |
|
7795 #endif |
|
7796 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, ENOENT); |
|
7797 return (ENOENT); |
|
7798 } |
|
7799 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7800 (*addr) = (struct sockaddr *)sin; |
|
7801 #endif |
|
7802 return (0); |
|
7803 } |
|
7804 |
|
7805 #if defined(__FreeBSD__) || defined(__APPLE__) || defined(__Windows__) |
|
7806 struct pr_usrreqs sctp_usrreqs = { |
|
7807 #if defined(__FreeBSD__) |
|
7808 .pru_abort = sctp_abort, |
|
7809 .pru_accept = sctp_accept, |
|
7810 .pru_attach = sctp_attach, |
|
7811 .pru_bind = sctp_bind, |
|
7812 .pru_connect = sctp_connect, |
|
7813 .pru_control = in_control, |
|
7814 #if __FreeBSD_version >= 690000 |
|
7815 .pru_close = sctp_close, |
|
7816 .pru_detach = sctp_close, |
|
7817 .pru_sopoll = sopoll_generic, |
|
7818 .pru_flush = sctp_flush, |
|
7819 #else |
|
7820 .pru_detach = sctp_detach, |
|
7821 .pru_sopoll = sopoll, |
|
7822 #endif |
|
7823 .pru_disconnect = sctp_disconnect, |
|
7824 .pru_listen = sctp_listen, |
|
7825 .pru_peeraddr = sctp_peeraddr, |
|
7826 .pru_send = sctp_sendm, |
|
7827 .pru_shutdown = sctp_shutdown, |
|
7828 .pru_sockaddr = sctp_ingetaddr, |
|
7829 .pru_sosend = sctp_sosend, |
|
7830 .pru_soreceive = sctp_soreceive |
|
7831 #elif defined(__APPLE__) |
|
7832 .pru_abort = sctp_abort, |
|
7833 .pru_accept = sctp_accept, |
|
7834 .pru_attach = sctp_attach, |
|
7835 .pru_bind = sctp_bind, |
|
7836 .pru_connect = sctp_connect, |
|
7837 .pru_connect2 = pru_connect2_notsupp, |
|
7838 .pru_control = in_control, |
|
7839 .pru_detach = sctp_detach, |
|
7840 .pru_disconnect = sctp_disconnect, |
|
7841 .pru_listen = sctp_listen, |
|
7842 .pru_peeraddr = sctp_peeraddr, |
|
7843 .pru_rcvd = NULL, |
|
7844 .pru_rcvoob = pru_rcvoob_notsupp, |
|
7845 .pru_send = sctp_sendm, |
|
7846 .pru_sense = pru_sense_null, |
|
7847 .pru_shutdown = sctp_shutdown, |
|
7848 .pru_sockaddr = sctp_ingetaddr, |
|
7849 .pru_sosend = sctp_sosend, |
|
7850 .pru_soreceive = sctp_soreceive, |
|
7851 .pru_sopoll = sopoll |
|
7852 #elif defined(__Windows__) |
|
7853 sctp_abort, |
|
7854 sctp_accept, |
|
7855 sctp_attach, |
|
7856 sctp_bind, |
|
7857 sctp_connect, |
|
7858 pru_connect2_notsupp, |
|
7859 NULL, |
|
7860 NULL, |
|
7861 sctp_disconnect, |
|
7862 sctp_listen, |
|
7863 sctp_peeraddr, |
|
7864 NULL, |
|
7865 pru_rcvoob_notsupp, |
|
7866 NULL, |
|
7867 pru_sense_null, |
|
7868 sctp_shutdown, |
|
7869 sctp_flush, |
|
7870 sctp_ingetaddr, |
|
7871 sctp_sosend, |
|
7872 sctp_soreceive, |
|
7873 sopoll_generic, |
|
7874 NULL, |
|
7875 sctp_close |
|
7876 #endif |
|
7877 }; |
|
7878 #elif !defined(__Panda__) && !defined(__Userspace__) |
|
7879 int |
|
7880 sctp_usrreq(so, req, m, nam, control) |
|
7881 struct socket *so; |
|
7882 int req; |
|
7883 struct mbuf *m, *nam, *control; |
|
7884 { |
|
7885 struct proc *p = curproc; |
|
7886 uint32_t vrf_id; |
|
7887 struct sctp_vrf *vrf; |
|
7888 int error; |
|
7889 int family; |
|
7890 struct sctp_inpcb *inp = (struct sctp_inpcb *)so->so_pcb; |
|
7891 |
|
7892 error = 0; |
|
7893 family = so->so_proto->pr_domain->dom_family; |
|
7894 if (req == PRU_CONTROL) { |
|
7895 switch (family) { |
|
7896 case PF_INET: |
|
7897 error = in_control(so, (long)m, (caddr_t)nam, |
|
7898 (struct ifnet *)control); |
|
7899 break; |
|
7900 #ifdef INET6 |
|
7901 case PF_INET6: |
|
7902 error = in6_control(so, (long)m, (caddr_t)nam, |
|
7903 (struct ifnet *)control, p); |
|
7904 break; |
|
7905 #endif |
|
7906 default: |
|
7907 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); |
|
7908 error = EAFNOSUPPORT; |
|
7909 } |
|
7910 return (error); |
|
7911 } |
|
7912 switch (req) { |
|
7913 case PRU_ATTACH: |
|
7914 error = sctp_attach(so, family, p); |
|
7915 break; |
|
7916 case PRU_DETACH: |
|
7917 error = sctp_detach(so); |
|
7918 break; |
|
7919 case PRU_BIND: |
|
7920 if (nam == NULL) { |
|
7921 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7922 return (EINVAL); |
|
7923 } |
|
7924 error = sctp_bind(so, nam, p); |
|
7925 break; |
|
7926 case PRU_LISTEN: |
|
7927 error = sctp_listen(so, p); |
|
7928 break; |
|
7929 case PRU_CONNECT: |
|
7930 if (nam == NULL) { |
|
7931 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7932 return (EINVAL); |
|
7933 } |
|
7934 error = sctp_connect(so, nam, p); |
|
7935 break; |
|
7936 case PRU_DISCONNECT: |
|
7937 error = sctp_disconnect(so); |
|
7938 break; |
|
7939 case PRU_ACCEPT: |
|
7940 if (nam == NULL) { |
|
7941 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); |
|
7942 return (EINVAL); |
|
7943 } |
|
7944 error = sctp_accept(so, nam); |
|
7945 break; |
|
7946 case PRU_SHUTDOWN: |
|
7947 error = sctp_shutdown(so); |
|
7948 break; |
|
7949 |
|
7950 case PRU_RCVD: |
|
7951 /* |
|
7952 * For Open and Net BSD, this is real ugly. The mbuf *nam |
|
7953 * that is passed (by soreceive()) is the int flags c ast as |
|
7954 * a (mbuf *) yuck! |
|
7955 */ |
|
7956 break; |
|
7957 |
|
7958 case PRU_SEND: |
|
7959 /* Flags are ignored */ |
|
7960 { |
|
7961 struct sockaddr *addr; |
|
7962 |
|
7963 if (nam == NULL) |
|
7964 addr = NULL; |
|
7965 else |
|
7966 addr = mtod(nam, struct sockaddr *); |
|
7967 |
|
7968 error = sctp_sendm(so, 0, m, addr, control, p); |
|
7969 } |
|
7970 break; |
|
7971 case PRU_ABORT: |
|
7972 error = sctp_abort(so); |
|
7973 break; |
|
7974 |
|
7975 case PRU_SENSE: |
|
7976 error = 0; |
|
7977 break; |
|
7978 case PRU_RCVOOB: |
|
7979 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); |
|
7980 error = EAFNOSUPPORT; |
|
7981 break; |
|
7982 case PRU_SENDOOB: |
|
7983 SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EAFNOSUPPORT); |
|
7984 error = EAFNOSUPPORT; |
|
7985 break; |
|
7986 case PRU_PEERADDR: |
|
7987 error = sctp_peeraddr(so, nam); |
|
7988 break; |
|
7989 case PRU_SOCKADDR: |
|
7990 error = sctp_ingetaddr(so, nam); |
|
7991 break; |
|
7992 case PRU_SLOWTIMO: |
|
7993 error = 0; |
|
7994 break; |
|
7995 default: |
|
7996 break; |
|
7997 } |
|
7998 return (error); |
|
7999 } |
|
8000 |
|
8001 #endif |
|
8002 #endif |
|
8003 |
|
8004 #if defined(__Userspace__) |
|
8005 int |
|
8006 register_recv_cb(struct socket *so, |
|
8007 int (*receive_cb)(struct socket *sock, union sctp_sockstore addr, void *data, |
|
8008 size_t datalen, struct sctp_rcvinfo, int flags, void *ulp_info)) |
|
8009 { |
|
8010 struct sctp_inpcb *inp; |
|
8011 |
|
8012 inp = (struct sctp_inpcb *) so->so_pcb; |
|
8013 if (inp == NULL) { |
|
8014 return (0); |
|
8015 } |
|
8016 SCTP_INP_WLOCK(inp); |
|
8017 inp->recv_callback = receive_cb; |
|
8018 SCTP_INP_WUNLOCK(inp); |
|
8019 return (1); |
|
8020 } |
|
8021 |
|
8022 int |
|
8023 register_send_cb(struct socket *so, uint32_t sb_threshold, int (*send_cb)(struct socket *sock, uint32_t sb_free)) |
|
8024 { |
|
8025 struct sctp_inpcb *inp; |
|
8026 |
|
8027 inp = (struct sctp_inpcb *) so->so_pcb; |
|
8028 if (inp == NULL) { |
|
8029 return (0); |
|
8030 } |
|
8031 SCTP_INP_WLOCK(inp); |
|
8032 inp->send_callback = send_cb; |
|
8033 inp->send_sb_threshold = sb_threshold; |
|
8034 SCTP_INP_WUNLOCK(inp); |
|
8035 /* FIXME change to current amount free. This will be the full buffer |
|
8036 * the first time this is registered but it could be only a portion |
|
8037 * of the send buffer if this is called a second time e.g. if the |
|
8038 * threshold changes. |
|
8039 */ |
|
8040 return (1); |
|
8041 } |
|
8042 |
|
8043 int |
|
8044 register_ulp_info (struct socket *so, void *ulp_info) |
|
8045 { |
|
8046 struct sctp_inpcb *inp; |
|
8047 |
|
8048 inp = (struct sctp_inpcb *) so->so_pcb; |
|
8049 if (inp == NULL) { |
|
8050 return (0); |
|
8051 } |
|
8052 SCTP_INP_WLOCK(inp); |
|
8053 inp->ulp_info = ulp_info; |
|
8054 SCTP_INP_WUNLOCK(inp); |
|
8055 return (1); |
|
8056 } |
|
8057 #endif |