From 1402a73c6615ff2d0419401764086bb8214c0540 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Mon, 24 Feb 2003 03:56:02 -0600 Subject: [SCTP] Add SCTP_SET_PEER_PRIMARY get/setsockopt. Also, rename all sctp_protocol_t -> struct sctp_protocol. Non-UDP-style SCTP sockets should ignore associd fields, so added this function into sctp_id2assoc() in anticipation of Sridhar's TCP-style work. --- include/net/sctp/sctp.h | 34 ++++++++++------------------------ include/net/sctp/structs.h | 25 ++++++++++++------------- 2 files changed, 22 insertions(+), 37 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index b2e19ebde563..bf8aaa165bd9 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -121,9 +121,10 @@ /* * sctp_protocol.c */ -extern sctp_protocol_t sctp_proto; +extern struct sctp_protocol sctp_proto; extern struct sock *sctp_get_ctl_sock(void); -extern int sctp_copy_local_addr_list(sctp_protocol_t *, sctp_bind_addr_t *, +extern int sctp_copy_local_addr_list(struct sctp_protocol *, + struct sctp_bind_addr *, sctp_scope_t, int priority, int flags); extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family); extern int sctp_register_pf(struct sctp_pf *, sa_family_t); @@ -348,25 +349,10 @@ static inline sctp_assoc_t sctp_assoc2id(const sctp_association_t *asoc) return (sctp_assoc_t) asoc; } + /* Look up the association by its id. */ -static inline sctp_association_t *sctp_id2assoc(const struct sock *sk, sctp_assoc_t id) -{ - sctp_association_t *asoc = NULL; - - /* First, verify that this is a kernel address. */ - if (sctp_is_valid_kaddr((unsigned long) id)) { - sctp_association_t *temp = (sctp_association_t *) id; - - /* Verify that this _is_ an sctp_association_t - * data structure and if so, that the socket matches. - */ - if ((SCTP_ASSOC_EYECATCHER == temp->eyecatcher) && - (temp->base.sk == sk)) - asoc = temp; - } +sctp_association_t *sctp_id2assoc(struct sock *sk, sctp_assoc_t id); - return asoc; -} /* A macro to walk a list of skbs. */ #define sctp_skb_for_each(pos, head, tmp) \ @@ -494,7 +480,7 @@ extern void sctp_put_port(struct sock *sk); /* Static inline functions. */ /* Return the SCTP protocol structure. */ -static inline sctp_protocol_t *sctp_get_protocol(void) +static inline struct sctp_protocol *sctp_get_protocol(void) { return &sctp_proto; } @@ -523,21 +509,21 @@ static inline int ipver2af(__u8 ipver) /* This is the hash function for the SCTP port hash table. */ static inline int sctp_phashfn(__u16 lport) { - sctp_protocol_t *sctp_proto = sctp_get_protocol(); + struct sctp_protocol *sctp_proto = sctp_get_protocol(); return (lport & (sctp_proto->port_hashsize - 1)); } /* This is the hash function for the endpoint hash table. */ static inline int sctp_ep_hashfn(__u16 lport) { - sctp_protocol_t *sctp_proto = sctp_get_protocol(); + struct sctp_protocol *sctp_proto = sctp_get_protocol(); return (lport & (sctp_proto->ep_hashsize - 1)); } /* This is the hash function for the association hash table. */ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) { - sctp_protocol_t *sctp_proto = sctp_get_protocol(); + struct sctp_protocol *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= h>>8; return (h & (sctp_proto->assoc_hashsize - 1)); @@ -549,7 +535,7 @@ static inline int sctp_assoc_hashfn(__u16 lport, __u16 rport) */ static inline int sctp_vtag_hashfn(__u16 lport, __u16 rport, __u32 vtag) { - sctp_protocol_t *sctp_proto = sctp_get_protocol(); + struct sctp_protocol *sctp_proto = sctp_get_protocol(); int h = (lport << 16) + rport; h ^= vtag; return (h & (sctp_proto->assoc_hashsize-1)); diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index d136122af892..2cc13c137a18 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -118,7 +118,6 @@ struct sctp_opt; struct sctp_endpoint_common; struct sctp_ssnmap; -typedef struct sctp_protocol sctp_protocol_t; typedef struct sctp_endpoint sctp_endpoint_t; typedef struct sctp_association sctp_association_t; typedef struct sctp_packet sctp_packet_t; @@ -254,7 +253,7 @@ struct sctp_af { void (*get_saddr) (struct sctp_association *asoc, struct dst_entry *dst, union sctp_addr *daddr, - union sctp_addr *saddr); + union sctp_addr *saddr); void (*copy_addrlist) (struct list_head *, struct net_device *); void (*dst_saddr) (union sctp_addr *saddr, @@ -1130,8 +1129,9 @@ static inline sctp_endpoint_t *sctp_ep(sctp_endpoint_common_t *base) } /* These are function signatures for manipulating endpoints. */ -sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *, struct sock *, int); -sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *, sctp_protocol_t *, +sctp_endpoint_t *sctp_endpoint_new(struct sctp_protocol *, struct sock *, int); +sctp_endpoint_t *sctp_endpoint_init(struct sctp_endpoint *, + struct sctp_protocol *, struct sock *, int priority); void sctp_endpoint_free(sctp_endpoint_t *); void sctp_endpoint_put(sctp_endpoint_t *); @@ -1143,7 +1143,6 @@ sctp_association_t *sctp_endpoint_lookup_assoc(const sctp_endpoint_t *ep, int sctp_endpoint_is_peeled_off(sctp_endpoint_t *, const union sctp_addr *); sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *, const union sctp_addr *); - int sctp_has_association(const union sctp_addr *laddr, const union sctp_addr *paddr); @@ -1619,7 +1618,7 @@ struct sctp_transport *sctp_assoc_lookup_paddr(const sctp_association_t *, struct sctp_transport *sctp_assoc_add_peer(sctp_association_t *, const union sctp_addr *address, const int priority); -void sctp_assoc_control_transport(sctp_association_t *, +void sctp_assoc_control_transport(struct sctp_association *, struct sctp_transport *, sctp_transport_cmd_t, sctp_sn_error_t); struct sctp_transport *sctp_assoc_lookup_tsn(sctp_association_t *, __u32); @@ -1629,14 +1628,14 @@ struct sctp_transport *sctp_assoc_is_match(sctp_association_t *, void sctp_assoc_migrate(sctp_association_t *, struct sock *); void sctp_assoc_update(sctp_association_t *dst, sctp_association_t *src); -__u32 __sctp_association_get_next_tsn(sctp_association_t *); -__u32 __sctp_association_get_tsn_block(sctp_association_t *, int); -__u16 __sctp_association_get_next_ssn(sctp_association_t *, __u16 sid); - -void sctp_assoc_sync_pmtu(sctp_association_t *); -void sctp_assoc_rwnd_increase(sctp_association_t *, int); -void sctp_assoc_rwnd_decrease(sctp_association_t *, int); +__u32 sctp_association_get_next_tsn(struct sctp_association *); +__u32 sctp_association_get_tsn_block(struct sctp_association *, int); +void sctp_assoc_sync_pmtu(struct sctp_association *); +void sctp_assoc_rwnd_increase(struct sctp_association *, int); +void sctp_assoc_rwnd_decrease(struct sctp_association *, int); +void sctp_assoc_set_primary(struct sctp_association *, + struct sctp_transport *); int sctp_assoc_set_bind_addr_from_ep(sctp_association_t *, int); int sctp_assoc_set_bind_addr_from_cookie(sctp_association_t *, sctp_cookie_t *, int); -- cgit v1.2.3 From 44310455879437f96eade4ba5721408f38fcd711 Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Wed, 26 Feb 2003 02:07:01 -0600 Subject: [SCTP] Supported address types should be based on pf_family. PF_INET sockets are advertising v6 address support. Make this choice a pf_family function. --- include/net/sctp/sctp.h | 3 ++- include/net/sctp/structs.h | 3 +-- net/sctp/ipv6.c | 15 +++++++++++++++ net/sctp/protocol.c | 11 +++++++++++ net/sctp/sm_make_chunk.c | 48 ++++++++++++++++++++-------------------------- 5 files changed, 50 insertions(+), 30 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index bf8aaa165bd9..1898cb15c70f 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -323,7 +323,8 @@ static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) return ipv6_addr_type((struct in6_addr*) addr); } -#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 2 * sizeof(__u16)) +/* Size of Supported Address Parameter for 'x' address types. */ +#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16)) /* Note: These V6 macros are obsolescent. */ /* Use this macro to enclose code fragments which are V6-dependent. */ diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 2cc13c137a18..f027a8c90aa8 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -293,6 +293,7 @@ struct sctp_pf { const union sctp_addr *, struct sctp_opt *); int (*bind_verify) (struct sctp_opt *, union sctp_addr *); + int (*supported_addrs)(const struct sctp_opt *, __u16 *); struct sctp_af *af; }; @@ -397,8 +398,6 @@ typedef struct sctp_signed_cookie { sctp_cookie_t c; } sctp_signed_cookie_t; - - /* This is another convenience type to allocate memory for address * params for the maximum size and pass such structures around * internally. diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index db2c10135190..72467df4eb5c 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -565,6 +565,20 @@ static int sctp_inet6_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) return af->available(addr); } +/* Fill in Supported Address Type information for INIT and INIT-ACK + * chunks. Note: In the future, we may want to look at sock options + * to determine whether a PF_INET6 socket really wants to have IPV4 + * addresses. + * Returns number of addresses supported. + */ +static int sctp_inet6_supported_addrs(const struct sctp_opt *opt, + __u16 *types) +{ + types[0] = SCTP_PARAM_IPV4_ADDRESS; + types[1] = SCTP_PARAM_IPV6_ADDRESS; + return 2; +} + static struct proto_ops inet6_seqpacket_ops = { .family = PF_INET6, .release = inet6_release, @@ -627,6 +641,7 @@ static struct sctp_pf sctp_pf_inet6_specific = { .af_supported = sctp_inet6_af_supported, .cmp_addr = sctp_inet6_cmp_addr, .bind_verify = sctp_inet6_bind_verify, + .supported_addrs = sctp_inet6_supported_addrs, .af = &sctp_ipv6_specific, }; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 33ff2f5a434e..340aa00e38ec 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -631,6 +631,16 @@ static int sctp_inet_bind_verify(struct sctp_opt *opt, union sctp_addr *addr) return sctp_v4_available(addr); } +/* Fill in Supported Address Type information for INIT and INIT-ACK + * chunks. Returns number of addresses supported. + */ +static int sctp_inet_supported_addrs(const struct sctp_opt *opt, + __u16 *types) +{ + types[0] = SCTP_PARAM_IPV4_ADDRESS; + return 1; +} + /* Wrapper routine that calls the ip transmit routine. */ static inline int sctp_v4_xmit(struct sk_buff *skb, struct sctp_transport *transport, int ipfragok) @@ -653,6 +663,7 @@ static struct sctp_pf sctp_pf_inet = { .af_supported = sctp_inet_af_supported, .cmp_addr = sctp_inet_cmp_addr, .bind_verify = sctp_inet_bind_verify, + .supported_addrs = sctp_inet_supported_addrs, .af = &sctp_ipv4_specific, }; diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index ec0e2bf6a105..f2308f8373cb 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c @@ -66,29 +66,6 @@ #include #include -/* RFC 2960 3.3.2 Initiation (INIT) (1) - * - * Note 4: This parameter, when present, specifies all the - * address types the sending endpoint can support. The absence - * of this parameter indicates that the sending endpoint can - * support any address type. - */ -static const sctp_supported_addrs_param_t sat_param = { - { - SCTP_PARAM_SUPPORTED_ADDRESS_TYPES, - __constant_htons(SCTP_SAT_LEN), - } -}; - -/* gcc 3.2 doesn't allow initialization of zero-length arrays. So the above - * structure is split and the address types array is initialized using a - * fixed length array. - */ -static const __u16 sat_addr_types[2] = { - SCTP_PARAM_IPV4_ADDRESS, - SCTP_V6(SCTP_PARAM_IPV6_ADDRESS,) -}; - /* RFC 2960 3.3.2 Initiation (INIT) (1) * * Note 2: The ECN capable field is reserved for future use of @@ -174,7 +151,10 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, union sctp_params addrs; size_t chunksize; sctp_chunk_t *retval = NULL; - int addrs_len = 0; + int num_types, addrs_len = 0; + struct sctp_opt *sp; + sctp_supported_addrs_param_t sat; + __u16 types[2]; /* RFC 2960 3.3.2 Initiation (INIT) (1) * @@ -195,7 +175,11 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, init.num_inbound_streams = htons(asoc->c.sinit_max_instreams); init.initial_tsn = htonl(asoc->c.initial_tsn); - chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN; + /* How many address types are needed? */ + sp = sctp_sk(asoc->base.sk); + num_types = sp->pf->supported_addrs(sp, types); + + chunksize = sizeof(init) + addrs_len + SCTP_SAT_LEN(num_types); chunksize += sizeof(ecap_param); chunksize += vparam_len; @@ -220,8 +204,18 @@ sctp_chunk_t *sctp_make_init(const sctp_association_t *asoc, retval->param_hdr.v = sctp_addto_chunk(retval, addrs_len, addrs.v); - sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &sat_param); - sctp_addto_chunk(retval, sizeof(sat_addr_types), sat_addr_types); + /* RFC 2960 3.3.2 Initiation (INIT) (1) + * + * Note 4: This parameter, when present, specifies all the + * address types the sending endpoint can support. The absence + * of this parameter indicates that the sending endpoint can + * support any address type. + */ + sat.param_hdr.type = SCTP_PARAM_SUPPORTED_ADDRESS_TYPES; + sat.param_hdr.length = htons(SCTP_SAT_LEN(num_types)); + sctp_addto_chunk(retval, sizeof(sat), &sat); + sctp_addto_chunk(retval, num_types * sizeof(__u16), &types); + sctp_addto_chunk(retval, sizeof(ecap_param), &ecap_param); nodata: if (addrs.v) -- cgit v1.2.3 From bf9539992ec2eaa4a11b2b7a3cc04ee2fe56f643 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Sun, 2 Mar 2003 23:14:00 -0800 Subject: [SCTP] accept() support for TCP-style SCTP sockets. --- include/net/sctp/structs.h | 2 + net/sctp/endpointola.c | 2 + net/sctp/ipv6.c | 76 ++++++++++- net/sctp/protocol.c | 78 ++++++++++- net/sctp/sm_sideeffect.c | 27 +++- net/sctp/socket.c | 331 +++++++++++++++++++++++++++++++++------------ net/sctp/ulpqueue.c | 4 +- 7 files changed, 419 insertions(+), 101 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0fa7c1d2db90..dd8e37364fcd 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -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; }; diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index d24f06cdcaa9..1f4cdc25d81c 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c @@ -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); diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index fd3ac5c93deb..1133d3fd93bb 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c @@ -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); } diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 340aa00e38ec..f53710475167 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -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. */ -struct inet_protosw sctp_protosw = { +static 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 @@ err_ahash_alloc: 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); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1228f55dfdfb..74c1eefb96d5 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -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) && - (waitqueue_active(&asoc->wait))) - wake_up_interruptible(&asoc->wait); + 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 (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); + } } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index de934672f74e..dbf8be0cce5c 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -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); - *err = error; - return NULL; + 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 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. */ - 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 * 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, int *optlen) { struct sctp_status status; - sctp_endpoint_t *ep; sctp_association_t *assoc = NULL; struct sctp_transport *transport; sctp_assoc_t associd; @@ -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 *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 @@ -1893,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. - */ - 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); + /* Populate the fields of the newsk from the oldsk and migrate the + * assoc to the newsk. + */ + sctp_sock_migrate(oldsk, newsk, assoc, SCTP_SOCKET_UDP_HIGH_BANDWIDTH); *newsock = tmpsock; @@ -2615,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 @@ -2630,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; } @@ -2653,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; @@ -3285,7 +3323,7 @@ out: return err; do_error: - err = -ECONNABORTED; + err = -ECONNREFUSED; goto out; do_interrupted: @@ -3297,6 +3335,131 @@ do_nonblock: 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", diff --git a/net/sctp/ulpqueue.c b/net/sctp/ulpqueue.c index 96fdd8afbbb6..dd14e7554d97 100644 --- a/net/sctp/ulpqueue.c +++ b/net/sctp/ulpqueue.c @@ -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: @@ -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 (sctp_ulpq_clear_pd(ulpq) || ev) - wake_up_interruptible(sk->sleep); + sk->data_ready(sk, 0); } -- cgit v1.2.3 From 020fec6ee15d8ae40a666bc4ea1efbddc52c4a5d Mon Sep 17 00:00:00 2001 From: Jon Grimm Date: Mon, 3 Mar 2003 21:13:58 -0600 Subject: [SCTP] Add SCTP_NODELAY sockopt and message delay (ardelle.fan) Submitted by Ardelle Fan. Add Nagle-like delay to SCTP so small messages try to bundle together. Add sockopt to enable/disable the delay functionality. --- include/net/sctp/command.h | 16 +++---- include/net/sctp/constants.h | 1 + include/net/sctp/sctp.h | 16 ++----- include/net/sctp/sm.h | 46 +++++++++---------- include/net/sctp/structs.h | 26 +++++------ include/net/sctp/user.h | 2 + net/sctp/output.c | 90 ++++++++++++++++++++++-------------- net/sctp/outqueue.c | 106 +++++++++++++++++++++++++------------------ net/sctp/protocol.c | 9 ++-- net/sctp/sm_sideeffect.c | 2 +- net/sctp/sm_statefuns.c | 34 +++++++------- net/sctp/socket.c | 95 ++++++++++++++++++++++++++++++-------- 12 files changed, 267 insertions(+), 176 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/command.h b/include/net/sctp/command.h index 6603202d91f7..f730dd55f5ad 100644 --- a/include/net/sctp/command.h +++ b/include/net/sctp/command.h @@ -110,13 +110,13 @@ typedef union { sctp_event_timeout_t to; sctp_counter_t counter; void *ptr; - sctp_chunk_t *chunk; - sctp_association_t *asoc; + struct sctp_chunk *chunk; + struct sctp_association *asoc; struct sctp_transport *transport; - sctp_bind_addr_t *bp; + struct sctp_bind_addr *bp; sctp_init_chunk_t *init; struct sctp_ulpevent *ulpevent; - sctp_packet_t *packet; + struct sctp_packet *packet; sctp_sackhdr_t *sackh; } sctp_arg_t; @@ -158,13 +158,13 @@ SCTP_ARG_CONSTRUCTOR(STATE, sctp_state_t, state) SCTP_ARG_CONSTRUCTOR(COUNTER, sctp_counter_t, counter) SCTP_ARG_CONSTRUCTOR(TO, sctp_event_timeout_t, to) SCTP_ARG_CONSTRUCTOR(PTR, void *, ptr) -SCTP_ARG_CONSTRUCTOR(CHUNK, sctp_chunk_t *, chunk) -SCTP_ARG_CONSTRUCTOR(ASOC, sctp_association_t *, asoc) +SCTP_ARG_CONSTRUCTOR(CHUNK, struct sctp_chunk *, chunk) +SCTP_ARG_CONSTRUCTOR(ASOC, struct sctp_association *, asoc) SCTP_ARG_CONSTRUCTOR(TRANSPORT, struct sctp_transport *, transport) -SCTP_ARG_CONSTRUCTOR(BA, sctp_bind_addr_t *, bp) +SCTP_ARG_CONSTRUCTOR(BA, struct sctp_bind_addr *, bp) SCTP_ARG_CONSTRUCTOR(PEER_INIT, sctp_init_chunk_t *, init) SCTP_ARG_CONSTRUCTOR(ULPEVENT, struct sctp_ulpevent *, ulpevent) -SCTP_ARG_CONSTRUCTOR(PACKET, sctp_packet_t *, packet) +SCTP_ARG_CONSTRUCTOR(PACKET, struct sctp_packet *, packet) SCTP_ARG_CONSTRUCTOR(SACKH, sctp_sackhdr_t *, sackh) typedef struct { diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 3cc94d900f95..23a956762e41 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -345,6 +345,7 @@ typedef enum { SCTP_XMIT_PMTU_FULL, SCTP_XMIT_RWND_FULL, SCTP_XMIT_MUST_FRAG, + SCTP_XMIT_NAGLE_DELAY, } sctp_xmit_t; /* These are the commands for manipulating transports. */ diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h index 1898cb15c70f..27a69518c2f9 100644 --- a/include/net/sctp/sctp.h +++ b/include/net/sctp/sctp.h @@ -313,31 +313,21 @@ static inline void sctp_sysctl_unregister(void) { return; } #endif +/* Size of Supported Address Parameter for 'x' address types. */ +#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16)) + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) extern int sctp_v6_init(void); extern void sctp_v6_exit(void); - static inline int sctp_ipv6_addr_type(const struct in6_addr *addr) { return ipv6_addr_type((struct in6_addr*) addr); } -/* Size of Supported Address Parameter for 'x' address types. */ -#define SCTP_SAT_LEN(x) (sizeof(struct sctp_paramhdr) + (x) * sizeof(__u16)) - -/* Note: These V6 macros are obsolescent. */ -/* Use this macro to enclose code fragments which are V6-dependent. */ -#define SCTP_V6(m...) m -#define SCTP_V6_SUPPORT 1 - #else /* #ifdef defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) */ #define sctp_ipv6_addr_type(a) 0 -#define SCTP_SAT_LEN (sizeof(sctp_paramhdr_t) + 1 * sizeof(__u16)) -#define SCTP_V6(m...) /* Do nothing. */ -#undef SCTP_V6_SUPPORT - static inline int sctp_v6_init(void) { return 0; } static inline void sctp_v6_exit(void) { return; } diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h index 7b08e90a102a..16737eda8d8c 100644 --- a/include/net/sctp/sm.h +++ b/include/net/sctp/sm.h @@ -3,40 +3,40 @@ * Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 2001 Intel Corp. * Copyright (c) 2001-2002 International Business Machines Corp. - * + * * This file is part of the SCTP kernel reference Implementation - * + * * This file is part of the implementation of the add-IP extension, * based on June 29, 2001, * for the SCTP kernel reference Implementation. - * + * * These are definitions needed by the state machine. - * - * The SCTP reference implementation is free software; - * you can redistribute it and/or modify it under the terms of + * + * The SCTP reference implementation is free software; + * you can redistribute it and/or modify it under the terms of * the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. - * - * The SCTP reference implementation is distributed in the hope that it + * + * The SCTP reference implementation is distributed in the hope that it * will be useful, but WITHOUT ANY WARRANTY; without even the implied * ************************ * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. * See the GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public License * along with GNU CC; see the file COPYING. If not, write to * the Free Software Foundation, 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * + * Boston, MA 02111-1307, USA. + * * Please send any bug reports or fixes you make to the * email addresses: * lksctp developers - * + * * Or submit a bug report through the following website: * http://www.sf.net/projects/lksctp * - * Written or modified by: + * Written or modified by: * La Monte H.P. Yarroll * Karl Knutson * Xingang Guo @@ -313,18 +313,18 @@ void sctp_generate_t3_rtx_event(unsigned long peer); void sctp_generate_heartbeat_event(unsigned long peer); sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *); -sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, - const sctp_association_t *asoc, - sctp_chunk_t *chunk, - const void *payload, - size_t paylen); -sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, - const sctp_chunk_t *chunk); -void sctp_ootb_pkt_free(sctp_packet_t *packet); +struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *, + const struct sctp_association *, + struct sctp_chunk *chunk, + const void *payload, + size_t paylen); +struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *, + const struct sctp_chunk *); +void sctp_ootb_pkt_free(struct sctp_packet *); sctp_cookie_param_t * -sctp_pack_cookie(const sctp_endpoint_t *, const sctp_association_t *, - const sctp_chunk_t *, int *cookie_len, +sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *, + const struct sctp_chunk *, int *cookie_len, const __u8 *, int addrs_len); sctp_association_t *sctp_unpack_cookie(const sctp_endpoint_t *, const sctp_association_t *, diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h index 0fa7c1d2db90..a595ac501cca 100644 --- a/include/net/sctp/structs.h +++ b/include/net/sctp/structs.h @@ -88,7 +88,6 @@ struct sctp_ssnmap; typedef struct sctp_endpoint sctp_endpoint_t; typedef struct sctp_association sctp_association_t; -typedef struct sctp_packet sctp_packet_t; typedef struct sctp_chunk sctp_chunk_t; typedef struct sctp_bind_addr sctp_bind_addr_t; typedef struct sctp_endpoint_common sctp_endpoint_common_t; @@ -602,26 +601,26 @@ struct sctp_packet { typedef int (sctp_outq_thandler_t)(struct sctp_outq *, void *); typedef int (sctp_outq_ehandler_t)(struct sctp_outq *); -typedef sctp_packet_t *(sctp_outq_ohandler_init_t) - (sctp_packet_t *, +typedef struct sctp_packet *(sctp_outq_ohandler_init_t) + (struct sctp_packet *, struct sctp_transport *, __u16 sport, __u16 dport); -typedef sctp_packet_t *(sctp_outq_ohandler_config_t) - (sctp_packet_t *, +typedef struct sctp_packet *(sctp_outq_ohandler_config_t) + (struct sctp_packet *, __u32 vtag, int ecn_capable, sctp_packet_phandler_t *get_prepend_chunk); -typedef sctp_xmit_t (sctp_outq_ohandler_t)(sctp_packet_t *, +typedef sctp_xmit_t (sctp_outq_ohandler_t)(struct sctp_packet *, sctp_chunk_t *); -typedef int (sctp_outq_ohandler_force_t)(sctp_packet_t *); +typedef int (sctp_outq_ohandler_force_t)(struct sctp_packet *); sctp_outq_ohandler_init_t sctp_packet_init; sctp_outq_ohandler_config_t sctp_packet_config; sctp_outq_ohandler_t sctp_packet_append_chunk; sctp_outq_ohandler_t sctp_packet_transmit_chunk; sctp_outq_ohandler_force_t sctp_packet_transmit; -void sctp_packet_free(sctp_packet_t *); +void sctp_packet_free(struct sctp_packet *); /* This represents a remote transport address. @@ -787,7 +786,7 @@ struct sctp_transport { struct list_head transmitted; /* We build bundle-able packets for this transport here. */ - sctp_packet_t packet; + struct sctp_packet packet; /* This is the list of transports that have chunks to send. */ struct list_head send_ready; @@ -863,12 +862,11 @@ void sctp_inq_set_th_handler(struct sctp_inq *, void (*)(void *), void *); struct sctp_outq { sctp_association_t *asoc; - /* BUG: This really should be an array of streams. - * This really holds a list of chunks (one stream). - * FIXME: If true, why so? - */ + /* Data pending that has never been transmitted. */ struct sk_buff_head out; + unsigned out_qlen; /* Total length of queued data chunks. */ + /* These are control chunks we want to send. */ struct sk_buff_head control; @@ -883,7 +881,7 @@ struct sctp_outq { struct list_head retransmit; /* Call these functions to send chunks down to the next lower - * layer. This is always SCTP_packet, but we separate the two + * layer. This is always sctp_packet, but we separate the two * structures to make testing simpler. */ sctp_outq_ohandler_init_t *init_output; diff --git a/include/net/sctp/user.h b/include/net/sctp/user.h index 69e241b1a88a..fc99306d35e6 100644 --- a/include/net/sctp/user.h +++ b/include/net/sctp/user.h @@ -108,6 +108,8 @@ enum sctp_optname { #define SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS_NUM SCTP_GET_LOCAL_ADDRS, /* Get all local addresss. */ #define SCTP_GET_LOCAL_ADDRS SCTP_GET_LOCAL_ADDRS + SCTP_NODELAY, /* Get/set nodelay option. */ +#define SCTP_NODELAY SCTP_NODELAY }; diff --git a/net/sctp/output.c b/net/sctp/output.c index d7826c2216e6..0291d157c5f7 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c @@ -62,17 +62,16 @@ #include /* Forward declarations for private helpers. */ -static void sctp_packet_reset(sctp_packet_t *packet); -static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, - sctp_chunk_t *chunk); +static void sctp_packet_reset(struct sctp_packet *packet); +static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, + struct sctp_chunk *chunk); /* Config a packet. * This appears to be a followup set of initializations.) */ -sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, - __u32 vtag, - int ecn_capable, - sctp_packet_phandler_t *prepend_handler) +struct sctp_packet *sctp_packet_config(struct sctp_packet *packet, + __u32 vtag, int ecn_capable, + sctp_packet_phandler_t *prepend_handler) { int packet_empty = (packet->size == SCTP_IP_OVERHEAD); @@ -89,10 +88,9 @@ sctp_packet_t *sctp_packet_config(sctp_packet_t *packet, } /* Initialize the packet structure. */ -sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, - struct sctp_transport *transport, - __u16 sport, - __u16 dport) +struct sctp_packet *sctp_packet_init(struct sctp_packet *packet, + struct sctp_transport *transport, + __u16 sport, __u16 dport) { packet->transport = transport; packet->source_port = sport; @@ -109,14 +107,12 @@ sctp_packet_t *sctp_packet_init(sctp_packet_t *packet, } /* Free a packet. */ -void sctp_packet_free(sctp_packet_t *packet) +void sctp_packet_free(struct sctp_packet *packet) { - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; - while (NULL != - (chunk = (sctp_chunk_t *)skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) sctp_free_chunk(chunk); - } if (packet->malloced) kfree(packet); @@ -129,8 +125,8 @@ void sctp_packet_free(sctp_packet_t *packet) * as it can fit in the packet, but any more data that does not fit in this * packet can be sent only after receiving the COOKIE_ACK. */ -sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, - sctp_chunk_t *chunk) +sctp_xmit_t sctp_packet_transmit_chunk(struct sctp_packet *packet, + struct sctp_chunk *chunk) { sctp_xmit_t retval; int error = 0; @@ -152,6 +148,7 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, case SCTP_XMIT_MUST_FRAG: case SCTP_XMIT_RWND_FULL: case SCTP_XMIT_OK: + case SCTP_XMIT_NAGLE_DELAY: break; }; @@ -161,7 +158,8 @@ sctp_xmit_t sctp_packet_transmit_chunk(sctp_packet_t *packet, /* Append a chunk to the offered packet reporting back any inability to do * so. */ -sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) +sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, + struct sctp_chunk *chunk) { sctp_xmit_t retval = SCTP_XMIT_OK; __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); @@ -223,7 +221,7 @@ append: } /* It is OK to send this chunk. */ - skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); + __skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk); packet->size += chunk_len; finish: return retval; @@ -234,18 +232,18 @@ finish: * * The return value is a normal kernel error return value. */ -int sctp_packet_transmit(sctp_packet_t *packet) +int sctp_packet_transmit(struct sctp_packet *packet) { struct sctp_transport *transport = packet->transport; - sctp_association_t *asoc = transport->asoc; + struct sctp_association *asoc = transport->asoc; struct sctphdr *sh; __u32 crc32; struct sk_buff *nskb; - sctp_chunk_t *chunk; + struct sctp_chunk *chunk; struct sock *sk; int err = 0; int padding; /* How much padding do we need? */ - __u8 packet_has_data = 0; + __u8 has_data = 0; struct dst_entry *dst; /* Do NOT generate a chunkless packet... */ @@ -253,7 +251,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) return err; /* Set up convenience variables... */ - chunk = (sctp_chunk_t *) (packet->chunks.next); + chunk = (struct sctp_chunk *) (packet->chunks.next); sk = chunk->skb->sk; /* Allocate the new skb. */ @@ -291,8 +289,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) * [This whole comment explains WORD_ROUND() below.] */ SCTP_DEBUG_PRINTK("***sctp_transmit_packet***\n"); - while (NULL != (chunk = (sctp_chunk_t *) - skb_dequeue(&packet->chunks))) { + while ((chunk = (struct sctp_chunk *)__skb_dequeue(&packet->chunks))) { chunk->num_times_sent++; chunk->sent_at = jiffies; if (sctp_chunk_is_data(chunk)) { @@ -309,7 +306,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) chunk->rtt_in_progress = 1; transport->rto_pending = 1; } - packet_has_data = 1; + has_data = 1; } memcpy(skb_put(nskb, chunk->skb->len), chunk->skb->data, chunk->skb->len); @@ -399,7 +396,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) asoc->peer.last_sent_to = transport; } - if (packet_has_data) { + if (has_data) { struct timer_list *timer; unsigned long timeout; @@ -456,9 +453,9 @@ no_route: /* * This private function resets the packet to a fresh state. */ -static void sctp_packet_reset(sctp_packet_t *packet) +static void sctp_packet_reset(struct sctp_packet *packet) { - sctp_chunk_t *chunk = NULL; + struct sctp_chunk *chunk = NULL; packet->size = SCTP_IP_OVERHEAD; @@ -473,13 +470,15 @@ static void sctp_packet_reset(sctp_packet_t *packet) } /* This private function handles the specifics of appending DATA chunks. */ -static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, - sctp_chunk_t *chunk) +static sctp_xmit_t sctp_packet_append_data(struct sctp_packet *packet, + struct sctp_chunk *chunk) { sctp_xmit_t retval = SCTP_XMIT_OK; size_t datasize, rwnd, inflight; struct sctp_transport *transport = packet->transport; __u32 max_burst_bytes; + struct sctp_opt *sp = sctp_sk(transport->asoc->base.sk); + struct sctp_outq *q = &transport->asoc->outqueue; /* RFC 2960 6.1 Transmission of DATA Chunks * @@ -543,11 +542,34 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, * When a Fast Retransmit is being performed the sender SHOULD * ignore the value of cwnd and SHOULD NOT delay retransmission. */ - if (!chunk->fast_retransmit) { + if (!chunk->fast_retransmit) if (transport->flight_size >= transport->cwnd) { retval = SCTP_XMIT_RWND_FULL; goto finish; } + + /* Nagle's algorithm to solve small-packet problem: + * inhibit the sending of new chunks when new outgoing data arrives + * if any proeviously transmitted data on the connection remains + * unacknowledged. Unless the connection was previously idle. Check + * whether the connection is idle. No outstanding means idle, flush + * it. If outstanding bytes are less than half cwnd, the connection + * is not in the state of congestion, so also flush it. + */ + if (!sp->nodelay && q->outstanding_bytes >= transport->cwnd >> 1) { + /* Check whether this chunk and all the rest of pending + * data will fit or whether we'll choose to delay in + * hopes of bundling a full sized packet. + */ + if ((datasize + q->out_qlen) < transport->asoc->frag_point) { + + /* If the the chunk should be delay + * for future sending, we could not + * append it. + */ + retval = SCTP_XMIT_NAGLE_DELAY; + goto finish; + } } /* Keep track of how many bytes are in flight over this transport. */ diff --git a/net/sctp/outqueue.c b/net/sctp/outqueue.c index a1bed254eba1..2ef83c5c040a 100644 --- a/net/sctp/outqueue.c +++ b/net/sctp/outqueue.c @@ -1,7 +1,7 @@ /* SCTP kernel reference Implementation * Copyright (c) 1999-2000 Cisco, Inc. * Copyright (c) 1999-2001 Motorola, Inc. - * Copyright (c) 2001 Intel Corp. + * Copyright (c) 2001-2003 Intel Corp. * Copyright (c) 2001-2003 International Business Machines Corp. * * This file is part of the SCTP kernel reference Implementation @@ -62,6 +62,33 @@ static void sctp_check_transmitted(struct sctp_outq *q, sctp_sackhdr_t *sack, __u32 highest_new_tsn); +/* Add data to the front of the queue. */ +static inline void sctp_outq_head_data(struct sctp_outq *q, + struct sctp_chunk *ch) +{ + __skb_queue_head(&q->out, (struct sk_buff *)ch); + q->out_qlen += ch->skb->len; + return; +} + +/* Take data from the front of the queue. */ +static inline struct sctp_chunk *sctp_outq_dequeue_data(struct sctp_outq *q) +{ + struct sctp_chunk *ch; + ch = (struct sctp_chunk *)__skb_dequeue(&q->out); + if (ch) + q->out_qlen -= ch->skb->len; + return ch; +} +/* Add data chunk to the end of the queue. */ +static inline void sctp_outq_tail_data(struct sctp_outq *q, + struct sctp_chunk *ch) +{ + __skb_queue_tail(&q->out, (struct sk_buff *)ch); + q->out_qlen += ch->skb->len; + return; +} + /* Generate a new outqueue. */ struct sctp_outq *sctp_outq_new(sctp_association_t *asoc) { @@ -97,6 +124,7 @@ void sctp_outq_init(sctp_association_t *asoc, struct sctp_outq *q) q->empty = 1; q->malloced = 0; + q->out_qlen = 0; } /* Free the outqueue structure and any related pending chunks. @@ -133,7 +161,7 @@ void sctp_outq_teardown(struct sctp_outq *q) } /* Throw away any leftover data chunks. */ - while ((chunk = (sctp_chunk_t *) skb_dequeue(&q->out))) + while ((chunk = sctp_outq_dequeue_data(q))) sctp_free_chunk(chunk); /* Throw away any leftover control chunks. */ @@ -192,7 +220,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) sctp_cname(SCTP_ST_CHUNK(chunk->chunk_hdr->type)) : "Illegal Chunk"); - skb_queue_tail(&q->out, (struct sk_buff *) chunk); + sctp_outq_tail_data(q, chunk); if (chunk->chunk_hdr->flags & SCTP_DATA_UNORDERED) SCTP_INC_STATS(SctpOutUnorderChunks); else @@ -201,7 +229,7 @@ int sctp_outq_tail(struct sctp_outq *q, sctp_chunk_t *chunk) break; }; } else { - skb_queue_tail(&q->control, (struct sk_buff *) chunk); + __skb_queue_tail(&q->control, (struct sk_buff *) chunk); SCTP_INC_STATS(SctpOutCtrlChunks); } @@ -351,7 +379,7 @@ void sctp_retransmit(struct sctp_outq *q, struct sctp_transport *transport, * * The return value is a normal kernel error return value. */ -static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, +static int sctp_outq_flush_rtx(struct sctp_outq *q, struct sctp_packet *pkt, int rtx_timeout, int *start_timer) { struct list_head *lqueue; @@ -385,17 +413,6 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, while (lchunk) { chunk = list_entry(lchunk, sctp_chunk_t, transmitted_list); -#if 0 - /* If a chunk has been tried for more than SCTP_DEF_MAX_SEND - * times, discard it, and check the empty flag of the outqueue. - * - * --xguo - */ - if (chunk->snd_count > SCTP_DEF_MAX_SEND) { - sctp_free_chunk(chunk); - continue; - } -#endif /* Make sure that Gap Acked TSNs are not retransmitted. A * simple approach is just to move such TSNs out of the @@ -462,7 +479,7 @@ static int sctp_outq_flush_rtx(struct sctp_outq *q, sctp_packet_t *pkt, * chunk that is currently in the process of fragmentation. */ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, - sctp_packet_t *packet, sctp_chunk_t *frag, __u32 tsn) + struct sctp_packet *packet, sctp_chunk_t *frag, __u32 tsn) { struct sctp_transport *transport = packet->transport; struct sk_buff_head *queue = &q->out; @@ -480,11 +497,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, SCTP_DEBUG_PRINTK("sctp_xmit_frag: q not empty. " "adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); - if (pos) { - skb_insert(pos, (struct sk_buff *) frag); - } else { - skb_queue_tail(queue, (struct sk_buff *) frag); - } + if (pos) + __skb_insert((struct sk_buff *)frag, pos->prev, + pos, pos->list); + else + __skb_queue_tail(queue, (struct sk_buff *) frag); return; } @@ -496,11 +513,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, SCTP_DEBUG_PRINTK("sctp_xmit_frag: rwnd full. " "adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); - if (pos) { - skb_insert(pos, (struct sk_buff *) frag); - } else { - skb_queue_tail(queue, (struct sk_buff *) frag); - } + if (pos) + __skb_insert((struct sk_buff *)frag, pos->prev, + pos, pos->list); + else + __skb_queue_tail(queue, (struct sk_buff *)frag); break; case SCTP_XMIT_OK: @@ -512,11 +529,11 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " "failed. adding 0x%x to outqueue\n", ntohl(frag->subh.data_hdr->tsn)); - if (pos) { - skb_insert(pos, (struct sk_buff *) frag); - } else { - skb_queue_tail(queue, (struct sk_buff *) frag); - } + if (pos) + __skb_insert((struct sk_buff *)frag, pos->prev, + pos, pos->list); + else + __skb_queue_tail(queue,(struct sk_buff *)frag); } else { SCTP_DEBUG_PRINTK("sctp_xmit_frag: force output " "success. 0x%x sent\n", @@ -537,7 +554,7 @@ void sctp_xmit_frag(struct sctp_outq *q, struct sk_buff *pos, * The argument 'frag' point to the first fragment and it holds the list * of all the other fragments in the 'frag_list' field. */ -void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet, +void sctp_xmit_fragmented_chunks(struct sctp_outq *q, struct sctp_packet *pkt, sctp_chunk_t *frag) { sctp_association_t *asoc = frag->asoc; @@ -557,13 +574,13 @@ void sctp_xmit_fragmented_chunks(struct sctp_outq *q, sctp_packet_t *packet, pos = skb_peek(&q->out); /* Transmit the first fragment. */ - sctp_xmit_frag(q, pos, packet, frag, tsn++); + sctp_xmit_frag(q, pos, pkt, frag, tsn++); /* Transmit the rest of fragments. */ frag_list = &frag->frag_list; list_for_each(lfrag, frag_list) { frag = list_entry(lfrag, sctp_chunk_t, frag_list); - sctp_xmit_frag(q, pos, packet, frag, tsn++); + sctp_xmit_frag(q, pos, pkt, frag, tsn++); } } @@ -672,15 +689,14 @@ err: * * Description: Send everything in q which we legally can, subject to * congestion limitations. - * - * Note: This function can be called from multiple contexts so appropriate + * * Note: This function can be called from multiple contexts so appropriate * locking concerns must be made. Today we use the sock lock to protect * this function. */ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) { - sctp_packet_t *packet; - sctp_packet_t singleton; + struct sctp_packet *packet; + struct sctp_packet singleton; sctp_association_t *asoc = q->asoc; int ecn_capable = asoc->peer.ecn_capable; __u16 sport = asoc->base.bind_addr.port; @@ -852,7 +868,8 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) /* Finally, transmit new packets. */ start_timer = 0; queue = &q->out; - while (NULL != (chunk = (sctp_chunk_t *) skb_dequeue(queue))) { + + while (NULL != (chunk = sctp_outq_dequeue_data(q))) { /* RFC 2960 6.5 Every DATA chunk MUST carry a valid * stream identifier. */ @@ -925,6 +942,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) switch (status) { case SCTP_XMIT_PMTU_FULL: case SCTP_XMIT_RWND_FULL: + case SCTP_XMIT_NAGLE_DELAY: /* We could not append this chunk, so put * the chunk back on the output queue. */ @@ -932,7 +950,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) "not transmit TSN: 0x%x, status: %d\n", ntohl(chunk->subh.data_hdr->tsn), status); - skb_queue_head(queue, (struct sk_buff *)chunk); + sctp_outq_head_data(q, chunk); goto sctp_flush_out; break; @@ -994,6 +1012,7 @@ int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout) } sctp_flush_out: + /* Before returning, examine all the transports touched in * this call. Right now, we bluntly force clear all the * transports. Things might change after we implement Nagle. @@ -1163,11 +1182,10 @@ int sctp_outq_sack(struct sctp_outq *q, sctp_sackhdr_t *sack) sack_a_rwnd = ntohl(sack->a_rwnd); outstanding = q->outstanding_bytes; - if (outstanding < sack_a_rwnd) { + if (outstanding < sack_a_rwnd) sack_a_rwnd -= outstanding; - } else { + else sack_a_rwnd = 0; - } asoc->peer.rwnd = sack_a_rwnd; diff --git a/net/sctp/protocol.c b/net/sctp/protocol.c index 340aa00e38ec..711564bf898e 100644 --- a/net/sctp/protocol.c +++ b/net/sctp/protocol.c @@ -502,10 +502,13 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long event, */ int sctp_ctl_sock_init(void) { - int err = 0; - int family = PF_INET; + int err; + sa_family_t family; - SCTP_V6(family = PF_INET6;) + if (sctp_get_pf_specific(PF_INET6)) + family = PF_INET6; + else + family = PF_INET; err = sock_create(family, SOCK_SEQPACKET, IPPROTO_SCTP, &sctp_ctl_socket); diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 1228f55dfdfb..37dfce4fb24c 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -256,7 +256,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, sctp_cmd_t *cmd; sctp_chunk_t *new_obj; sctp_chunk_t *chunk = NULL; - sctp_packet_t *packet; + struct sctp_packet *packet; struct list_head *pos; struct timer_list *timer; unsigned long timeout; diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 12889a5d350f..fac774a0f504 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c @@ -189,7 +189,7 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const sctp_endpoint_t *ep, sctp_chunk_t *repl; sctp_association_t *new_asoc; sctp_chunk_t *err_chunk; - sctp_packet_t *packet; + struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; int len; @@ -354,10 +354,9 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const sctp_endpoint_t *ep, sctp_init_chunk_t *initchunk; __u32 init_tag; sctp_chunk_t *err_chunk; - sctp_packet_t *packet; + struct sctp_packet *packet; sctp_disposition_t ret; - /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. @@ -912,14 +911,14 @@ static int sctp_sf_send_restart_abort(union sctp_addr *ssa, sctp_cmd_seq_t *commands) { int len; - sctp_packet_t *pkt; + struct sctp_packet *pkt; sctp_addr_param_t *addrparm; sctp_errhdr_t *errhdr; sctp_endpoint_t *ep; char buffer[sizeof(sctp_errhdr_t) + sizeof(sctp_addr_param_t)]; - /* Build the error on the stack. We are way to malloc - * malloc crazy throughout the code today. + /* Build the error on the stack. We are way to malloc crazy + * throughout the code today. */ errhdr = (sctp_errhdr_t *)buffer; addrparm = (sctp_addr_param_t *)errhdr->variable; @@ -1105,11 +1104,10 @@ static sctp_disposition_t sctp_sf_do_unexpected_init( sctp_chunk_t *repl; sctp_association_t *new_asoc; sctp_chunk_t *err_chunk; - sctp_packet_t *packet; + struct sctp_packet *packet; sctp_unrecognized_param_t *unk_param; int len; - /* 6.10 Bundling * An endpoint MUST NOT bundle INIT, INIT ACK or * SHUTDOWN COMPLETE with any other chunks. @@ -2351,7 +2349,7 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const sctp_endpoint_t *ep, * room. Note: Playing nice with a confused sender. A * malicious sender can still eat up all our buffer * space and in the future we may want to detect and - * do more drastic reneging. + * do more drastic reneging. */ if (sctp_tsnmap_has_gap(&asoc->peer.tsn_map) && (sctp_tsnmap_get_ctsn(&asoc->peer.tsn_map) + 1) == tsn) { @@ -2751,7 +2749,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const sctp_endpoint_t *ep, void *arg, sctp_cmd_seq_t *commands) { - sctp_packet_t *packet = NULL; + struct sctp_packet *packet = NULL; sctp_chunk_t *chunk = arg; sctp_chunk_t *abort; @@ -2953,7 +2951,7 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const sctp_endpoint_t *ep, void *arg, sctp_cmd_seq_t *commands) { - sctp_packet_t *packet = NULL; + struct sctp_packet *packet = NULL; sctp_chunk_t *chunk = arg; sctp_chunk_t *shut; @@ -4377,13 +4375,13 @@ sctp_sackhdr_t *sctp_sm_pull_sack(sctp_chunk_t *chunk) /* Create an ABORT packet to be sent as a response, with the specified * error causes. */ -sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, +struct sctp_packet *sctp_abort_pkt_new(const sctp_endpoint_t *ep, const sctp_association_t *asoc, sctp_chunk_t *chunk, const void *payload, size_t paylen) { - sctp_packet_t *packet; + struct sctp_packet *packet; sctp_chunk_t *abort; packet = sctp_ootb_pkt_new(asoc, chunk); @@ -4413,10 +4411,10 @@ sctp_packet_t *sctp_abort_pkt_new(const sctp_endpoint_t *ep, } /* Allocate a packet for responding in the OOTB conditions. */ -sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, +struct sctp_packet *sctp_ootb_pkt_new(const sctp_association_t *asoc, const sctp_chunk_t *chunk) { - sctp_packet_t *packet; + struct sctp_packet *packet; struct sctp_transport *transport; __u16 sport; __u16 dport; @@ -4449,7 +4447,7 @@ sctp_packet_t *sctp_ootb_pkt_new(const sctp_association_t *asoc, goto nomem; /* Allocate a new packet for sending the response. */ - packet = t_new(sctp_packet_t, GFP_ATOMIC); + packet = t_new(struct sctp_packet, GFP_ATOMIC); if (!packet) goto nomem_packet; @@ -4471,7 +4469,7 @@ nomem: } /* Free the packet allocated earlier for responding in the OOTB condition. */ -void sctp_ootb_pkt_free(sctp_packet_t *packet) +void sctp_ootb_pkt_free(struct sctp_packet *packet) { sctp_transport_free(packet->transport); sctp_packet_free(packet); @@ -4484,7 +4482,7 @@ void sctp_send_stale_cookie_err(const sctp_endpoint_t *ep, sctp_cmd_seq_t *commands, sctp_chunk_t *err_chunk) { - sctp_packet_t *packet; + struct sctp_packet *packet; if (err_chunk) { packet = sctp_ootb_pkt_new(asoc, chunk); diff --git a/net/sctp/socket.c b/net/sctp/socket.c index d04c6b7faf98..b7b42f8829ef 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1221,7 +1221,7 @@ out: return err; } -static inline int sctp_setsockopt_disable_fragments(struct sock *sk, +static int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) { int val; @@ -1237,7 +1237,7 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, return 0; } -static inline int sctp_setsockopt_events(struct sock *sk, char *optval, +static int sctp_setsockopt_events(struct sock *sk, char *optval, int optlen) { if (optlen != sizeof(struct sctp_event_subscribe)) @@ -1247,7 +1247,7 @@ static inline int sctp_setsockopt_events(struct sock *sk, char *optval, return 0; } -static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, +static int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) { struct sctp_opt *sp = sctp_sk(sk); @@ -1264,7 +1264,7 @@ static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, return 0; } -static inline int sctp_setsockopt_peer_addr_params(struct sock *sk, +static int sctp_setsockopt_peer_addr_params(struct sock *sk, char *optval, int optlen) { struct sctp_paddrparams params; @@ -1323,7 +1323,7 @@ static inline int sctp_setsockopt_peer_addr_params(struct sock *sk, return 0; } -static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, +static int sctp_setsockopt_initmsg(struct sock *sk, char *optval, int optlen) { if (optlen != sizeof(struct sctp_initmsg)) @@ -1348,7 +1348,7 @@ static inline int sctp_setsockopt_initmsg(struct sock *sk, char *optval, * sinfo_timetolive. The user must provide the sinfo_assoc_id field in * to this call if the caller is using the UDP model. */ -static inline int sctp_setsockopt_default_send_param(struct sock *sk, +static int sctp_setsockopt_default_send_param(struct sock *sk, char *optval, int optlen) { struct sctp_sndrcvinfo info; @@ -1406,6 +1406,31 @@ static int sctp_setsockopt_peer_prim(struct sock *sk, char *optval, int optlen) return 0; } +/* + * + * 7.1.5 SCTP_NODELAY + * + * Turn on/off any Nagle-like algorithm. This means that packets are + * generally sent as soon as possible and no unnecessary delays are + * introduced, at the cost of more packets in the network. Expects an + * integer boolean flag. + */ +static int sctp_setsockopt_nodelay(struct sock *sk, char *optval, + int optlen) +{ + __u8 val; + + if (optlen < sizeof(__u8)) + return -EINVAL; + + if (get_user(val, (__u8 *)optval)) + return -EFAULT; + + sctp_sk(sk)->nodelay = (val == 0) ? 0 : 1; + + return 0; +} + /* API 6.2 setsockopt(), getsockopt() * * Applications use setsockopt() and getsockopt() to set or retrieve @@ -1505,6 +1530,10 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname, retval = sctp_setsockopt_peer_prim(sk, optval, optlen); break; + case SCTP_NODELAY: + retval = sctp_setsockopt_nodelay(sk, optval, optlen); + break; + default: retval = -ENOPROTOOPT; break; @@ -1715,7 +1744,7 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk) sp->disable_fragments = 0; /* Turn on/off any Nagle-like algorithm. */ - sp->nodelay = 0; + sp->nodelay = 1; /* Auto-close idle associations after the configured * number of seconds. A value of 0 disables this @@ -1834,7 +1863,7 @@ out: return (retval); } -static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, +static int sctp_getsockopt_disable_fragments(struct sock *sk, int len, char *optval, int *optlen) { int val; @@ -1851,7 +1880,7 @@ static inline int sctp_getsockopt_disable_fragments(struct sock *sk, int len, return 0; } -static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_set_events(struct sock *sk, int len, char *optval, int *optlen) { if (len != sizeof(struct sctp_event_subscribe)) return -EINVAL; @@ -1860,7 +1889,7 @@ static inline int sctp_getsockopt_set_events(struct sock *sk, int len, char *opt return 0; } -static inline int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_autoclose(struct sock *sk, int len, char *optval, int *optlen) { /* Applicable to UDP-style socket only */ if (SCTP_SOCKET_TCP == sctp_sk(sk)->type) @@ -1973,7 +2002,7 @@ SCTP_STATIC int sctp_do_peeloff(sctp_association_t *assoc, struct socket **newso return err; } -static inline int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_peeloff(struct sock *sk, int len, char *optval, int *optlen) { sctp_peeloff_arg_t peeloff; struct socket *newsock; @@ -2016,7 +2045,7 @@ out: return retval; } -static inline int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, +static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_paddrparams params; @@ -2060,7 +2089,7 @@ static inline int sctp_getsockopt_peer_addr_params(struct sock *sk, int len, return 0; } -static inline int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) +static int sctp_getsockopt_initmsg(struct sock *sk, int len, char *optval, int *optlen) { if (len != sizeof(struct sctp_initmsg)) return -EINVAL; @@ -2139,7 +2168,7 @@ static int sctp_getsockopt_peer_addrs(struct sock *sk, int len, return 0; } -static inline int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, +static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, char *optval, int *optlen) { sctp_assoc_t id; @@ -2178,7 +2207,7 @@ static inline int sctp_getsockopt_local_addrs_num(struct sock *sk, int len, return 0; } -static inline int sctp_getsockopt_local_addrs(struct sock *sk, int len, +static int sctp_getsockopt_local_addrs(struct sock *sk, int len, char *optval, int *optlen) { sctp_bind_addr_t *bp; @@ -2280,7 +2309,7 @@ static int sctp_getsockopt_peer_prim(struct sock *sk, int len, * * For getsockopt, it get the default sctp_sndrcvinfo structure. */ -static inline int sctp_getsockopt_default_send_param(struct sock *sk, +static int sctp_getsockopt_default_send_param(struct sock *sk, int len, char *optval, int *optlen) { struct sctp_sndrcvinfo info; @@ -2307,6 +2336,33 @@ static inline int sctp_getsockopt_default_send_param(struct sock *sk, return 0; } +/* + * + * 7.1.5 SCTP_NODELAY + * + * Turn on/off any Nagle-like algorithm. This means that packets are + * generally sent as soon as possible and no unnecessary delays are + * introduced, at the cost of more packets in the network. Expects an + * integer boolean flag. + */ + +static int sctp_getsockopt_nodelay(struct sock *sk, int len, + char *optval, int *optlen) +{ + __u8 val; + + if (len < sizeof(__u8)) + return -EINVAL; + + len = sizeof(__u8); + val = (sctp_sk(sk)->nodelay == 1); + if (put_user(len, optlen)) + return -EFAULT; + if (copy_to_user(optval, &val, len)) + return -EFAULT; + return 0; +} + SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) { @@ -2380,6 +2436,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname, case SCTP_SET_PEER_PRIMARY_ADDR: retval = sctp_getsockopt_peer_prim(sk, len, optval, optlen); break; + case SCTP_NODELAY: + retval = sctp_getsockopt_nodelay(sk, len, optval, optlen); + break; default: retval = -ENOPROTOOPT; break; @@ -2650,7 +2709,6 @@ int sctp_inet_listen(struct socket *sock, int backlog) case SOCK_SEQPACKET: err = sctp_seqpacket_listen(sk, backlog); break; - case SOCK_STREAM: /* FIXME for TCP-style sockets. */ err = -EOPNOTSUPP; @@ -3038,7 +3096,8 @@ no_packet: } /* Verify that this is a valid address. */ -static int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, int len) +static inline int sctp_verify_addr(struct sock *sk, union sctp_addr *addr, + int len) { struct sctp_af *af; -- cgit v1.2.3 From 78f4b6b868f0e5bee37d896109fb772cc56e1550 Mon Sep 17 00:00:00 2001 From: Sridhar Samudrala Date: Wed, 5 Mar 2003 17:45:15 -0800 Subject: [SCTP] Minor changes for tcp-style socket support. --- include/net/sctp/constants.h | 21 +++++++++++++-------- net/sctp/sm_sideeffect.c | 16 +++++++++++----- net/sctp/socket.c | 10 ++++++++-- 3 files changed, 32 insertions(+), 15 deletions(-) (limited to 'include/net') diff --git a/include/net/sctp/constants.h b/include/net/sctp/constants.h index 3cc94d900f95..99a8a1deeadc 100644 --- a/include/net/sctp/constants.h +++ b/include/net/sctp/constants.h @@ -210,14 +210,19 @@ typedef enum { /* These are values for sk->state. * For a UDP-style SCTP socket, the states are defined as follows - * (at this point of time, may change later after more discussions: FIXME) - * A socket in SCTP_SS_UNCONNECTED state indicates that it is not willing - * to accept new associations, but it can initiate the creation of new - * ones. - * A socket in SCTP_SS_LISTENING state indicates that it is willing to - * accept new associations and can initiate the creation of new ones. - * A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off - * socket with one association. + * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to + * accept new associations, but it can initiate the creation of new ones. + * - A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations and can initiate the creation of new ones. + * - A socket in SCTP_SS_ESTABLISHED state indicates that it is a peeled off + * socket with one association. + * For a TCP-style SCTP socket, the states are defined as follows + * - A socket in SCTP_SS_CLOSED state indicates that it is not willing to + * accept new associations, but it can initiate the creation of new ones. + * - A socket in SCTP_SS_LISTENING state indicates that it is willing to + * accept new associations, but cannot initiate the creation of new ones. + * - A socket in SCTP_SS_ESTABLISHED state indicates that it has a single + * association in ESTABLISHED state. */ typedef enum { SCTP_SS_CLOSED = TCP_CLOSE, diff --git a/net/sctp/sm_sideeffect.c b/net/sctp/sm_sideeffect.c index 74c1eefb96d5..038eb5366f3c 100644 --- a/net/sctp/sm_sideeffect.c +++ b/net/sctp/sm_sideeffect.c @@ -105,8 +105,7 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *, sctp_association_t *, #define DEBUG_POST_SFX \ SCTP_DEBUG_PRINTK("sctp_do_sm post sfx: error %d, asoc %p[%s]\n", \ error, asoc, \ - sctp_state_tbl[sctp_id2assoc(ep->base.sk, \ - sctp_assoc2id(asoc))?asoc->state:SCTP_STATE_CLOSED]) + sctp_state_tbl[asoc?asoc->state:SCTP_STATE_CLOSED]) /* * This is the master state machine processing function. @@ -1239,12 +1238,19 @@ static void sctp_cmd_new_state(sctp_cmd_seq_t *cmds, sctp_association_t *asoc, 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 + * 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 + * For a UDP-style socket, the waiters are woken up by the * notifications. */ - if (sp->type != SCTP_SOCKET_UDP) + if (SCTP_SOCKET_UDP != sp->type) sk->state_change(sk); } + + /* Change the sk->state of a TCP-style socket that has sucessfully + * completed a connect() call. + */ + if ((SCTP_STATE_ESTABLISHED == asoc->state) && + (SCTP_SOCKET_TCP == sp->type) && (SCTP_SS_CLOSED == sk->state)) + sk->state = SCTP_SS_ESTABLISHED; } diff --git a/net/sctp/socket.c b/net/sctp/socket.c index dbf8be0cce5c..f5e5b2d7f281 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c @@ -1563,8 +1563,14 @@ SCTP_STATIC int sctp_connect(struct sock *sk, struct sockaddr *uaddr, sp = sctp_sk(sk); ep = sp->ep; - /* connect() cannot be done on a peeled-off socket. */ - if (SCTP_SOCKET_UDP_HIGH_BANDWIDTH == sp->type) { + /* connect() cannot be done on a socket that is already in ESTABLISHED + * state - UDP-style peeled off socket or a TCP-style socket that + * is already connected. + * It cannot be done even on a TCP-style listening socket. + */ + if ((SCTP_SS_ESTABLISHED == sk->state) || + ((SCTP_SOCKET_TCP == sp->type) && + (SCTP_SS_LISTENING == sk->state))) { err = -EISCONN; goto out_unlock; } -- cgit v1.2.3