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
bf953999
Commit
bf953999
authored
Mar 02, 2003
by
Sridhar Samudrala
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
[SCTP] accept() support for TCP-style SCTP sockets.
parent
088e723f
Changes
7
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
419 additions
and
101 deletions
+419
-101
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
-84
net/sctp/ulpqueue.c
net/sctp/ulpqueue.c
+2
-2
No files found.
include/net/sctp/structs.h
View file @
bf953999
...
@@ -262,6 +262,8 @@ struct sctp_pf {
...
@@ -262,6 +262,8 @@ struct sctp_pf {
struct
sctp_opt
*
);
struct
sctp_opt
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
bind_verify
)
(
struct
sctp_opt
*
,
union
sctp_addr
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
int
(
*
supported_addrs
)(
const
struct
sctp_opt
*
,
__u16
*
);
struct
sock
*
(
*
create_accept_sk
)
(
struct
sock
*
sk
,
struct
sctp_association
*
asoc
);
struct
sctp_af
*
af
;
struct
sctp_af
*
af
;
};
};
...
...
net/sctp/endpointola.c
View file @
bf953999
...
@@ -195,6 +195,8 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
...
@@ -195,6 +195,8 @@ void sctp_endpoint_destroy(sctp_endpoint_t *ep)
{
{
SCTP_ASSERT
(
ep
->
base
.
dead
,
"Endpoint is not dead"
,
return
);
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! */
/* Unlink this endpoint, so we can't find it again! */
sctp_unhash_endpoint
(
ep
);
sctp_unhash_endpoint
(
ep
);
...
...
net/sctp/ipv6.c
View file @
bf953999
...
@@ -432,6 +432,62 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
...
@@ -432,6 +432,62 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
return
retval
;
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. */
/* Initialize a PF_INET6 socket msg_name. */
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
static
void
sctp_inet6_msgname
(
char
*
msgname
,
int
*
addr_len
)
{
{
...
@@ -597,7 +653,7 @@ static struct proto_ops inet6_seqpacket_ops = {
...
@@ -597,7 +653,7 @@ static struct proto_ops inet6_seqpacket_ops = {
.
mmap
=
sock_no_mmap
,
.
mmap
=
sock_no_mmap
,
};
};
static
struct
inet_protosw
sctpv6_protosw
=
{
static
struct
inet_protosw
sctpv6_
seqpacket_
protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
prot
=
&
sctp_prot
,
...
@@ -606,6 +662,15 @@ static struct inet_protosw sctpv6_protosw = {
...
@@ -606,6 +662,15 @@ static struct inet_protosw sctpv6_protosw = {
.
no_check
=
0
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
.
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
=
{
static
struct
inet6_protocol
sctpv6_protocol
=
{
.
handler
=
sctp_rcv
,
.
handler
=
sctp_rcv
,
...
@@ -641,6 +706,7 @@ static struct sctp_pf sctp_pf_inet6_specific = {
...
@@ -641,6 +706,7 @@ static struct sctp_pf sctp_pf_inet6_specific = {
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
cmp_addr
=
sctp_inet6_cmp_addr
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
bind_verify
=
sctp_inet6_bind_verify
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
supported_addrs
=
sctp_inet6_supported_addrs
,
.
create_accept_sk
=
sctp_v6_create_accept_sk
,
.
af
=
&
sctp_ipv6_specific
,
.
af
=
&
sctp_ipv6_specific
,
};
};
...
@@ -651,8 +717,9 @@ int sctp_v6_init(void)
...
@@ -651,8 +717,9 @@ int sctp_v6_init(void)
if
(
inet6_add_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
)
<
0
)
if
(
inet6_add_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
return
-
EAGAIN
;
/* Add SCTPv6 to inetsw6 linked list. */
/* Add SCTPv6(UDP and TCP style) to inetsw6 linked list. */
inet6_register_protosw
(
&
sctpv6_protosw
);
inet6_register_protosw
(
&
sctpv6_seqpacket_protosw
);
inet6_register_protosw
(
&
sctpv6_stream_protosw
);
/* Register the SCTP specfic PF_INET6 functions. */
/* Register the SCTP specfic PF_INET6 functions. */
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
sctp_register_pf
(
&
sctp_pf_inet6_specific
,
PF_INET6
);
...
@@ -671,6 +738,7 @@ void sctp_v6_exit(void)
...
@@ -671,6 +738,7 @@ void sctp_v6_exit(void)
{
{
list_del
(
&
sctp_ipv6_specific
.
list
);
list_del
(
&
sctp_ipv6_specific
.
list
);
inet6_del_protocol
(
&
sctpv6_protocol
,
IPPROTO_SCTP
);
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
);
unregister_inet6addr_notifier
(
&
sctp_inetaddr_notifier
);
}
}
net/sctp/protocol.c
View file @
bf953999
...
@@ -480,6 +480,61 @@ void sctp_v4_get_saddr(sctp_association_t *asoc,
...
@@ -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.
/* Event handler for inet address addition/deletion events.
* Basically, whenever there is an event, we re-build our local address list.
* Basically, whenever there is an event, we re-build our local address list.
*/
*/
...
@@ -664,6 +719,7 @@ static struct sctp_pf sctp_pf_inet = {
...
@@ -664,6 +719,7 @@ static struct sctp_pf sctp_pf_inet = {
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
cmp_addr
=
sctp_inet_cmp_addr
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
bind_verify
=
sctp_inet_bind_verify
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
supported_addrs
=
sctp_inet_supported_addrs
,
.
create_accept_sk
=
sctp_v4_create_accept_sk
,
.
af
=
&
sctp_ipv4_specific
,
.
af
=
&
sctp_ipv4_specific
,
};
};
...
@@ -694,7 +750,7 @@ struct proto_ops inet_seqpacket_ops = {
...
@@ -694,7 +750,7 @@ struct proto_ops inet_seqpacket_ops = {
};
};
/* Registration with AF_INET family. */
/* Registration with AF_INET family. */
st
ruct
inet_protosw
sctp
_protosw
=
{
st
atic
struct
inet_protosw
sctp_seqpacket
_protosw
=
{
.
type
=
SOCK_SEQPACKET
,
.
type
=
SOCK_SEQPACKET
,
.
protocol
=
IPPROTO_SCTP
,
.
protocol
=
IPPROTO_SCTP
,
.
prot
=
&
sctp_prot
,
.
prot
=
&
sctp_prot
,
...
@@ -703,6 +759,15 @@ struct inet_protosw sctp_protosw = {
...
@@ -703,6 +759,15 @@ struct inet_protosw sctp_protosw = {
.
no_check
=
0
,
.
no_check
=
0
,
.
flags
=
SCTP_PROTOSW_FLAG
.
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. */
/* Register with IP layer. */
static
struct
inet_protocol
sctp_protocol
=
{
static
struct
inet_protocol
sctp_protocol
=
{
...
@@ -809,8 +874,9 @@ __init int sctp_init(void)
...
@@ -809,8 +874,9 @@ __init int sctp_init(void)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
if
(
inet_add_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
)
<
0
)
return
-
EAGAIN
;
return
-
EAGAIN
;
/* Add SCTP to inetsw linked list. */
/* Add SCTP(TCP and UDP style) to inetsw linked list. */
inet_register_protosw
(
&
sctp_protosw
);
inet_register_protosw
(
&
sctp_seqpacket_protosw
);
inet_register_protosw
(
&
sctp_stream_protosw
);
/* Allocate and initialise sctp mibs. */
/* Allocate and initialise sctp mibs. */
status
=
init_sctp_mibs
();
status
=
init_sctp_mibs
();
...
@@ -956,7 +1022,8 @@ __init int sctp_init(void)
...
@@ -956,7 +1022,8 @@ __init int sctp_init(void)
cleanup_sctp_mibs
();
cleanup_sctp_mibs
();
err_init_mibs:
err_init_mibs:
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
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
;
return
status
;
}
}
...
@@ -989,7 +1056,8 @@ __exit void sctp_exit(void)
...
@@ -989,7 +1056,8 @@ __exit void sctp_exit(void)
cleanup_sctp_mibs
();
cleanup_sctp_mibs
();
inet_del_protocol
(
&
sctp_protocol
,
IPPROTO_SCTP
);
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
);
module_init
(
sctp_init
);
...
...
net/sctp/sm_sideeffect.c
View file @
bf953999
...
@@ -1223,13 +1223,28 @@ static void sctp_cmd_setup_t2(sctp_cmd_seq_t *cmds, sctp_association_t *asoc,
...
@@ -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
,
static
void
sctp_cmd_new_state
(
sctp_cmd_seq_t
*
cmds
,
sctp_association_t
*
asoc
,
sctp_state_t
state
)
sctp_state_t
state
)
{
{
struct
sock
*
sk
=
asoc
->
base
.
sk
;
struct
sctp_opt
*
sp
=
sctp_sk
(
sk
);
asoc
->
state
=
state
;
asoc
->
state
=
state
;
asoc
->
state_timestamp
=
jiffies
;
asoc
->
state_timestamp
=
jiffies
;
/* Wake up any process waiting for the association to
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
||
* get established.
(
SCTP_STATE_CLOSED
==
asoc
->
state
))
{
*/
/* Wake up any processes waiting in the asoc's wait queue in
if
((
SCTP_STATE_ESTABLISHED
==
asoc
->
state
)
&&
* sctp_wait_for_connect() or sctp_wait_for_sndbuf().
(
waitqueue_active
(
&
asoc
->
wait
)))
*/
wake_up_interruptible
(
&
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 @
bf953999
...
@@ -88,11 +88,14 @@ static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
...
@@ -88,11 +88,14 @@ static int sctp_wait_for_sndbuf(struct sctp_association *, long *timeo_p,
int
msg_len
);
int
msg_len
);
static
int
sctp_wait_for_packet
(
struct
sock
*
sk
,
int
*
err
,
long
*
timeo_p
);
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_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
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_add
(
struct
sock
*
,
struct
sockaddr_storage
*
,
int
);
static
int
sctp_bindx_rem
(
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_do_bind
(
struct
sock
*
,
union
sctp_addr
*
,
int
);
static
int
sctp_autobind
(
struct
sock
*
sk
);
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
/* Look up the association by its id. If this is not a UDP-style
* socket, the ID field is always ignored.
* socket, the ID field is always ignored.
...
@@ -1151,6 +1154,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
...
@@ -1151,6 +1154,13 @@ SCTP_STATIC int sctp_recvmsg(struct kiocb *iocb, struct sock *sk, struct msghdr
"flags"
,
flags
,
"addr_len"
,
addr_len
);
"flags"
,
flags
,
"addr_len"
,
addr_len
);
sctp_lock_sock
(
sk
);
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
);
skb
=
sctp_skb_recv_datagram
(
sk
,
flags
,
noblock
,
&
err
);
if
(
!
skb
)
if
(
!
skb
)
goto
out
;
goto
out
;
...
@@ -1563,6 +1573,8 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
...
@@ -1563,6 +1573,8 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr,
if
(
err
)
if
(
err
)
goto
out_unlock
;
goto
out_unlock
;
if
(
addr_len
>
sizeof
(
to
))
addr_len
=
sizeof
(
to
);
memcpy
(
&
to
,
uaddr
,
addr_len
);
memcpy
(
&
to
,
uaddr
,
addr_len
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
to
.
v4
.
sin_port
=
ntohs
(
to
.
v4
.
sin_port
);
...
@@ -1635,13 +1647,63 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
...
@@ -1635,13 +1647,63 @@ SCTP_STATIC int sctp_disconnect(struct sock *sk, int flags)
return
-
EOPNOTSUPP
;
/* STUB */
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
)
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
);
*
err
=
error
;
sp
=
sctp_sk
(
sk
);
return
NULL
;
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
newsk
;
}
}
/* FIXME: Write Comments. */
/* FIXME: Write Comments. */
...
@@ -1667,7 +1729,16 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
...
@@ -1667,7 +1729,16 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
sp
=
sctp_sk
(
sk
);
sp
=
sctp_sk
(
sk
);
/* Initialize the SCTP per socket area. */
/* Initialize the SCTP per socket area. */
sp
->
type
=
SCTP_SOCKET_UDP
;
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
/* FIXME: The next draft (04) of the SCTP Sockets Extensions
* should include a socket option for manipulating these
* should include a socket option for manipulating these
...
@@ -1775,7 +1846,6 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
...
@@ -1775,7 +1846,6 @@ static int sctp_getsockopt_sctp_status(struct sock *sk, int len, char *optval,
int
*
optlen
)
int
*
optlen
)
{
{
struct
sctp_status
status
;
struct
sctp_status
status
;
sctp_endpoint_t
*
ep
;
sctp_association_t
*
assoc
=
NULL
;
sctp_association_t
*
assoc
=
NULL
;
struct
sctp_transport
*
transport
;
struct
sctp_transport
*
transport
;
sctp_assoc_t
associd
;
sctp_assoc_t
associd
;
...
@@ -1879,11 +1949,6 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1879,11 +1949,6 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
struct
sock
*
oldsk
=
assoc
->
base
.
sk
;
struct
sock
*
newsk
;
struct
sock
*
newsk
;
struct
socket
*
tmpsock
;
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
;
int
err
=
0
;
/* An association cannot be branched off from an already peeled-off
/* An association cannot be branched off from an already peeled-off
...
@@ -1893,81 +1958,17 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
...
@@ -1893,81 +1958,17 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso
return
-
EOPNOTSUPP
;
return
-
EOPNOTSUPP
;
/* Create a new socket. */
/* 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
)
if
(
err
<
0
)
return
err
;
return
err
;
newsk
=
tmpsock
->
sk
;
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.
*/
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. */
/* Populate the fields of the newsk from the oldsk and migrate the
if
(
assoc
->
ulpq
.
pd_mode
)
{
* assoc to the newsk.
queue
=
&
newsp
->
pd_lobby
;
*/
}
else
sctp_sock_migrate
(
oldsk
,
newsk
,
assoc
,
SCTP_SOCKET_UDP_HIGH_BANDWIDTH
);
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
);
*
newsock
=
tmpsock
;
*
newsock
=
tmpsock
;
...
@@ -2615,6 +2616,42 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
...
@@ -2615,6 +2616,42 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
if
(
SCTP_SOCKET_UDP
!=
sp
->
type
)
return
-
EINVAL
;
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()
* If a bind() or sctp_bindx() is not called prior to a listen()
* call that allows new associations to be accepted, the system
* call that allows new associations to be accepted, the system
...
@@ -2630,6 +2667,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
...
@@ -2630,6 +2667,7 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
return
-
EAGAIN
;
return
-
EAGAIN
;
}
}
sk
->
state
=
SCTP_SS_LISTENING
;
sk
->
state
=
SCTP_SS_LISTENING
;
sk
->
max_ack_backlog
=
backlog
;
sctp_hash_endpoint
(
ep
);
sctp_hash_endpoint
(
ep
);
return
0
;
return
0
;
}
}
...
@@ -2653,8 +2691,8 @@ int sctp_inet_listen(struct socket *sock, int backlog)
...
@@ -2653,8 +2691,8 @@ int sctp_inet_listen(struct socket *sock, int backlog)
break
;
break
;
case
SOCK_STREAM
:
case
SOCK_STREAM
:
/* FIXME for TCP-style sockets. */
err
=
sctp_stream_listen
(
sk
,
backlog
);
err
=
-
EOPNOTSUPP
;
break
;
default:
default:
goto
out
;
goto
out
;
...
@@ -3285,7 +3323,7 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
...
@@ -3285,7 +3323,7 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
return
err
;
return
err
;
do_error:
do_error:
err
=
-
ECONN
ABORT
ED
;
err
=
-
ECONN
REFUS
ED
;
goto
out
;
goto
out
;
do_interrupted:
do_interrupted:
...
@@ -3297,6 +3335,131 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
...
@@ -3297,6 +3335,131 @@ static int sctp_wait_for_connect(sctp_association_t *asoc, long *timeo_p)
goto
out
;
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. */
/* This proto struct describes the ULP interface for SCTP. */
struct
proto
sctp_prot
=
{
struct
proto
sctp_prot
=
{
.
name
=
"SCTP"
,
.
name
=
"SCTP"
,
...
...
net/sctp/ulpqueue.c
View file @
bf953999
...
@@ -230,7 +230,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
...
@@ -230,7 +230,7 @@ int sctp_ulpq_tail_event(struct sctp_ulpq *ulpq, struct sctp_ulpevent *event)
sctp_ulpq_clear_pd
(
ulpq
);
sctp_ulpq_clear_pd
(
ulpq
);
if
(
queue
==
&
sk
->
receive_queue
)
if
(
queue
==
&
sk
->
receive_queue
)
wake_up_interruptible
(
sk
->
sleep
);
sk
->
data_ready
(
sk
,
0
);
return
1
;
return
1
;
out_free:
out_free:
...
@@ -790,5 +790,5 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
...
@@ -790,5 +790,5 @@ void sctp_ulpq_abort_pd(struct sctp_ulpq *ulpq, int priority)
/* If there is data waiting, send it up the socket now. */
/* If there is data waiting, send it up the socket now. */
if
(
sctp_ulpq_clear_pd
(
ulpq
)
||
ev
)
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