Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
linux
Commits
7cd48512
Commit
7cd48512
authored
Mar 02, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Plain Diff
Merge us.ibm.com:/home/sridhar/BK/lksctp-2.5.work
into us.ibm.com:/home/sridhar/BK/lksctp-2.5.63
parents
1026ffaf
bf953999
Changes
7
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
419 additions
and
100 deletions
+419
-100
include/net/sctp/structs.h
include/net/sctp/structs.h
+2
-0
net/sctp/endpointola.c
net/sctp/endpointola.c
+2
-0
net/sctp/ipv6.c
net/sctp/ipv6.c
+72
-4
net/sctp/protocol.c
net/sctp/protocol.c
+73
-5
net/sctp/sm_sideeffect.c
net/sctp/sm_sideeffect.c
+21
-6
net/sctp/socket.c
net/sctp/socket.c
+247
-83
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+2
-2
No files found.
include/net/sctp/structs.h
View file @
7cd48512
...
...
@@ -262,6 +262,8 @@ struct sctp_pf {
struct
sctp_opt
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
struct
sock
*
(
*
create_accept_sk
)
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
);
struct
sctp_af
*
af
;
};
...
...
net/sctp/endpointola.c
View file @
7cd48512
...
...
@@ -195,6 +195,8 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
{
SCTP_ASSERT
(
ep
->
base
.
dead
,
"Endpoint is not dead"
,
return
);
ep
->
base
.
sk
->
state
=
SCTP_SS_CLOSED
;
/* Unlink this endpoint, so we can't find it again! */
sctp_unhash_endpoint
(
ep
);
...
...
net/sctp/ipv6.c
View file @
7cd48512
...
...
@@ -432,6 +432,62 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
return
retval
;
}
/* Create and initialize a new sk for the socket to be returned by accept(). */
struct
sock
*
sctp_v6_create_accept_sk
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
)
{
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
sock
*
newsk
;
struct
inet_opt
*
newinet
;
struct
ipv6_pinfo
*
newnp
,
*
np
=
inet6_sk
(
sk
);
struct
sctp6_sock
*
newsctp6sk
;
newsk
=
sk_alloc
(
PF_INET6
,
GFP_KERNEL
,
sizeof
(
struct
sctp6_sock
),
sk
->
slab
);
if
(
!
newsk
)
goto
out
;
sock_init_data
(
NULL
,
newsk
);
newsk
->
type
=
SOCK_STREAM
;
newsk
->
prot
=
sk
->
prot
;
newsk
->
no_check
=
sk
->
no_check
;
newsk
->
reuse
=
sk
->
reuse
;
newsk
->
destruct
=
inet_sock_destruct
;
newsk
->
zapped
=
0
;
newsk
->
family
=
PF_INET6
;
newsk
->
protocol
=
IPPROTO_SCTP
;
newsk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
newsctp6sk
=
(
struct
sctp6_sock
*
)
newsk
;
newsctp6sk
->
pinet6
=
&
newsctp6sk
->
inet6
;
newinet
=
inet_sk
(
newsk
);
newnp
=
inet6_sk
(
newsk
);
memcpy
(
newnp
,
np
,
sizeof
(
struct
ipv6_pinfo
));
ipv6_addr_copy
(
&
newnp
->
daddr
,
&
asoc
->
peer
.
primary_addr
.
v6
.
sin6_addr
);
newinet
->
sport
=
inet
->
sport
;
newinet
->
dport
=
asoc
->
peer
.
port
;
#ifdef INET_REFCNT_DEBUG
atomic_inc
(
&
inet6_sock_nr
);
atomic_inc
(
&
inet_sock_nr
);
#endif
if
(
0
!=
newsk
->
prot
->
init
(
newsk
))
{
inet_sock_release
(
newsk
);
newsk
=
NULL
;
}
out:
return
newsk
;
}
/* Initialize a PF_INET6 socket msg_name. */
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
{
...
...
@@ -597,7 +653,7 @@ static struct proto_ops inet6_seqpacket_ops = {
.
mmap
=
sock_no_mmap
,
};
static
struct
inet_protosw
sctpv6_protosw
=
{
static
struct
inet_protosw
sctpv6_
seqpacket_
protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
...
...
@@ -606,6 +662,15 @@ static struct inet_protosw sctpv6_protosw = {
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
static
struct
inet_protosw
sctpv6_stream_protosw
=
{
.
type
=
SOCK_STREAM
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
ops
=
&
inet6_seqpacket_ops
,
.
capability
=
-
1
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
static
struct
inet6_protocol
sctpv6_protocol
=
{
.
handler
=
sctp_rcv
,
...
...
@@ -641,6 +706,7 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
create_accept_sk
=
sctp_v6_create_accept_sk
,
.
af
=
&
sctp_ipv6_specific
,
};
...
...
@@ -651,8 +717,9 @@ int sctp_v6_init(void)
if
(
inet6_add_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
/* Add SCTPv6 to inetsw6 linked list. */
inet6_register_protosw
(
&
sctpv6_protosw
);
/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw
(
&
sctpv6_seqpacket_protosw
);
inet6_register_protosw
(
&
sctpv6_stream_protosw
);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
...
...
@@ -671,6 +738,7 @@ void sctp_v6_exit(void)
{
list_del
(
&
sctp_ipv6_specific
.
list
);
inet6_del_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
);
inet6_unregister_protosw
(
&
sctpv6_protosw
);
inet6_unregister_protosw
(
&
sctpv6_seqpacket_protosw
);
inet6_unregister_protosw
(
&
sctpv6_stream_protosw
);
unregister_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
}
net/sctp/protocol.c
View file @
7cd48512
...
...
@@ -480,6 +480,61 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
}
/* Create and initialize a new sk for the socket returned by accept(). */
struct
sock
*
sctp_v4_create_accept_sk
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
)
{
struct
sock
*
newsk
;
struct
inet_opt
*
inet
=
inet_sk
(
sk
);
struct
inet_opt
*
newinet
;
newsk
=
sk_alloc
(
PF_INET
,
GFP_KERNEL
,
sizeof
(
struct
sctp_sock
),
sk
->
slab
);
if
(
!
newsk
)
goto
out
;
sock_init_data
(
NULL
,
newsk
);
newsk
->
type
=
SOCK_STREAM
;
newsk
->
prot
=
sk
->
prot
;
newsk
->
no_check
=
sk
->
no_check
;
newsk
->
reuse
=
sk
->
reuse
;
newsk
->
destruct
=
inet_sock_destruct
;
newsk
->
zapped
=
0
;
newsk
->
family
=
PF_INET
;
newsk
->
protocol
=
IPPROTO_SCTP
;
newsk
->
backlog_rcv
=
sk
->
prot
->
backlog_rcv
;
newinet
=
inet_sk
(
newsk
);
newinet
->
sport
=
inet
->
sport
;
newinet
->
saddr
=
inet
->
saddr
;
newinet
->
rcv_saddr
=
inet
->
saddr
;
newinet
->
dport
=
asoc
->
peer
.
port
;
newinet
->
daddr
=
asoc
->
peer
.
primary_addr
.
v4
.
sin_addr
.
s_addr
;
newinet
->
pmtudisc
=
inet
->
pmtudisc
;
newinet
->
id
=
0
;
newinet
->
ttl
=
sysctl_ip_default_ttl
;
newinet
->
mc_loop
=
1
;
newinet
->
mc_ttl
=
1
;
newinet
->
mc_index
=
0
;
newinet
->
mc_list
=
NULL
;
#ifdef INET_REFCNT_DEBUG
atomic_inc
(
&
inet_sock_nr
);
#endif
if
(
0
!=
newsk
->
prot
->
init
(
newsk
))
{
inet_sock_release
(
newsk
);
newsk
=
NULL
;
}
out:
return
newsk
;
}
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
*/
...
...
@@ -664,6 +719,7 @@ static struct sctp_pf sctp_pf_inet = {
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
create_accept_sk
=
sctp_v4_create_accept_sk
,
.
af
=
&
sctp_ipv4_specific
,
};
...
...
@@ -694,7 +750,7 @@ struct proto_ops inet_seqpacket_ops = {
};
/* Registration with AF_INET family. */
st
ruct
inet_protosw
sctp
_protosw
=
{
st
atic
struct
inet_protosw
sctp_seqpacket
_protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
...
...
@@ -703,6 +759,15 @@ struct inet_protosw sctp_protosw = {
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
static
struct
inet_protosw
sctp_stream_protosw
=
{
.
type
=
SOCK_STREAM
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
ops
=
&
inet_seqpacket_ops
,
.
capability
=
-
1
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
};
/* Register with IP layer. */
static
struct
inet_protocol
sctp_protocol
=
{
...
...
@@ -809,8 +874,9 @@ __init int sctp_init(void)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
/* Add SCTP to inetsw linked list. */
inet_register_protosw
(
&
sctp_protosw
);
/* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw
(
&
sctp_seqpacket_protosw
);
inet_register_protosw
(
&
sctp_stream_protosw
);
/* Allocate and initialise sctp mibs. */
status
=
init_sctp_mibs
();
...
...
@@ -956,7 +1022,8 @@ __init int sctp_init(void)
cleanup_sctp_mibs
();
err_init_mibs:
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_unregister_protosw
(
&
sctp_protosw
);
inet_unregister_protosw
(
&
sctp_seqpacket_protosw
);
inet_unregister_protosw
(
&
sctp_stream_protosw
);
return
status
;
}
...
...
@@ -989,7 +1056,8 @@ __exit void sctp_exit(void)
cleanup_sctp_mibs
();
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
inet_unregister_protosw
(
&
sctp_protosw
);
inet_unregister_protosw
(
&
sctp_seqpacket_protosw
);
inet_unregister_protosw
(
&
sctp_stream_protosw
);
}
module_init
(
sctp_init
);
...
...
net/sctp/sm_sideeffect.c
View file @
7cd48512
...
...
@@ -1223,13 +1223,28 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_state_t
state
)
{
struct
sock
*
sk
=
asoc
->
base
.
sk
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
asoc
->
state
=
state
;
asoc
->
state_timestamp
=
jiffies
;
/* Wake up any process waiting for the association to
* get established.
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
||
(
SCTP_STATE_CLOSED
==
asoc
->
state
))
{
/* Wake up any processes waiting in the asoc's wait queue in
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
*/
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
(
waitqueue_active
(
&
asoc
->
wait
)))
if
(
waitqueue_active
(
&
asoc
->
wait
))
wake_up_interruptible
(
&
asoc
->
wait
);
/* Wake up any processes waiting in the sk's sleep queue of
* a tcp-style or udp-style peeled-off socket in
* sctp_wait_for_accept() or sctp_wait_for_packet().
* For a udp-style socket, the waiters are woken up by the
* notifications.
*/
if
(
sp
->
type
!=
SCTP_SOCKET_UDP
)
sk
->
state_change
(
sk
);
}
}
net/sctp/socket.c
View file @
7cd48512
...
...
@@ -88,11 +88,14 @@ static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
static
int
sctp_wait_for_connect
(
struct
sctp_association
*
,
long
*
timeo_p
);
static
int
sctp_wait_for_accept
(
struct
sock
*
sk
,
long
timeo
);
static
inline
int
sctp_verify_addr
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_bindx_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
static
void
sctp_sock_migrate
(
struct
sock
*
,
struct
sock
*
,
struct
sctp_association
*
,
sctp_socket_type_t
);
/* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored.
...
...
@@ -1151,6 +1154,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
"flags"
,
flags
,
"addr_len"
,
addr_len
);
sctp_lock_sock
(
sk
);
if
((
SCTP_SOCKET_TCP
==
sp
->
type
)
&&
(
SCTP_SS_ESTABLISHED
!=
sk
->
state
))
{
err
=
-
ENOTCONN
;
goto
out
;
}
skb
=
sctp_skb_recv_datagram
(
sk
,
flags
,
noblock
,
&
err
);
if
(
!
skb
)
goto
out
;
...
...
@@ -1563,6 +1573,8 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
if
(
err
)
goto
out_unlock
;
if
(
addr_len
>
sizeof
(
to
))
addr_len
=
sizeof
(
to
);
memcpy
(
&
to
,
uaddr
,
addr_len
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
...
...
@@ -1635,13 +1647,63 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
return
-
EOPNOTSUPP
;
/* STUB */
}
/* FIXME: Write comments. */
/* 4.1.4 accept() - TCP Style Syntax
*
* Applications use accept() call to remove an established SCTP
* association from the accept queue of the endpoint. A new socket
* descriptor will be returned from accept() to represent the newly
* formed association.
*/
SCTP_STATIC
struct
sock
*
sctp_accept
(
struct
sock
*
sk
,
int
flags
,
int
*
err
)
{
int
error
=
-
EOPNOTSUPP
;
struct
sctp_opt
*
sp
;
struct
sctp_endpoint
*
ep
;
struct
sock
*
newsk
=
NULL
;
struct
sctp_association
*
assoc
;
long
timeo
;
int
error
=
0
;
sctp_lock_sock
(
sk
);
sp
=
sctp_sk
(
sk
);
ep
=
sp
->
ep
;
if
(
SCTP_SOCKET_TCP
!=
sp
->
type
)
{
error
=
-
EOPNOTSUPP
;
goto
out
;
}
if
(
SCTP_SS_LISTENING
!=
sk
->
state
)
{
error
=
-
EINVAL
;
goto
out
;
}
timeo
=
sock_rcvtimeo
(
sk
,
sk
->
socket
->
file
->
f_flags
&
O_NONBLOCK
);
error
=
sctp_wait_for_accept
(
sk
,
timeo
);
if
(
error
)
goto
out
;
/* We treat the list of associations on the endpoint as the accept
* queue and pick the first association on the list.
*/
assoc
=
list_entry
(
ep
->
asocs
.
next
,
struct
sctp_association
,
asocs
);
newsk
=
sp
->
pf
->
create_accept_sk
(
sk
,
assoc
);
if
(
!
newsk
)
{
error
=
-
ENOMEM
;
goto
out
;
}
/* Populate the fields of the newsk from the oldsk and migrate the
* assoc to the newsk.
*/
sctp_sock_migrate
(
sk
,
newsk
,
assoc
,
SCTP_SOCKET_TCP
);
out:
sctp_release_sock
(
sk
);
*
err
=
error
;
return
NULL
;
return
newsk
;
}
/* FIXME: Write Comments. */
...
...
@@ -1667,7 +1729,16 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp
=
sctp_sk
(
sk
);
/* Initialize the SCTP per socket area. */
switch
(
sk
->
type
)
{
case
SOCK_SEQPACKET
:
sp
->
type
=
SCTP_SOCKET_UDP
;
break
;
case
SOCK_STREAM
:
sp
->
type
=
SCTP_SOCKET_TCP
;
break
;
default:
return
-
ESOCKTNOSUPPORT
;
}
/* FIXME: The next draft (04) of the SCTP Sockets Extensions
* should include a socket option for manipulating these
...
...
@@ -1878,11 +1949,6 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
sctp_endpoint_t
*
newep
;
struct
sctp_opt
*
oldsp
=
sctp_sk
(
oldsk
);
struct
sctp_opt
*
newsp
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sctp_ulpevent
*
event
;
int
err
=
0
;
/* An association cannot be branched off from an already peeled-off
...
...
@@ -1892,81 +1958,17 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
return
-
EOPNOTSUPP
;
/* Create a new socket. */
err
=
sock_create
(
PF_INET
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
&
tmpsock
);
err
=
sock_create
(
oldsk
->
family
,
SOCK_SEQPACKET
,
IPPROTO_SCTP
,
&
tmpsock
);
if
(
err
<
0
)
return
err
;
newsk
=
tmpsock
->
sk
;
newsp
=
sctp_sk
(
newsk
);
newep
=
newsp
->
ep
;
/* Migrate socket buffer sizes and all the socket level options to the
* new socket.
*/
newsk
->
sndbuf
=
oldsk
->
sndbuf
;
newsk
->
rcvbuf
=
oldsk
->
rcvbuf
;
*
newsp
=
*
oldsp
;
/* Restore the ep value that was overwritten with the above structure
* copy.
*/
newsp
->
ep
=
newep
;
/* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
/* Clean up an messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
/* Populate the fields of the newsk from the oldsk and migrate the
* assoc to the newsk.
*/
skb_queue_head_init
(
&
newsp
->
pd_lobby
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
* original socket.
*/
newsp
->
type
=
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
;
/* Migrate the association to the new socket. */
sctp_assoc_migrate
(
assoc
,
newsk
);
sctp_sock_migrate
(
oldsk
,
newsk
,
assoc
,
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
);
*
newsock
=
tmpsock
;
...
...
@@ -2614,6 +2616,42 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
return
-
EINVAL
;
if
(
sk
->
state
==
SCTP_SS_LISTENING
)
return
0
;
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
* picks an ephemeral port and will choose an address set equivalent
* to binding with a wildcard address.
*
* This is not currently spelled out in the SCTP sockets
* extensions draft, but follows the practice as seen in TCP
* sockets.
*/
if
(
!
ep
->
base
.
bind_addr
.
port
)
{
if
(
sctp_autobind
(
sk
))
return
-
EAGAIN
;
}
sk
->
state
=
SCTP_SS_LISTENING
;
sctp_hash_endpoint
(
ep
);
return
0
;
}
/*
* 4.1.3 listen() - TCP Style Syntax
*
* Applications uses listen() to ready the SCTP endpoint for accepting
* inbound associations.
*/
SCTP_STATIC
int
sctp_stream_listen
(
struct
sock
*
sk
,
int
backlog
)
{
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
sctp_endpoint_t
*
ep
=
sp
->
ep
;
if
(
sk
->
state
==
SCTP_SS_LISTENING
)
return
0
;
/*
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
...
...
@@ -2629,6 +2667,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
return
-
EAGAIN
;
}
sk
->
state
=
SCTP_SS_LISTENING
;
sk
->
max_ack_backlog
=
backlog
;
sctp_hash_endpoint
(
ep
);
return
0
;
}
...
...
@@ -2652,8 +2691,8 @@ int sctp_inet_listen(struct socket *sock, int backlog)
break
;
case
SOCK_STREAM
:
/* FIXME for TCP-style sockets. */
err
=
-
EOPNOTSUPP
;
err
=
sctp_stream_listen
(
sk
,
backlog
);
break
;
default:
goto
out
;
...
...
@@ -3284,7 +3323,7 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
return
err
;
do_error:
err
=
-
ECONN
ABORT
ED
;
err
=
-
ECONN
REFUS
ED
;
goto
out
;
do_interrupted:
...
...
@@ -3296,6 +3335,131 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
goto
out
;
}
static
int
sctp_wait_for_accept
(
struct
sock
*
sk
,
long
timeo
)
{
struct
sctp_endpoint
*
ep
;
int
err
=
0
;
DECLARE_WAITQUEUE
(
wait
,
current
);
ep
=
sctp_sk
(
sk
)
->
ep
;
add_wait_queue_exclusive
(
sk
->
sleep
,
&
wait
);
for
(;;)
{
__set_current_state
(
TASK_INTERRUPTIBLE
);
if
(
list_empty
(
&
ep
->
asocs
))
{
sctp_release_sock
(
sk
);
timeo
=
schedule_timeout
(
timeo
);
sctp_lock_sock
(
sk
);
}
err
=
-
EINVAL
;
if
(
sk
->
state
!=
SCTP_SS_LISTENING
)
break
;
err
=
0
;
if
(
!
list_empty
(
&
ep
->
asocs
))
break
;
err
=
sock_intr_errno
(
timeo
);
if
(
signal_pending
(
current
))
break
;
err
=
-
EAGAIN
;
if
(
!
timeo
)
break
;
}
remove_wait_queue
(
sk
->
sleep
,
&
wait
);
__set_current_state
(
TASK_RUNNING
);
return
err
;
}
/* Populate the fields of the newsk from the oldsk and migrate the assoc
* and its messages to the newsk.
*/
void
sctp_sock_migrate
(
struct
sock
*
oldsk
,
struct
sock
*
newsk
,
struct
sctp_association
*
assoc
,
sctp_socket_type_t
type
)
{
struct
sctp_opt
*
oldsp
=
sctp_sk
(
oldsk
);
struct
sctp_opt
*
newsp
=
sctp_sk
(
newsk
);
sctp_endpoint_t
*
newep
=
newsp
->
ep
;
struct
sk_buff
*
skb
,
*
tmp
;
struct
sctp_ulpevent
*
event
;
/* Migrate socket buffer sizes and all the socket level options to the
* new socket.
*/
newsk
->
sndbuf
=
oldsk
->
sndbuf
;
newsk
->
rcvbuf
=
oldsk
->
rcvbuf
;
*
newsp
=
*
oldsp
;
/* Restore the ep value that was overwritten with the above structure
* copy.
*/
newsp
->
ep
=
newep
;
/* Move any messages in the old socket's receive queue that are for the
* peeled off association to the new socket's receive queue.
*/
sctp_skb_for_each
(
skb
,
&
oldsk
->
receive_queue
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
&
newsk
->
receive_queue
,
skb
);
}
}
/* Clean up any messages pending delivery due to partial
* delivery. Three cases:
* 1) No partial deliver; no work.
* 2) Peeling off partial delivery; keep pd_lobby in new pd_lobby.
* 3) Peeling off non-partial delivery; move pd_lobby to recieve_queue.
*/
skb_queue_head_init
(
&
newsp
->
pd_lobby
);
sctp_sk
(
newsk
)
->
pd_mode
=
assoc
->
ulpq
.
pd_mode
;;
if
(
sctp_sk
(
oldsk
)
->
pd_mode
)
{
struct
sk_buff_head
*
queue
;
/* Decide which queue to move pd_lobby skbs to. */
if
(
assoc
->
ulpq
.
pd_mode
)
{
queue
=
&
newsp
->
pd_lobby
;
}
else
queue
=
&
newsk
->
receive_queue
;
/* Walk through the pd_lobby, looking for skbs that
* need moved to the new socket.
*/
sctp_skb_for_each
(
skb
,
&
oldsp
->
pd_lobby
,
tmp
)
{
event
=
sctp_skb2event
(
skb
);
if
(
event
->
asoc
==
assoc
)
{
__skb_unlink
(
skb
,
skb
->
list
);
__skb_queue_tail
(
queue
,
skb
);
}
}
/* Clear up any skbs waiting for the partial
* delivery to finish.
*/
if
(
assoc
->
ulpq
.
pd_mode
)
sctp_clear_pd
(
oldsk
);
}
/* Set the type of socket to indicate that it is peeled off from the
* original UDP-style socket or created with the accept() call on a
* TCP-style socket..
*/
newsp
->
type
=
type
;
/* Migrate the association to the new socket. */
sctp_assoc_migrate
(
assoc
,
newsk
);
newsk
->
state
=
SCTP_SS_ESTABLISHED
;
}
/* This proto struct describes the ULP interface for SCTP. */
struct
proto
sctp_prot
=
{
.
name
=
"SCTP"
,
...
...
net/sctp/ulpqueue.c
View file @
7cd48512
...
...
@@ -230,7 +230,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
sctp_ulpq_clear_pd
(
ulpq
);
if
(
queue
==
&
sk
->
receive_queue
)
wake_up_interruptible
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
return
1
;
out_free:
...
...
@@ -787,5 +787,5 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
/* If there is data waiting, send it up the socket now. */
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
wake_up_interruptible
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
}
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment