Commit bf953999 authored by Sridhar Samudrala's avatar Sridhar Samudrala

[SCTP] accept() support for TCP-style SCTP sockets.

parent 088e723f
...@@ -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;
}; };
......
...@@ -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);
......
...@@ -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);
} }
...@@ -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. */
struct inet_protosw sctp_protosw = { static 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);
......
...@@ -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);
}
} }
This diff is collapsed.
...@@ -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);
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment