Commit 372f525b authored by Jon Grimm's avatar Jon Grimm

SCTP: Resync with LKSCTP tree.

sctp: one more list_t removal.
sctp: more whitespace cleanup (jgrimm)
sctp: merge with linux bk tree
sctp: Minor ABORT updates (ardelle.fan)  
sctp: Fix misc. COOKIE-ECHO bundling bugs.  (jgrimm)

  There were small windows where the following could occur.
  -Two DATA chunks bundled with COOKIE-ECHO (only 1 allowed.)
  -DATA bundled with lost COOKIE-ECHO needs resent too.
  -DATA sent while in COOKIE-ECHOED if there had not been control data already bundled.

sctp:  more updates for abort (jgrimm and ardelle.fan)
  
  Cleanup T5 upon abort.   Send COMM_LOST notification to ULP upon abort.

sctp: updates to T5 shutdown timer.  (samudrala)
  
  I missed a couple changes from Sridhar's last patch.

sctp: more ABORT, cleanup shutdown timers (ardelle.fan)
  
  When we send or receive an ABORT, there may be a variety of timers running. 
  Turn these timers off when we abort.

sctp: Fix bug in COOKIE-ECHO retransmission.  (jgrimm)
    
  We had saved away the pointer directly to the INIT-ACK state cookie param, but upon COOKIE ECHO retransmission, this skb has already been thrown away.   The fix is to save away the cookie.

sctp:  Unknown chunk processing. (daisyc)
  
  Each chunkheader contains the chunk type.  
  For forward compatiblity, 'action' bits in the type describe what action 
  the peer requests if one does not understand that chunk type.  This patch is to
  implement the handling of those 'unrecognized chunk' actions.

sctp: Add T5 shutdown guard handling. (samudrala)
  
  The T5-shutdown-guard timer is used to bound the time we are willing to try gracefully shutting down.   This protects against certain pathological peers.

sctp: Add msg_name support for notifications and PF_INET sockets. (jgrimm)
parent cc8f2609
...@@ -112,6 +112,7 @@ typedef enum { ...@@ -112,6 +112,7 @@ typedef enum {
SCTP_EVENT_TIMEOUT_T2_SHUTDOWN, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN,
SCTP_EVENT_TIMEOUT_T3_RTX, SCTP_EVENT_TIMEOUT_T3_RTX,
SCTP_EVENT_TIMEOUT_T4_RTO, SCTP_EVENT_TIMEOUT_T4_RTO,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD,
SCTP_EVENT_TIMEOUT_HEARTBEAT, SCTP_EVENT_TIMEOUT_HEARTBEAT,
SCTP_EVENT_TIMEOUT_SACK, SCTP_EVENT_TIMEOUT_SACK,
SCTP_EVENT_TIMEOUT_AUTOCLOSE, SCTP_EVENT_TIMEOUT_AUTOCLOSE,
......
...@@ -114,7 +114,8 @@ extern sctp_protocol_t sctp_proto; ...@@ -114,7 +114,8 @@ extern sctp_protocol_t sctp_proto;
extern struct sock *sctp_get_ctl_sock(void); 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(sctp_protocol_t *, sctp_bind_addr_t *,
sctp_scope_t, int priority, int flags); sctp_scope_t, int priority, int flags);
extern sctp_pf_t *sctp_get_pf_specific(int family);
extern void sctp_set_pf_specific(int family, sctp_pf_t *);
/* /*
* sctp_socket.c * sctp_socket.c
......
...@@ -107,6 +107,9 @@ sctp_state_fn_t sctp_sf_timer_ignore; ...@@ -107,6 +107,9 @@ sctp_state_fn_t sctp_sf_timer_ignore;
sctp_state_fn_t sctp_sf_do_9_1_abort; sctp_state_fn_t sctp_sf_do_9_1_abort;
sctp_state_fn_t sctp_sf_cookie_wait_abort; sctp_state_fn_t sctp_sf_cookie_wait_abort;
sctp_state_fn_t sctp_sf_cookie_echoed_abort; sctp_state_fn_t sctp_sf_cookie_echoed_abort;
sctp_state_fn_t sctp_sf_shutdown_pending_abort;
sctp_state_fn_t sctp_sf_shutdown_sent_abort;
sctp_state_fn_t sctp_sf_shutdown_ack_sent_abort;
sctp_state_fn_t sctp_sf_do_5_1B_init; sctp_state_fn_t sctp_sf_do_5_1B_init;
sctp_state_fn_t sctp_sf_do_5_1C_ack; sctp_state_fn_t sctp_sf_do_5_1C_ack;
sctp_state_fn_t sctp_sf_do_5_1D_ce; sctp_state_fn_t sctp_sf_do_5_1D_ce;
...@@ -119,6 +122,7 @@ sctp_state_fn_t sctp_sf_tabort_8_4_8; ...@@ -119,6 +122,7 @@ sctp_state_fn_t sctp_sf_tabort_8_4_8;
sctp_state_fn_t sctp_sf_operr_notify; sctp_state_fn_t sctp_sf_operr_notify;
sctp_state_fn_t sctp_sf_t1_timer_expire; sctp_state_fn_t sctp_sf_t1_timer_expire;
sctp_state_fn_t sctp_sf_t2_timer_expire; sctp_state_fn_t sctp_sf_t2_timer_expire;
sctp_state_fn_t sctp_sf_t5_timer_expire;
sctp_state_fn_t sctp_sf_sendbeat_8_3; sctp_state_fn_t sctp_sf_sendbeat_8_3;
sctp_state_fn_t sctp_sf_beat_8_3; sctp_state_fn_t sctp_sf_beat_8_3;
sctp_state_fn_t sctp_sf_backbeat_8_3; sctp_state_fn_t sctp_sf_backbeat_8_3;
...@@ -134,6 +138,7 @@ sctp_state_fn_t sctp_sf_discard_chunk; ...@@ -134,6 +138,7 @@ sctp_state_fn_t sctp_sf_discard_chunk;
sctp_state_fn_t sctp_sf_do_5_2_1_siminit; sctp_state_fn_t sctp_sf_do_5_2_1_siminit;
sctp_state_fn_t sctp_sf_do_5_2_2_dupinit; sctp_state_fn_t sctp_sf_do_5_2_2_dupinit;
sctp_state_fn_t sctp_sf_do_5_2_4_dupcook; sctp_state_fn_t sctp_sf_do_5_2_4_dupcook;
sctp_state_fn_t sctp_sf_unk_chunk;
/* Prototypes for primitive event state functions. */ /* Prototypes for primitive event state functions. */
sctp_state_fn_t sctp_sf_do_prm_asoc; sctp_state_fn_t sctp_sf_do_prm_asoc;
...@@ -144,6 +149,9 @@ sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown; ...@@ -144,6 +149,9 @@ sctp_state_fn_t sctp_sf_cookie_echoed_prm_shutdown;
sctp_state_fn_t sctp_sf_do_9_1_prm_abort; sctp_state_fn_t sctp_sf_do_9_1_prm_abort;
sctp_state_fn_t sctp_sf_cookie_wait_prm_abort; sctp_state_fn_t sctp_sf_cookie_wait_prm_abort;
sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort; sctp_state_fn_t sctp_sf_cookie_echoed_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_pending_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_sent_prm_abort;
sctp_state_fn_t sctp_sf_shutdown_ack_sent_prm_abort;
sctp_state_fn_t sctp_sf_error_closed; sctp_state_fn_t sctp_sf_error_closed;
sctp_state_fn_t sctp_sf_error_shutdown; sctp_state_fn_t sctp_sf_error_shutdown;
sctp_state_fn_t sctp_sf_ignore_primitive; sctp_state_fn_t sctp_sf_ignore_primitive;
......
...@@ -255,6 +255,12 @@ typedef struct sctp_func { ...@@ -255,6 +255,12 @@ typedef struct sctp_func {
sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address); sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address);
/* Protocol family functions. */
typedef struct sctp_pf {
void (*event_msgname)(sctp_ulpevent_t *, char *, int *);
void (*skb_msgname)(struct sk_buff *, char *, int *);
} sctp_pf_t;
/* SCTP Socket type: UDP or TCP style. */ /* SCTP Socket type: UDP or TCP style. */
typedef enum { typedef enum {
SCTP_SOCKET_UDP = 0, SCTP_SOCKET_UDP = 0,
...@@ -280,6 +286,7 @@ struct sctp_opt { ...@@ -280,6 +286,7 @@ struct sctp_opt {
__u32 autoclose; __u32 autoclose;
__u8 nodelay; __u8 nodelay;
__u8 disable_fragments; __u8 disable_fragments;
sctp_pf_t *pf;
}; };
...@@ -845,6 +852,7 @@ int sctp_outqueue_set_output_handlers(sctp_outqueue_t *, ...@@ -845,6 +852,7 @@ int sctp_outqueue_set_output_handlers(sctp_outqueue_t *,
sctp_outqueue_ohandler_force_t force); sctp_outqueue_ohandler_force_t force);
void sctp_outqueue_restart(sctp_outqueue_t *); void sctp_outqueue_restart(sctp_outqueue_t *);
void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8); void sctp_retransmit(sctp_outqueue_t *, sctp_transport_t *, __u8);
void sctp_retransmit_mark(sctp_outqueue_t *, sctp_transport_t *, __u8);
/* These bind address data fields common between endpoints and associations */ /* These bind address data fields common between endpoints and associations */
...@@ -1128,6 +1136,11 @@ struct SCTP_association { ...@@ -1128,6 +1136,11 @@ struct SCTP_association {
*/ */
sctp_transport_t *primary_path; sctp_transport_t *primary_path;
/* Cache the primary path address here, when we
* need a an address for msg_name.
*/
sockaddr_storage_t primary_addr;
/* active_path /* active_path
* The path that we are currently using to * The path that we are currently using to
* transmit new data and most control chunks. * transmit new data and most control chunks.
...@@ -1183,7 +1196,7 @@ struct SCTP_association { ...@@ -1183,7 +1196,7 @@ struct SCTP_association {
int next_dup_tsn; int next_dup_tsn;
/* Do we need to sack the peer? */ /* Do we need to sack the peer? */
int sack_needed; uint8_t sack_needed;
/* These are capabilities which our peer advertised. */ /* These are capabilities which our peer advertised. */
__u8 ecn_capable; /* Can peer do ECN? */ __u8 ecn_capable; /* Can peer do ECN? */
......
...@@ -96,7 +96,7 @@ unsigned long update_adler32(unsigned long adler, ...@@ -96,7 +96,7 @@ unsigned long update_adler32(unsigned long adler,
* one subtract at the MOST, since buf[n] * one subtract at the MOST, since buf[n]
* is a max of 255. * is a max of 255.
*/ */
if(s1 >= BASE) if (s1 >= BASE)
s1 -= BASE; s1 -= BASE;
/* s2 = (s2 + s1) % BASE */ /* s2 = (s2 + s1) % BASE */
......
...@@ -288,7 +288,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc, ...@@ -288,7 +288,6 @@ sctp_association_t *sctp_association_init(sctp_association_t *asoc,
return NULL; return NULL;
} }
/* Free this association if possible. There may still be users, so /* Free this association if possible. There may still be users, so
* the actual deallocation may be delayed. * the actual deallocation may be delayed.
*/ */
...@@ -330,6 +329,11 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -330,6 +329,11 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
} }
/* Free peer's cached cookie. */
if (asoc->peer.cookie) {
kfree(asoc->peer.cookie);
}
/* Release the transport structures. */ /* Release the transport structures. */
list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) {
transport = list_entry(pos, sctp_transport_t, transports); transport = list_entry(pos, sctp_transport_t, transports);
...@@ -342,7 +346,6 @@ void sctp_association_free(sctp_association_t *asoc) ...@@ -342,7 +346,6 @@ void sctp_association_free(sctp_association_t *asoc)
sctp_association_put(asoc); sctp_association_put(asoc);
} }
/* Cleanup and free up an association. */ /* Cleanup and free up an association. */
static void sctp_association_destroy(sctp_association_t *asoc) static void sctp_association_destroy(sctp_association_t *asoc)
{ {
...@@ -387,8 +390,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -387,8 +390,7 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
asoc->peer.port = *port; asoc->peer.port = *port;
} }
SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", SCTP_ASSERT(*port == asoc->peer.port, ":Invalid port\n", return NULL);
return NULL);
/* Check to see if this is a duplicate. */ /* Check to see if this is a duplicate. */
peer = sctp_assoc_lookup_paddr(asoc, addr); peer = sctp_assoc_lookup_paddr(asoc, addr);
...@@ -464,6 +466,16 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc, ...@@ -464,6 +466,16 @@ sctp_transport_t *sctp_assoc_add_peer(sctp_association_t *asoc,
/* Attach the remote transport to our asoc. */ /* Attach the remote transport to our asoc. */
list_add_tail(&peer->transports, &asoc->peer.transport_addr_list); list_add_tail(&peer->transports, &asoc->peer.transport_addr_list);
/* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) {
asoc->peer.primary_path = peer;
/* Set a default msg_name for events. */
memcpy(&asoc->peer.primary_addr, &peer->ipaddr,
sizeof(sockaddr_storage_t));
asoc->peer.active_path = peer;
asoc->peer.retran_path = peer;
}
/* If we do not yet have a primary path, set one. */ /* If we do not yet have a primary path, set one. */
if (NULL == asoc->peer.primary_path) { if (NULL == asoc->peer.primary_path) {
asoc->peer.primary_path = peer; asoc->peer.primary_path = peer;
......
...@@ -198,6 +198,7 @@ static const char *sctp_timer_tbl[] = { ...@@ -198,6 +198,7 @@ static const char *sctp_timer_tbl[] = {
"TIMEOUT_T2_SHUTDOWN", "TIMEOUT_T2_SHUTDOWN",
"TIMEOUT_T3_RTX", "TIMEOUT_T3_RTX",
"TIMEOUT_T4_RTO", "TIMEOUT_T4_RTO",
"TIMEOUT_T5_SHUTDOWN_GUARD",
"TIMEOUT_HEARTBEAT", "TIMEOUT_HEARTBEAT",
"TIMEOUT_SACK", "TIMEOUT_SACK",
"TIMEOUT_AUTOCLOSE", "TIMEOUT_AUTOCLOSE",
......
...@@ -92,6 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto, ...@@ -92,6 +92,7 @@ sctp_endpoint_t *sctp_endpoint_new(sctp_protocol_t *proto,
sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
struct sock *sk, int priority) struct sock *sk, int priority)
{ {
sctp_opt_t *sp = sctp_sk(sk);
memset(ep, 0, sizeof(sctp_endpoint_t)); memset(ep, 0, sizeof(sctp_endpoint_t));
/* Initialize the base structure. */ /* Initialize the base structure. */
...@@ -129,22 +130,30 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto, ...@@ -129,22 +130,30 @@ sctp_endpoint_t *sctp_endpoint_init(sctp_endpoint_t *ep, sctp_protocol_t *proto,
/* Set up the base timeout information. */ /* Set up the base timeout information. */
ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_NONE] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] ep->timeouts[SCTP_EVENT_TIMEOUT_T1_COOKIE] =
= SCTP_DEFAULT_TIMEOUT_T1_COOKIE; SCTP_DEFAULT_TIMEOUT_T1_COOKIE;
ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] ep->timeouts[SCTP_EVENT_TIMEOUT_T1_INIT] =
= SCTP_DEFAULT_TIMEOUT_T1_INIT; SCTP_DEFAULT_TIMEOUT_T1_INIT;
ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] ep->timeouts[SCTP_EVENT_TIMEOUT_T2_SHUTDOWN] =
= sctp_sk(sk)->rtoinfo.srto_initial; sp->rtoinfo.srto_initial;
ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T3_RTX] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0; ep->timeouts[SCTP_EVENT_TIMEOUT_T4_RTO] = 0;
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT]
= SCTP_DEFAULT_TIMEOUT_HEARTBEAT; /* sctpimpguide-05 Section 2.12.2
ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] * If the 'T5-shutdown-guard' timer is used, it SHOULD be set to the
= SCTP_DEFAULT_TIMEOUT_SACK; * recommended value of 5 times 'RTO.Max'.
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] */
= sctp_sk(sk)->autoclose * HZ; ep->timeouts[SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD]
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] = 5 * sp->rtoinfo.srto_max;
= SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
ep->timeouts[SCTP_EVENT_TIMEOUT_HEARTBEAT] =
SCTP_DEFAULT_TIMEOUT_HEARTBEAT;
ep->timeouts[SCTP_EVENT_TIMEOUT_SACK] =
SCTP_DEFAULT_TIMEOUT_SACK;
ep->timeouts[SCTP_EVENT_TIMEOUT_AUTOCLOSE] =
sp->autoclose * HZ;
ep->timeouts[SCTP_EVENT_TIMEOUT_PMTU_RAISE] =
SCTP_DEFAULT_TIMEOUT_PMTU_RAISE;
/* Set up the default send/receive buffer space. */ /* Set up the default send/receive buffer space. */
...@@ -251,7 +260,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep, ...@@ -251,7 +260,8 @@ sctp_endpoint_t *sctp_endpoint_is_match(sctp_endpoint_t *ep,
* We do a linear search of the associations for this endpoint. * We do a linear search of the associations for this endpoint.
* We return the matching transport address too. * We return the matching transport address too.
*/ */
sctp_association_t *__sctp_endpoint_lookup_assoc(const sctp_endpoint_t *endpoint, sctp_association_t *__sctp_endpoint_lookup_assoc(
const sctp_endpoint_t *endpoint,
const sockaddr_storage_t *paddr, const sockaddr_storage_t *paddr,
sctp_transport_t **transport) sctp_transport_t **transport)
{ {
...@@ -360,10 +370,5 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep) ...@@ -360,10 +370,5 @@ static void sctp_endpoint_bh_rcv(sctp_endpoint_t *ep)
/* Is this the right way to pass errors up to the ULP? */ /* Is this the right way to pass errors up to the ULP? */
if (error) if (error)
ep->base.sk->err = -error; ep->base.sk->err = -error;
out: out:
} }
...@@ -189,6 +189,80 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -189,6 +189,80 @@ int sctp_v6_get_dst_mtu(const sockaddr_storage_t *address)
return dst_mtu; return dst_mtu;
} }
/* Initialize a PF_INET6 socket msg_name. */
static void sctp_inet6_msgname(char *msgname, int *addr_len)
{
struct sockaddr_in6 *sin6;
sin6 = (struct sockaddr_in6 *)msgname;
sin6->sin6_family = AF_INET6;
sin6->sin6_flowinfo = 0;
sin6->sin6_scope_id = 0;
*addr_len = sizeof(struct sockaddr_in6);
}
/* Initialize a PF_INET msgname from a ulpevent. */
static void sctp_inet6_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addrlen)
{
struct sockaddr_in6 *sin6, *sin6from;
if (msgname) {
sockaddr_storage_t *addr;
sctp_inet6_msgname(msgname, addrlen);
sin6 = (struct sockaddr_in6 *)msgname;
sin6->sin6_port = htons(event->asoc->peer.port);
addr = &event->asoc->peer.primary_addr;
/* Note: If we go to a common v6 format, this code
* will change.
*/
/* Map ipv4 address into v4-mapped-on-v6 address. */
if (AF_INET == addr->sa.sa_family) {
/* FIXME: Easy, but there was no way to test this
* yet.
*/
return;
}
sin6from = &event->asoc->peer.primary_addr.v6;
ipv6_addr_copy(&sin6->sin6_addr, &sin6from->sin6_addr);
}
}
/* Initialize a msg_name from an inbound skb. */
static void sctp_inet6_skb_msgname(struct sk_buff *skb, char *msgname,
int *addr_len)
{
struct sctphdr *sh;
struct sockaddr_in6 *sin6;
if (msgname) {
sctp_inet6_msgname(msgname, addr_len);
sin6 = (struct sockaddr_in6 *)msgname;
sh = (struct sctphdr *)skb->h.raw;
sin6->sin6_port = sh->source;
/* FIXME: Map ipv4 address into v4-mapped-on-v6 address. */
if (__constant_htons(ETH_P_IP) == skb->protocol) {
/* FIXME: Easy, but there was no way to test this
* yet.
*/
return;
}
/* Otherwise, just copy the v6 address. */
ipv6_addr_copy(&sin6->sin6_addr, &skb->nh.ipv6h->saddr);
if (ipv6_addr_type(&sin6->sin6_addr) & IPV6_ADDR_LINKLOCAL) {
struct inet6_skb_parm *opt =
(struct inet6_skb_parm *) skb->cb;
sin6->sin6_scope_id = opt->iif;
}
}
}
static struct proto_ops inet6_seqpacket_ops = { static struct proto_ops inet6_seqpacket_ops = {
.family = PF_INET6, .family = PF_INET6,
.release = inet6_release, .release = inet6_release,
...@@ -238,15 +312,22 @@ static sctp_func_t sctp_ipv6_specific = { ...@@ -238,15 +312,22 @@ static sctp_func_t sctp_ipv6_specific = {
.sa_family = AF_INET6, .sa_family = AF_INET6,
}; };
static sctp_pf_t sctp_pf_inet6_specific = {
.event_msgname = sctp_inet6_event_msgname,
.skb_msgname = sctp_inet6_skb_msgname,
};
/* Initialize IPv6 support and register with inet6 stack. */ /* Initialize IPv6 support and register with inet6 stack. */
int sctp_v6_init(void) int sctp_v6_init(void)
{ {
/* Add SCTPv6 to inetsw6 linked list. */ /* Add SCTPv6 to inetsw6 linked list. */
inet6_register_protosw(&sctpv6_protosw); inet6_register_protosw(&sctpv6_protosw);
/* Register inet6 protocol. */ /* Register inet6 protocol. */
inet6_add_protocol(&sctpv6_protocol); inet6_add_protocol(&sctpv6_protocol);
/* Register the SCTP specfic PF_INET6 functions. */
sctp_set_pf_specific(PF_INET6, &sctp_pf_inet6_specific);
/* Fill in address family info. */ /* Fill in address family info. */
INIT_LIST_HEAD(&sctp_ipv6_specific.list); INIT_LIST_HEAD(&sctp_ipv6_specific.list);
list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families); list_add_tail(&sctp_ipv6_specific.list, &sctp_proto.address_families);
......
...@@ -129,7 +129,8 @@ void sctp_packet_free(sctp_packet_t *packet) ...@@ -129,7 +129,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 * 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. * 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(sctp_packet_t *packet,
sctp_chunk_t *chunk)
{ {
sctp_xmit_t retval; sctp_xmit_t retval;
int error = 0; int error = 0;
...@@ -181,8 +182,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -181,8 +182,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
/* Both control chunks and data chunks with TSNs are /* Both control chunks and data chunks with TSNs are
* non-fragmentable. * non-fragmentable.
*/ */
int fragmentable = sctp_chunk_is_data(chunk) int fragmentable = sctp_chunk_is_data(chunk) &&
&& (!chunk->has_tsn); (!chunk->has_tsn);
if (packet_empty) { if (packet_empty) {
if (fragmentable) { if (fragmentable) {
retval = SCTP_XMIT_MUST_FRAG; retval = SCTP_XMIT_MUST_FRAG;
...@@ -221,10 +222,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk) ...@@ -221,10 +222,8 @@ sctp_xmit_t sctp_packet_append_chunk(sctp_packet_t *packet, sctp_chunk_t *chunk)
} }
/* It is OK to send this chunk. */ /* It is OK to send this chunk. */
skb_queue_tail(&packet->chunks, skb_queue_tail(&packet->chunks, (struct sk_buff *)chunk);
(struct sk_buff *)chunk);
packet->size += chunk_len; packet->size += chunk_len;
finish: finish:
return retval; return retval;
} }
...@@ -337,7 +336,7 @@ int sctp_packet_transmit(sctp_packet_t *packet) ...@@ -337,7 +336,7 @@ int sctp_packet_transmit(sctp_packet_t *packet)
} }
/* Build the SCTP header. */ /* Build the SCTP header. */
sh = (struct sctphdr *) skb_push(nskb, sizeof(struct sctphdr)); sh = (struct sctphdr *)skb_push(nskb, sizeof(struct sctphdr));
sh->source = htons(packet->source_port); sh->source = htons(packet->source_port);
sh->dest = htons(packet->destination_port); sh->dest = htons(packet->destination_port);
...@@ -467,7 +466,8 @@ static void sctp_packet_reset(sctp_packet_t *packet) ...@@ -467,7 +466,8 @@ static void sctp_packet_reset(sctp_packet_t *packet)
} }
/* This private function handles the specifics of appending DATA chunks. */ /* 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(sctp_packet_t *packet,
sctp_chunk_t *chunk)
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
size_t datasize, rwnd, inflight; size_t datasize, rwnd, inflight;
...@@ -502,12 +502,13 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t * ...@@ -502,12 +502,13 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *
} }
} }
/* sctpimpguide-05 2.14.2 D) When the time comes for the sender to /* sctpimpguide-05 2.14.2
* D) When the time comes for the sender to
* transmit new DATA chunks, the protocol parameter Max.Burst MUST * transmit new DATA chunks, the protocol parameter Max.Burst MUST
* first be applied to limit how many new DATA chunks may be sent. * first be applied to limit how many new DATA chunks may be sent.
* The limit is applied by adjusting cwnd as follows: * The limit is applied by adjusting cwnd as follows:
* if((flightsize + Max.Burst*MTU) < cwnd) * if ((flightsize + Max.Burst * MTU) < cwnd)
* cwnd = flightsize + Max.Burst*MTU * cwnd = flightsize + Max.Burst * MTU
*/ */
max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu; max_burst_bytes = transport->asoc->max_burst * transport->asoc->pmtu;
if ((transport->flight_size + max_burst_bytes) < transport->cwnd) { if ((transport->flight_size + max_burst_bytes) < transport->cwnd) {
...@@ -552,7 +553,3 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t * ...@@ -552,7 +553,3 @@ static sctp_xmit_t sctp_packet_append_data(sctp_packet_t *packet, sctp_chunk_t *
finish: finish:
return retval; return retval;
} }
...@@ -196,23 +196,14 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk) ...@@ -196,23 +196,14 @@ int sctp_push_outqueue(sctp_outqueue_t *q, sctp_chunk_t *chunk)
return error; return error;
} }
/* Mark all the eligible packets on a transport for retransmission and force /* Mark all the eligible packets on a transport for retransmission. */
* one packet out. void sctp_retransmit_mark(sctp_outqueue_t *q, sctp_transport_t *transport,
*/
void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit) __u8 fast_retransmit)
{ {
struct list_head *lchunk; struct list_head *lchunk;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
int error = 0;
struct list_head tlist; struct list_head tlist;
if (fast_retransmit) {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
} else {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
}
INIT_LIST_HEAD(&tlist); INIT_LIST_HEAD(&tlist);
while (!list_empty(&transport->transmitted)) { while (!list_empty(&transport->transmitted)) {
...@@ -276,7 +267,26 @@ void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport, ...@@ -276,7 +267,26 @@ void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
transport->flight_size, transport->flight_size,
transport->partial_bytes_acked); transport->partial_bytes_acked);
}
/* Mark all the eligible packets on a transport for retransmission and force
* one packet out.
*/
void sctp_retransmit(sctp_outqueue_t *q, sctp_transport_t *transport,
__u8 fast_retransmit)
{
int error = 0;
if (fast_retransmit) {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_FAST_RTX);
} else {
sctp_transport_lower_cwnd(transport, SCTP_LOWER_CWND_T3_RTX);
}
sctp_retransmit_mark(q, transport, fast_retransmit);
error = sctp_flush_outqueue(q, /* rtx_timeout */ 1); error = sctp_flush_outqueue(q, /* rtx_timeout */ 1);
if (error) if (error)
q->asoc->base.sk->err = -error; q->asoc->base.sk->err = -error;
} }
...@@ -370,8 +380,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, ...@@ -370,8 +380,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
/* The append was successful, so add this chunk to /* The append was successful, so add this chunk to
* the transmitted list. * the transmitted list.
*/ */
list_add_tail(lchunk, list_add_tail(lchunk, &transport->transmitted);
&transport->transmitted);
*start_timer = 1; *start_timer = 1;
q->empty = 0; q->empty = 0;
...@@ -389,8 +398,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt, ...@@ -389,8 +398,7 @@ static int sctp_flush_retran_queue(sctp_outqueue_t *q, sctp_packet_t *pkt,
* chunk that is currently in the process of fragmentation. * chunk that is currently in the process of fragmentation.
*/ */
void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos, void sctp_xmit_frag(sctp_outqueue_t *q, struct sk_buff *pos,
sctp_packet_t *packet, sctp_packet_t *packet, sctp_chunk_t *frag, __u32 tsn)
sctp_chunk_t *frag, __u32 tsn)
{ {
sctp_transport_t *transport = packet->transport; sctp_transport_t *transport = packet->transport;
struct sk_buff_head *queue = &q->out; struct sk_buff_head *queue = &q->out;
...@@ -499,7 +507,8 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet, ...@@ -499,7 +507,8 @@ void sctp_xmit_fragmented_chunks(sctp_outqueue_t *q, sctp_packet_t *packet,
* fragments. It returns the first fragment with the frag_list field holding * fragments. It returns the first fragment with the frag_list field holding
* the remaining fragments. * the remaining fragments.
*/ */
sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk,
size_t max_frag_data_len)
{ {
sctp_association_t *asoc = chunk->asoc; sctp_association_t *asoc = chunk->asoc;
void *data_ptr = chunk->subh.data_hdr; void *data_ptr = chunk->subh.data_hdr;
...@@ -533,11 +542,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len) ...@@ -533,11 +542,14 @@ sctp_chunk_t *sctp_fragment_chunk(sctp_chunk_t *chunk, size_t max_frag_data_len)
/* Make the middle fragments. */ /* Make the middle fragments. */
while (chunk_data_len > max_frag_data_len) { while (chunk_data_len > max_frag_data_len) {
frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len, frag = sctp_make_datafrag(asoc, sinfo, max_frag_data_len,
data_ptr, SCTP_DATA_MIDDLE_FRAG, ssn); data_ptr, SCTP_DATA_MIDDLE_FRAG,
ssn);
if (!frag) if (!frag)
goto err; goto err;
/* Add the middle fragment to the first fragment's frag_list. */ /* Add the middle fragment to the first fragment's
* frag_list.
*/
list_add_tail(&frag->frag_list, frag_list); list_add_tail(&frag->frag_list, frag_list);
chunk_data_len -= max_frag_data_len; chunk_data_len -= max_frag_data_len;
...@@ -674,7 +686,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -674,7 +686,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
(void) (*q->build_output)(&singleton, chunk); (void) (*q->build_output)(&singleton, chunk);
error = (*q->force_output)(&singleton); error = (*q->force_output)(&singleton);
if (error < 0) if (error < 0)
return(error); return error;
break; break;
case SCTP_CID_ABORT: case SCTP_CID_ABORT:
...@@ -705,10 +717,10 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -705,10 +717,10 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
/* Is it OK to send data chunks? */ /* Is it OK to send data chunks? */
switch (asoc->state) { switch (asoc->state) {
case SCTP_STATE_COOKIE_ECHOED: case SCTP_STATE_COOKIE_ECHOED:
/* Only allow bundling, if this packet has a COOKIE-ECHO /* Only allow bundling when this packet has a COOKIE-ECHO
* chunk. * chunk.
*/ */
if (packet && !packet->has_cookie_echo) if (!packet || !packet->has_cookie_echo)
break; break;
/* fallthru */ /* fallthru */
...@@ -748,6 +760,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -748,6 +760,12 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
if (start_timer) if (start_timer)
sctp_transport_reset_timers(transport); sctp_transport_reset_timers(transport);
/* This can happen on COOKIE-ECHO resend. Only
* one chunk can get bundled with a COOKIE-ECHO.
*/
if (packet->has_cookie_echo)
goto sctp_flush_out;
} }
/* Finally, transmit new packets. */ /* Finally, transmit new packets. */
...@@ -813,8 +831,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -813,8 +831,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
ntohl(chunk->subh.data_hdr->tsn), ntohl(chunk->subh.data_hdr->tsn),
chunk->skb ?chunk->skb->head : 0, chunk->skb ?chunk->skb->head : 0,
chunk->skb ? chunk->skb ?
atomic_read(&chunk->skb->users) : atomic_read(&chunk->skb->users) : -1);
-1);
/* Add the chunk to the packet. */ /* Add the chunk to the packet. */
status = (*q->build_output)(packet, chunk); status = (*q->build_output)(packet, chunk);
...@@ -827,7 +844,8 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -827,7 +844,8 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
*/ */
SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could" SCTP_DEBUG_PRINTK("sctp_flush_outqueue: could"
"not transmit TSN: 0x%x, status: %d\n", "not transmit TSN: 0x%x, status: %d\n",
ntohl(chunk->subh.data_hdr->tsn), status); ntohl(chunk->subh.data_hdr->tsn),
status);
skb_queue_head(queue, (struct sk_buff *)chunk); skb_queue_head(queue, (struct sk_buff *)chunk);
goto sctp_flush_out; goto sctp_flush_out;
break; break;
...@@ -857,7 +875,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -857,7 +875,7 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
default: default:
BUG(); BUG();
}; }
/* BUG: We assume that the (*q->force_output()) /* BUG: We assume that the (*q->force_output())
* call below will succeed all the time and add the * call below will succeed all the time and add the
...@@ -875,13 +893,19 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout) ...@@ -875,13 +893,19 @@ int sctp_flush_outqueue(sctp_outqueue_t *q, int rtx_timeout)
sctp_transport_reset_timers(transport); sctp_transport_reset_timers(transport);
q->empty = 0; q->empty = 0;
/* Only let one DATA chunk get bundled with a
* COOKIE-ECHO chunk.
*/
if (packet->has_cookie_echo)
goto sctp_flush_out;
} }
break; break;
default: default:
/* Do nothing. */ /* Do nothing. */
break; break;
}; }
sctp_flush_out: sctp_flush_out:
/* Before returning, examine all the transports touched in /* Before returning, examine all the transports touched in
...@@ -986,8 +1010,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack) ...@@ -986,8 +1010,7 @@ int sctp_sack_outqueue(sctp_outqueue_t *q, sctp_sackhdr_t *sack)
ctsn = q->asoc->ctsn_ack_point; ctsn = q->asoc->ctsn_ack_point;
SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n", SCTP_DEBUG_PRINTK("%s: sack Cumulative TSN Ack is 0x%x.\n",
__FUNCTION__, __FUNCTION__, sack_ctsn);
sack_ctsn);
SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association " SCTP_DEBUG_PRINTK("%s: Cumulative TSN Ack of association "
"%p is 0x%x.\n", __FUNCTION__, q->asoc, ctsn); "%p is 0x%x.\n", __FUNCTION__, q->asoc, ctsn);
...@@ -1114,8 +1137,9 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1114,8 +1137,9 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 6.3.1 C5) Karn's algorithm: RTT measurements * 6.3.1 C5) Karn's algorithm: RTT measurements
* MUST NOT be made using packets that were * MUST NOT be made using packets that were
* retransmitted (and thus for which it is * retransmitted (and thus for which it is
* ambiguous whether the reply was for the first * ambiguous whether the reply was for the
* instance of the packet or a later instance). * first instance of the packet or a later
* instance).
*/ */
if ((!tchunk->tsn_gap_acked) && if ((!tchunk->tsn_gap_acked) &&
(1 == tchunk->num_times_sent) && (1 == tchunk->num_times_sent) &&
...@@ -1150,15 +1174,15 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1150,15 +1174,15 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* 'Stray DATA chunk(s)' record the highest TSN * 'Stray DATA chunk(s)' record the highest TSN
* reported as newly acknowledged, call this * reported as newly acknowledged, call this
* value 'HighestTSNinSack'. A newly * value 'HighestTSNinSack'. A newly
* acknowledged DATA chunk is one not previously * acknowledged DATA chunk is one not
* acknowledged in a SACK. * previously acknowledged in a SACK.
* *
* When the SCTP sender of data receives a SACK * When the SCTP sender of data receives a SACK
* chunk that acknowledges, for the first time, * chunk that acknowledges, for the first time,
* the receipt of a DATA chunk, all the still * the receipt of a DATA chunk, all the still
* unacknowledged DATA chunks whose TSN is older * unacknowledged DATA chunks whose TSN is
* than that newly acknowledged DATA chunk, are * older than that newly acknowledged DATA
* qualified as 'Stray DATA chunks'. * chunk, are qualified as 'Stray DATA chunks'.
*/ */
if (!tchunk->tsn_gap_acked) { if (!tchunk->tsn_gap_acked) {
tchunk->tsn_gap_acked = 1; tchunk->tsn_gap_acked = 1;
...@@ -1217,8 +1241,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1217,8 +1241,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
} else { } else {
if (tchunk->tsn_gap_acked) { if (tchunk->tsn_gap_acked) {
SCTP_DEBUG_PRINTK("%s: Receiver reneged on data " SCTP_DEBUG_PRINTK("%s: Receiver reneged on "
"TSN: 0x%x\n", "data TSN: 0x%x\n",
__FUNCTION__, __FUNCTION__,
tsn); tsn);
tchunk->tsn_gap_acked = 0; tchunk->tsn_gap_acked = 0;
...@@ -1227,10 +1251,11 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1227,10 +1251,11 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
/* RFC 2960 6.3.2 Retransmission Timer Rules /* RFC 2960 6.3.2 Retransmission Timer Rules
* *
* R4) Whenever a SACK is received missing a TSN * R4) Whenever a SACK is received missing a
* that was previously acknowledged via a Gap Ack * TSN that was previously acknowledged via a
* Block, start T3-rtx for the destination * Gap Ack Block, start T3-rtx for the
* address to which the DATA chunk was originally * destination address to which the DATA
* chunk was originally
* transmitted if it is not already running. * transmitted if it is not already running.
*/ */
restart_timer = 1; restart_timer = 1;
...@@ -1306,7 +1331,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1306,7 +1331,8 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
* active if it is not so marked. * active if it is not so marked.
*/ */
if (!transport->state.active) { if (!transport->state.active) {
sctp_assoc_control_transport(transport->asoc, sctp_assoc_control_transport(
transport->asoc,
transport, transport,
SCTP_TRANSPORT_UP, SCTP_TRANSPORT_UP,
SCTP_RECEIVED_SACK); SCTP_RECEIVED_SACK);
...@@ -1398,8 +1424,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q, ...@@ -1398,8 +1424,7 @@ static void sctp_check_transmitted(sctp_outqueue_t *q,
SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, " SCTP_DEBUG_PRINTK("%s: transport: %p, cwnd: %d, "
"ssthresh: %d, flight_size: %d, pba: %d\n", "ssthresh: %d, flight_size: %d, pba: %d\n",
__FUNCTION__, __FUNCTION__, transport, transport->cwnd,
transport, transport->cwnd,
transport->ssthresh, transport->flight_size, transport->ssthresh, transport->flight_size,
transport->partial_bytes_acked); transport->partial_bytes_acked);
} }
......
...@@ -66,6 +66,9 @@ struct proc_dir_entry *proc_net_sctp; ...@@ -66,6 +66,9 @@ struct proc_dir_entry *proc_net_sctp;
*/ */
static struct socket *sctp_ctl_socket; static struct socket *sctp_ctl_socket;
static sctp_pf_t *sctp_pf_inet6_specific;
static sctp_pf_t *sctp_pf_inet_specific;
extern struct net_proto_family inet_family_ops; extern struct net_proto_family inet_family_ops;
/* Return the address of the control sock. */ /* Return the address of the control sock. */
...@@ -91,7 +94,7 @@ void sctp_proc_init(void) ...@@ -91,7 +94,7 @@ void sctp_proc_init(void)
void sctp_proc_exit(void) void sctp_proc_exit(void)
{ {
if (proc_net_sctp) { if (proc_net_sctp) {
proc_net_sctp= NULL; proc_net_sctp = NULL;
remove_proc_entry("net/sctp", 0); remove_proc_entry("net/sctp", 0);
} }
} }
...@@ -135,7 +138,8 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto, ...@@ -135,7 +138,8 @@ static inline void sctp_v4_get_local_addr_list(sctp_protocol_t *proto,
* the protocol structure. * the protocol structure.
* FIXME: Make this an address family function. * FIXME: Make this an address family function.
*/ */
static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto, struct net_device *dev) static inline void sctp_v6_get_local_addr_list(sctp_protocol_t *proto,
struct net_device *dev)
{ {
#ifdef SCTP_V6_SUPPORT #ifdef SCTP_V6_SUPPORT
/* FIXME: The testframe doesn't support this function. */ /* FIXME: The testframe doesn't support this function. */
...@@ -239,8 +243,7 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp, ...@@ -239,8 +243,7 @@ int sctp_copy_local_addr_list(sctp_protocol_t *proto, sctp_bind_addr_t *bp,
(((AF_INET6 == addr->a.sa.sa_family) && (((AF_INET6 == addr->a.sa.sa_family) &&
(copy_flags & SCTP_ADDR6_ALLOWED) && (copy_flags & SCTP_ADDR6_ALLOWED) &&
(copy_flags & SCTP_ADDR6_PEERSUPP)))) { (copy_flags & SCTP_ADDR6_PEERSUPP)))) {
error = sctp_add_bind_addr(bp, error = sctp_add_bind_addr(bp, &addr->a,
&addr->a,
priority); priority);
if (error) if (error)
goto end_copy; goto end_copy;
...@@ -286,7 +289,8 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address) ...@@ -286,7 +289,8 @@ int sctp_v4_get_dst_mtu(const sockaddr_storage_t *address)
/* Event handler for inet device events. /* Event handler for inet device 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.
*/ */
static int sctp_netdev_event(struct notifier_block *this, unsigned long event, void *ptr) static int sctp_netdev_event(struct notifier_block *this, unsigned long event,
void *ptr)
{ {
long flags __attribute__ ((unused)); long flags __attribute__ ((unused));
...@@ -347,6 +351,52 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address) ...@@ -347,6 +351,52 @@ sctp_func_t *sctp_get_af_specific(const sockaddr_storage_t *address)
return retval; return retval;
} }
/* Common code to initialize a AF_INET msg_name. */
static void sctp_inet_msgname(char *msgname, int *addr_len)
{
struct sockaddr_in *sin;
sin = (struct sockaddr_in *)msgname;
*addr_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
}
/* Copy the primary address of the peer primary address as the msg_name. */
static void sctp_inet_event_msgname(sctp_ulpevent_t *event, char *msgname, int *addr_len)
{
struct sockaddr_in *sin, *sinfrom;
if (msgname) {
sctp_inet_msgname(msgname, addr_len);
sin = (struct sockaddr_in *)msgname;
sinfrom = &event->asoc->peer.primary_addr.v4;
sin->sin_port = htons(event->asoc->peer.port);
sin->sin_addr.s_addr = sinfrom->sin_addr.s_addr;
}
}
/* Initialize and copy out a msgname from an inbound skb. */
static void sctp_inet_skb_msgname(struct sk_buff *skb, char *msgname, int *addr_len)
{
struct sctphdr *sh;
struct sockaddr_in *sin;
if (msgname) {
sctp_inet_msgname(msgname, addr_len);
sin = (struct sockaddr_in *)msgname;
sh = (struct sctphdr *)skb->h.raw;
sin->sin_port = sh->source;
sin->sin_addr.s_addr = skb->nh.iph->saddr;
}
}
static sctp_pf_t sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname,
.skb_msgname = sctp_inet_skb_msgname,
};
/* Registration for netdev events. */ /* Registration for netdev events. */
struct notifier_block sctp_netdev_notifier = { struct notifier_block sctp_netdev_notifier = {
.notifier_call = sctp_netdev_event, .notifier_call = sctp_netdev_event,
...@@ -403,6 +453,34 @@ sctp_func_t sctp_ipv4_specific = { ...@@ -403,6 +453,34 @@ sctp_func_t sctp_ipv4_specific = {
.sa_family = AF_INET, .sa_family = AF_INET,
}; };
sctp_pf_t *sctp_get_pf_specific(int family) {
switch (family) {
case PF_INET:
return sctp_pf_inet_specific;
case PF_INET6:
return sctp_pf_inet6_specific;
default:
return NULL;
}
}
/* Set the PF specific function table. */
void sctp_set_pf_specific(int family, sctp_pf_t *pf)
{
switch (family) {
case PF_INET:
sctp_pf_inet_specific = pf;
break;
case PF_INET6:
sctp_pf_inet6_specific = pf;
break;
default:
BUG();
break;
}
}
/* Initialize the universe into something sensible. */ /* Initialize the universe into something sensible. */
int sctp_init(void) int sctp_init(void)
{ {
...@@ -421,6 +499,8 @@ int sctp_init(void) ...@@ -421,6 +499,8 @@ int sctp_init(void)
/* Initialize object count debugging. */ /* Initialize object count debugging. */
sctp_dbg_objcnt_init(); sctp_dbg_objcnt_init();
/* Initialize the SCTP specific PF functions. */
sctp_set_pf_specific(PF_INET, &sctp_pf_inet);
/* /*
* 14. Suggested SCTP Protocol Parameter Values * 14. Suggested SCTP Protocol Parameter Values
*/ */
...@@ -468,7 +548,7 @@ int sctp_init(void) ...@@ -468,7 +548,7 @@ int sctp_init(void)
sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *) sctp_proto.assoc_hashbucket = (sctp_hashbucket_t *)
kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.assoc_hashbucket) { if (!sctp_proto.assoc_hashbucket) {
printk (KERN_ERR "SCTP: Failed association hash alloc.\n"); printk(KERN_ERR "SCTP: Failed association hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ahash_alloc; goto err_ahash_alloc;
} }
...@@ -482,7 +562,7 @@ int sctp_init(void) ...@@ -482,7 +562,7 @@ int sctp_init(void)
sctp_proto.ep_hashbucket = (sctp_hashbucket_t *) sctp_proto.ep_hashbucket = (sctp_hashbucket_t *)
kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL); kmalloc(64 * sizeof(sctp_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.ep_hashbucket) { if (!sctp_proto.ep_hashbucket) {
printk (KERN_ERR "SCTP: Failed endpoint_hash alloc.\n"); printk(KERN_ERR "SCTP: Failed endpoint_hash alloc.\n");
status = -ENOMEM; status = -ENOMEM;
goto err_ehash_alloc; goto err_ehash_alloc;
} }
...@@ -497,7 +577,7 @@ int sctp_init(void) ...@@ -497,7 +577,7 @@ int sctp_init(void)
sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *) sctp_proto.port_hashtable = (sctp_bind_hashbucket_t *)
kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL); kmalloc(4096 * sizeof(sctp_bind_hashbucket_t), GFP_KERNEL);
if (!sctp_proto.port_hashtable) { if (!sctp_proto.port_hashtable) {
printk (KERN_ERR "SCTP: Failed bind hash alloc."); printk(KERN_ERR "SCTP: Failed bind hash alloc.");
status = -ENOMEM; status = -ENOMEM;
goto err_bhash_alloc; goto err_bhash_alloc;
} }
......
...@@ -1418,6 +1418,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1418,6 +1418,7 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
__u8 *end; __u8 *end;
sctp_transport_t *transport; sctp_transport_t *transport;
struct list_head *pos, *temp; struct list_head *pos, *temp;
char *cookie;
/* We must include the address that the INIT packet came from. /* We must include the address that the INIT packet came from.
* This is the only address that matters for an INIT packet. * This is the only address that matters for an INIT packet.
...@@ -1471,6 +1472,15 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid, ...@@ -1471,6 +1472,15 @@ void sctp_process_init(sctp_association_t *asoc, sctp_cid_t cid,
/* Peer Rwnd : Current calculated value of the peer's rwnd. */ /* Peer Rwnd : Current calculated value of the peer's rwnd. */
asoc->peer.rwnd = asoc->peer.i.a_rwnd; asoc->peer.rwnd = asoc->peer.i.a_rwnd;
/* Copy cookie in case we need to resend COOKIE-ECHO. */
cookie = asoc->peer.cookie;
if (cookie) {
asoc->peer.cookie = kmalloc(asoc->peer.cookie_len, priority);
if (!asoc->peer.cookie)
goto clean_up;
memcpy(asoc->peer.cookie, cookie, asoc->peer.cookie_len);
}
/* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily /* RFC 2960 7.2.1 The initial value of ssthresh MAY be arbitrarily
* high (for example, implementations MAY use the size of the receiver * high (for example, implementations MAY use the size of the receiver
* advertised window). * advertised window).
...@@ -1560,7 +1570,7 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1560,7 +1570,7 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
break; break;
case SCTP_PARAM_HOST_NAME_ADDRESS: case SCTP_PARAM_HOST_NAME_ADDRESS:
SCTP_DEBUG_PRINTK("unimplmented SCTP_HOST_NAME_ADDRESS\n"); SCTP_DEBUG_PRINTK("unimplemented SCTP_HOST_NAME_ADDRESS\n");
break; break;
case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES: case SCTP_PARAM_SUPPORTED_ADDRESS_TYPES:
...@@ -1595,13 +1605,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param, ...@@ -1595,13 +1605,12 @@ int sctp_process_param(sctp_association_t *asoc, sctpParam_t param,
case SCTP_PARAM_STATE_COOKIE: case SCTP_PARAM_STATE_COOKIE:
asoc->peer.cookie_len = asoc->peer.cookie_len =
ntohs(param.p->length) - ntohs(param.p->length) - sizeof(sctp_paramhdr_t);
sizeof(sctp_paramhdr_t);
asoc->peer.cookie = param.cookie->body; asoc->peer.cookie = param.cookie->body;
break; break;
case SCTP_PARAM_HEATBEAT_INFO: case SCTP_PARAM_HEATBEAT_INFO:
SCTP_DEBUG_PRINTK("unimplmented " SCTP_DEBUG_PRINTK("unimplemented "
"SCTP_PARAM_HEATBEAT_INFO\n"); "SCTP_PARAM_HEATBEAT_INFO\n");
break; break;
......
...@@ -253,6 +253,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -253,6 +253,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_chunk_t *new_obj; sctp_chunk_t *new_obj;
sctp_chunk_t *chunk; sctp_chunk_t *chunk;
sctp_packet_t *packet; sctp_packet_t *packet;
struct list_head *pos;
struct timer_list *timer; struct timer_list *timer;
unsigned long timeout; unsigned long timeout;
sctp_transport_t *t; sctp_transport_t *t;
...@@ -336,9 +337,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -336,9 +337,8 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
case SCTP_CMD_PEER_INIT: case SCTP_CMD_PEER_INIT:
/* Process a unified INIT from the peer. */ /* Process a unified INIT from the peer. */
sctp_cmd_process_init(commands, sctp_cmd_process_init(commands, asoc, chunk,
asoc, chunk, command->obj.ptr, command->obj.ptr, priority);
priority);
break; break;
case SCTP_CMD_GEN_COOKIE_ECHO: case SCTP_CMD_GEN_COOKIE_ECHO:
...@@ -462,6 +462,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -462,6 +462,7 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
break; break;
case SCTP_CMD_INIT_RESTART: case SCTP_CMD_INIT_RESTART:
/* Do the needed accounting and updates /* Do the needed accounting and updates
* associated with restarting an initialization * associated with restarting an initialization
* timer. * timer.
...@@ -474,6 +475,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype, ...@@ -474,6 +475,15 @@ int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
asoc->max_init_timeo; asoc->max_init_timeo;
} }
/* If we've sent any data bundled with
* COOKIE-ECHO we need to resend.
*/
list_for_each(pos, &asoc->peer.transport_addr_list) {
t = list_entry(pos, sctp_transport_t,
transports);
sctp_retransmit_mark(&asoc->outqueue, t, 0);
}
sctp_add_cmd_sf(commands, sctp_add_cmd_sf(commands,
SCTP_CMD_TIMER_RESTART, SCTP_CMD_TIMER_RESTART,
SCTP_TO(command->obj.to)); SCTP_TO(command->obj.to));
...@@ -867,6 +877,14 @@ void sctp_generate_t2_shutdown_event(unsigned long data) ...@@ -867,6 +877,14 @@ void sctp_generate_t2_shutdown_event(unsigned long data)
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN); sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
} }
void sctp_generate_t5_shutdown_guard_event(unsigned long data)
{
sctp_association_t *asoc = (sctp_association_t *)data;
sctp_generate_timeout_event(asoc,
SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD);
} /* sctp_generate_t5_shutdown_guard_event() */
void sctp_generate_autoclose_event(unsigned long data) void sctp_generate_autoclose_event(unsigned long data)
{ {
sctp_association_t *asoc = (sctp_association_t *) data; sctp_association_t *asoc = (sctp_association_t *) data;
...@@ -932,6 +950,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = { ...@@ -932,6 +950,7 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
sctp_generate_t2_shutdown_event, sctp_generate_t2_shutdown_event,
NULL, NULL,
NULL, NULL,
sctp_generate_t5_shutdown_guard_event,
sctp_generate_heartbeat_event, sctp_generate_heartbeat_event,
sctp_generate_sack_event, sctp_generate_sack_event,
sctp_generate_autoclose_event, sctp_generate_autoclose_event,
...@@ -1023,6 +1042,9 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands, ...@@ -1023,6 +1042,9 @@ static void sctp_cmd_assoc_failed(sctp_cmd_seq_t *commands,
sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP, sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
SCTP_ULPEVENT(event)); SCTP_ULPEVENT(event));
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
/* FIXME: We need to handle data that could not be sent or was not /* FIXME: We need to handle data that could not be sent or was not
* acked, if the user has enabled SEND_FAILED notifications. * acked, if the user has enabled SEND_FAILED notifications.
*/ */
......
This diff is collapsed.
This diff is collapsed.
/* Copyright (c) 1999-2000 Cisco, Inc. /* Copyright (c) 1999-2000 Cisco, Inc.
* Copyright (c) 1999-2001 Motorola, Inc. * Copyright (c) 1999-2001 Motorola, Inc.
* Copyright (c) 2001 International Business Machines, Corp. * Copyright (c) 2001-2002 International Business Machines, Corp.
* Copyright (c) 2001 Intel Corp. * Copyright (c) 2001-2002 Intel Corp.
* Copyright (c) 2001 Nokia, Inc. * Copyright (c) 2001-2002 Nokia, Inc.
* Copyright (c) 2001 La Monte H.P. Yarroll * Copyright (c) 2001 La Monte H.P. Yarroll
* *
* This file is part of the SCTP kernel reference Implementation * This file is part of the SCTP kernel reference Implementation
...@@ -82,8 +82,6 @@ static void sctp_wfree(struct sk_buff *skb); ...@@ -82,8 +82,6 @@ static void sctp_wfree(struct sk_buff *skb);
static int sctp_wait_for_sndbuf(sctp_association_t *asoc, long *timeo_p, static int sctp_wait_for_sndbuf(sctp_association_t *asoc, 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 inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname,
int *addr_len, struct sk_buff *skb);
static inline void sctp_sk_addr_set(struct sock *, static inline void sctp_sk_addr_set(struct sock *,
const sockaddr_storage_t *newaddr, const sockaddr_storage_t *newaddr,
sockaddr_storage_t *saveaddr); sockaddr_storage_t *saveaddr);
...@@ -326,8 +324,8 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs, ...@@ -326,8 +324,8 @@ static int __sctp_bindx(struct sock *sk, struct sockaddr_storage *addrs,
SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, " SCTP_DEBUG_PRINTK("__sctp_bindx(sk: %p, addrs: %p, addrcnt: %d, "
"flags: %s)\n", sk, addrs, addrcnt, "flags: %s)\n", sk, addrs, addrcnt,
(BINDX_ADD_ADDR == flags)?"ADD": (BINDX_ADD_ADDR == flags) ? "ADD" :
((BINDX_REM_ADDR == flags)?"REM":"BOGUS")); ((BINDX_REM_ADDR == flags) ? "REM" : "BOGUS"));
switch (flags) { switch (flags) {
case BINDX_ADD_ADDR: case BINDX_ADD_ADDR:
...@@ -500,9 +498,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -500,9 +498,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
case AF_INET: case AF_INET:
saveaddr = *((sockaddr_storage_t *) saveaddr = *((sockaddr_storage_t *)
&addrs[cnt]); &addrs[cnt]);
saveaddr.v4.sin_port = saveaddr.v4.sin_port = ntohs(saveaddr.v4.sin_port);
ntohs(saveaddr.v4.sin_port); /* Verify the port. */
/* verify the port */
if (saveaddr.v4.sin_port != bp->port) { if (saveaddr.v4.sin_port != bp->port) {
retval = -EINVAL; retval = -EINVAL;
goto err_bindx_rem; goto err_bindx_rem;
...@@ -606,7 +603,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt) ...@@ -606,7 +603,8 @@ int sctp_bindx_rem(struct sock *sk, struct sockaddr_storage *addrs, int addrcnt)
* *
* Returns 0 if ok, <0 errno code on error. * Returns 0 if ok, <0 errno code on error.
*/ */
static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs, static int sctp_setsockopt_bindx(struct sock* sk,
struct sockaddr_storage *addrs,
int addrssize, int op) int addrssize, int op)
{ {
struct sockaddr_storage *kaddrs; struct sockaddr_storage *kaddrs;
...@@ -614,8 +612,7 @@ static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs ...@@ -614,8 +612,7 @@ static int sctp_setsockopt_bindx(struct sock* sk, struct sockaddr_storage *addrs
size_t addrcnt; size_t addrcnt;
SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p" SCTP_DEBUG_PRINTK("sctp_do_setsocktopt_bindx: sk %p addrs %p"
" addrssize %d opt %d\n", sk, addrs, " addrssize %d opt %d\n", sk, addrs, addrssize, op);
addrssize, op);
/* Do we have an integer number of structs sockaddr_storage? */ /* Do we have an integer number of structs sockaddr_storage? */
if (unlikely(addrssize <= 0 || if (unlikely(addrssize <= 0 ||
...@@ -851,7 +848,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -851,7 +848,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
goto out_unlock; goto out_unlock;
} }
if (sinfo_flags & MSG_ABORT) { if (sinfo_flags & MSG_ABORT) {
SCTP_DEBUG_PRINTK("Aborting association: %p\n",asoc); SCTP_DEBUG_PRINTK("Aborting association: %p\n", asoc);
sctp_primitive_ABORT(asoc, NULL); sctp_primitive_ABORT(asoc, NULL);
err = 0; err = 0;
goto out_unlock; goto out_unlock;
...@@ -866,8 +863,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -866,8 +863,7 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
* either the default or the user specified stream counts. * either the default or the user specified stream counts.
*/ */
if (sinfo) { if (sinfo) {
if (!sinit || if (!sinit || (sinit && !sinit->sinit_num_ostreams)) {
(sinit && !sinit->sinit_num_ostreams)) {
/* Check against the defaults. */ /* Check against the defaults. */
if (sinfo->sinfo_stream >= if (sinfo->sinfo_stream >=
sp->initmsg.sinit_num_ostreams) { sp->initmsg.sinit_num_ostreams) {
...@@ -1096,12 +1092,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size) ...@@ -1096,12 +1092,13 @@ static int sctp_sendmsg(struct sock *sk, struct msghdr *msg, int size)
* flags - flags sent or received with the user message, see Section * flags - flags sent or received with the user message, see Section
* 5 for complete description of the flags. * 5 for complete description of the flags.
*/ */
static struct sk_buff * sctp_skb_recv_datagram(struct sock *, int, int, int *); static struct sk_buff *sctp_skb_recv_datagram(struct sock *, int, int, int *);
static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
int noblock, int flags, int *addr_len) int noblock, int flags, int *addr_len)
{ {
sctp_ulpevent_t *event = NULL; sctp_ulpevent_t *event = NULL;
sctp_opt_t *sp = sctp_sk(sk);
struct sk_buff *skb; struct sk_buff *skb;
int copied; int copied;
int err = 0; int err = 0;
...@@ -1147,19 +1144,16 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, ...@@ -1147,19 +1144,16 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
sock_recv_timestamp(msg, sk, skb); sock_recv_timestamp(msg, sk, skb);
if (sctp_ulpevent_is_notification(event)) { if (sctp_ulpevent_is_notification(event)) {
msg->msg_flags |= MSG_NOTIFICATION; msg->msg_flags |= MSG_NOTIFICATION;
sp->pf->event_msgname(event, msg->msg_name, addr_len);
} else { } else {
/* Copy the address. */ sp->pf->skb_msgname(skb, msg->msg_name, addr_len);
if (addr_len && msg->msg_name)
sctp_sk_memcpy_msgname(sk, msg->msg_name,
addr_len, skb);
} }
/* Check if we allow SCTP_SNDRCVINFO. */ /* Check if we allow SCTP_SNDRCVINFO. */
if (sctp_sk(sk)->subscribe.sctp_data_io_event) if (sp->subscribe.sctp_data_io_event)
sctp_ulpevent_read_sndrcvinfo(event, msg); sctp_ulpevent_read_sndrcvinfo(event, msg);
#if 0 #if 0
/* FIXME: we should be calling IP layer too. */ /* FIXME: we should be calling IP/IPv6 layers. */
if (sk->protinfo.af_inet.cmsg_flags) if (sk->protinfo.af_inet.cmsg_flags)
ip_cmsg_recv(msg, skb); ip_cmsg_recv(msg, skb);
#endif #endif
...@@ -1176,7 +1170,8 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len, ...@@ -1176,7 +1170,8 @@ static int sctp_recvmsg(struct sock *sk, struct msghdr *msg, int len,
return err; return err;
} }
static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_disable_fragments(struct sock *sk,
char *optval, int optlen)
{ {
int val; int val;
...@@ -1191,7 +1186,8 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optva ...@@ -1191,7 +1186,8 @@ static inline int sctp_setsockopt_disable_fragments(struct sock *sk, char *optva
return 0; return 0;
} }
static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval,
int optlen)
{ {
if (optlen != sizeof(struct sctp_event_subscribe)) if (optlen != sizeof(struct sctp_event_subscribe))
return -EINVAL; return -EINVAL;
...@@ -1200,7 +1196,8 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int ...@@ -1200,7 +1196,8 @@ static inline int sctp_setsockopt_set_events(struct sock *sk, char *optval, int
return 0; return 0;
} }
static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval, int optlen) static inline int sctp_setsockopt_autoclose(struct sock *sk, char *optval,
int optlen)
{ {
sctp_opt_t *sp = sctp_sk(sk); sctp_opt_t *sp = sctp_sk(sk);
...@@ -1236,7 +1233,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname, ...@@ -1236,7 +1233,7 @@ static int sctp_setsockopt(struct sock *sk, int level, int optname,
char *optval, int optlen) char *optval, int optlen)
{ {
int retval = 0; int retval = 0;
char * tmp; char *tmp;
sctp_protocol_t *proto = sctp_get_protocol(); sctp_protocol_t *proto = sctp_get_protocol();
struct list_head *pos; struct list_head *pos;
sctp_func_t *af; sctp_func_t *af;
...@@ -1356,19 +1353,9 @@ static int sctp_init_sock(struct sock *sk) ...@@ -1356,19 +1353,9 @@ static int sctp_init_sock(struct sock *sk)
proto = sctp_get_protocol(); proto = sctp_get_protocol();
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
*/
ep = sctp_endpoint_new(proto, sk, GFP_KERNEL);
if (!ep)
return -ENOMEM;
sp = sctp_sk(sk); sp = sctp_sk(sk);
/* Initialize the SCTP per socket area. */ /* Initialize the SCTP per socket area. */
sp->ep = ep;
sp->type = SCTP_SOCKET_UDP; sp->type = SCTP_SOCKET_UDP;
/* FIXME: The next draft (04) of the SCTP Sockets Extensions /* FIXME: The next draft (04) of the SCTP Sockets Extensions
...@@ -1425,6 +1412,16 @@ static int sctp_init_sock(struct sock *sk) ...@@ -1425,6 +1412,16 @@ static int sctp_init_sock(struct sock *sk)
* for UDP-style sockets only. * for UDP-style sockets only.
*/ */
sp->autoclose = 0; sp->autoclose = 0;
sp->pf = sctp_get_pf_specific(sk->family);
/* Create a per socket endpoint structure. Even if we
* change the data structure relationships, this may still
* be useful for storing pre-connect address information.
*/
ep = sctp_endpoint_new(proto, sk, GFP_KERNEL);
if (NULL == ep)
return -ENOMEM;
sp->ep = ep;
SCTP_DBG_OBJCNT_INC(sock); SCTP_DBG_OBJCNT_INC(sock);
return 0; return 0;
...@@ -1836,8 +1833,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1836,8 +1833,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
case PF_INET6: case PF_INET6:
SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6; SCTP_V6(tmpaddr.v6.sin6_family = AF_INET6;
tmpaddr.v6.sin6_port = snum; tmpaddr.v6.sin6_port = snum;
tmpaddr.v6.sin6_addr = tmpaddr.v6.sin6_addr = inet6_sk(sk)->rcv_saddr;
inet6_sk(sk)->rcv_saddr;
) )
break; break;
...@@ -1855,7 +1851,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1855,7 +1851,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* that this port/socket (sk) combination are already * that this port/socket (sk) combination are already
* in an endpoint. * in an endpoint.
*/ */
for( ; sk2 != NULL; sk2 = sk2->bind_next) { for ( ; sk2 != NULL; sk2 = sk2->bind_next) {
sctp_endpoint_t *ep2; sctp_endpoint_t *ep2;
ep2 = sctp_sk(sk2)->ep; ep2 = sctp_sk(sk2)->ep;
...@@ -1887,7 +1883,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum) ...@@ -1887,7 +1883,7 @@ static long sctp_get_port_local(struct sock *sk, unsigned short snum)
* SO_REUSEADDR on this socket -sk-). * SO_REUSEADDR on this socket -sk-).
*/ */
if (pp->sk == NULL) { if (pp->sk == NULL) {
pp->fastreuse = sk->reuse? 1 : 0; pp->fastreuse = sk->reuse ? 1 : 0;
} else if (pp->fastreuse && sk->reuse == 0) { } else if (pp->fastreuse && sk->reuse == 0) {
pp->fastreuse = 0; pp->fastreuse = 0;
} }
...@@ -2073,7 +2069,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi ...@@ -2073,7 +2069,7 @@ static sctp_bind_bucket_t *sctp_bucket_create(sctp_bind_hashbucket_t *head, unsi
pp->sk = NULL; pp->sk = NULL;
if ((pp->next = head->chain) != NULL) if ((pp->next = head->chain) != NULL)
pp->next->pprev = &pp->next; pp->next->pprev = &pp->next;
head->chain= pp; head->chain = pp;
pp->pprev = &head->chain; pp->pprev = &head->chain;
} }
SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp); SCTP_DEBUG_PRINTK("sctp_bucket_create() ends, pp=%p\n", pp);
...@@ -2433,41 +2429,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no ...@@ -2433,41 +2429,6 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags, int no
return NULL; return NULL;
} }
/* Copy an approriately formatted address for msg_name. */
static inline void sctp_sk_memcpy_msgname(struct sock *sk, char * msgname,
int *addr_len, struct sk_buff *skb)
{
struct sockaddr_in *sin;
struct sockaddr_in6 *sin6 __attribute__ ((unused));
struct sctphdr *sh;
/* The sockets layer handles copying this out to user space. */
switch (sk->family) {
case PF_INET:
sin = (struct sockaddr_in *)msgname;
if (addr_len)
*addr_len = sizeof(struct sockaddr_in);
sin->sin_family = AF_INET;
sh = (struct sctphdr *) skb->h.raw;
sin->sin_port = sh->source;
sin->sin_addr.s_addr = skb->nh.iph->saddr;
memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
break;
case PF_INET6:
SCTP_V6(
/* FIXME: Need v6 code here. We should convert
* V4 addresses to PF_INET6 format. See ipv6/udp.c
* for an example. --jgrimm
*/
);
break;
default: /* Should not get here. */
break;
};
}
static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg) static inline int sctp_sendmsg_verify_name(struct sock *sk, struct msghdr *msg)
{ {
sockaddr_storage_t *sa; sockaddr_storage_t *sa;
......
...@@ -46,9 +46,10 @@ ...@@ -46,9 +46,10 @@
#include <net/sctp/sctp.h> #include <net/sctp/sctp.h>
#include <net/sctp/sm.h> #include <net/sctp/sm.h>
static void sctp_rcvmsg_rfree(struct sk_buff *skb);
static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, static void sctp_ulpevent_set_owner_r(struct sk_buff *skb,
sctp_association_t *asoc); sctp_association_t *asoc);
static void
sctp_ulpevent_set_owner(struct sk_buff *skb, const sctp_association_t *asoc);
/* Create a new sctp_ulpevent. */ /* Create a new sctp_ulpevent. */
sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority) sctp_ulpevent_t *sctp_ulpevent_new(int size, int msg_flags, int priority)
...@@ -123,14 +124,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -123,14 +124,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
struct sctp_assoc_change *sac; struct sctp_assoc_change *sac;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
sac = (struct sctp_assoc_change *) sac = (struct sctp_assoc_change *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_assoc_change));
sizeof(struct sctp_assoc_change));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
...@@ -199,6 +198,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc, ...@@ -199,6 +198,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_assoc_change(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sac->sac_assoc_id = sctp_assoc2id(asoc); sac->sac_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -227,14 +227,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -227,14 +227,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
struct sctp_paddr_change *spc; struct sctp_paddr_change *spc;
event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change), event = sctp_ulpevent_new(sizeof(struct sctp_paddr_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
spc = (struct sctp_paddr_change *) spc = (struct sctp_paddr_change *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_paddr_change));
sizeof(struct sctp_paddr_change));
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
* Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE * Section 5.3.1.2 SCTP_PEER_ADDR_CHANGE
...@@ -287,12 +285,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change( ...@@ -287,12 +285,13 @@ sctp_ulpevent_t *sctp_ulpevent_make_peer_addr_change(
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.1 SCTP_ASSOC_CHANGE * 5.3.1.1 SCTP_ASSOC_CHANGE
* *
* sac_assoc_id: sizeof (sctp_assoc_t) * spc_assoc_id: sizeof (sctp_assoc_t)
* *
* The association id field, holds the identifier for the association. * The association id field, holds the identifier for the association.
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
spc->spc_assoc_id = sctp_assoc2id(asoc); spc->spc_assoc_id = sctp_assoc2id(asoc);
/* Sockets API Extensions for SCTP /* Sockets API Extensions for SCTP
...@@ -360,9 +359,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -360,9 +359,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
/* Embed the event fields inside the cloned skb. */ /* Embed the event fields inside the cloned skb. */
event = (sctp_ulpevent_t *) skb->cb; event = (sctp_ulpevent_t *) skb->cb;
event = sctp_ulpevent_init(event, event = sctp_ulpevent_init(event, skb, MSG_NOTIFICATION);
skb,
MSG_NOTIFICATION);
if (!event) if (!event)
goto fail; goto fail;
...@@ -418,6 +416,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc, ...@@ -418,6 +416,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_remote_error(const sctp_association_t *asoc,
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sre->sre_assoc_id = sctp_assoc2id(asoc); sre->sre_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -515,9 +514,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -515,9 +514,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* The original send information associated with the undelivered * The original send information associated with the undelivered
* message. * message.
*/ */
memcpy(&ssf->ssf_info, memcpy(&ssf->ssf_info, &chunk->sinfo, sizeof(struct sctp_sndrcvinfo));
&chunk->sinfo,
sizeof(struct sctp_sndrcvinfo));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.4 SCTP_SEND_FAILED * 5.3.1.4 SCTP_SEND_FAILED
...@@ -528,8 +525,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -528,8 +525,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* same association identifier. For TCP style socket, this field is * same association identifier. For TCP style socket, this field is
* ignored. * ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
ssf->ssf_assoc_id = sctp_assoc2id(asoc); ssf->ssf_assoc_id = sctp_assoc2id(asoc);
return event; return event;
fail: fail:
...@@ -541,7 +538,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc, ...@@ -541,7 +538,8 @@ sctp_ulpevent_t *sctp_ulpevent_make_send_failed(const sctp_association_t *asoc,
* Socket Extensions for SCTP - draft-01 * Socket Extensions for SCTP - draft-01
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *asoc, sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(
const sctp_association_t *asoc,
__u16 flags, __u16 flags,
int priority) int priority)
{ {
...@@ -549,14 +547,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -549,14 +547,12 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
struct sctp_shutdown_event *sse; struct sctp_shutdown_event *sse;
event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change), event = sctp_ulpevent_new(sizeof(struct sctp_assoc_change),
MSG_NOTIFICATION, MSG_NOTIFICATION, priority);
priority);
if (!event) if (!event)
goto fail; goto fail;
sse = (struct sctp_shutdown_event *) sse = (struct sctp_shutdown_event *)
skb_put(event->parent, skb_put(event->parent, sizeof(struct sctp_shutdown_event));
sizeof(struct sctp_shutdown_event));
/* Socket Extensions for SCTP /* Socket Extensions for SCTP
* 5.3.1.5 SCTP_SHUTDOWN_EVENT * 5.3.1.5 SCTP_SHUTDOWN_EVENT
...@@ -591,6 +587,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -591,6 +587,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
* All notifications for a given association have the same association * All notifications for a given association have the same association
* identifier. For TCP style socket, this field is ignored. * identifier. For TCP style socket, this field is ignored.
*/ */
sctp_ulpevent_set_owner(event->parent, asoc);
sse->sse_assoc_id = sctp_assoc2id(asoc); sse->sse_assoc_id = sctp_assoc2id(asoc);
return event; return event;
...@@ -607,8 +604,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso ...@@ -607,8 +604,7 @@ sctp_ulpevent_t *sctp_ulpevent_make_shutdown_event(const sctp_association_t *aso
* 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV) * 5.2.2 SCTP Header Information Structure (SCTP_SNDRCV)
*/ */
sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc, sctp_ulpevent_t *sctp_ulpevent_make_rcvmsg(sctp_association_t *asoc,
sctp_chunk_t *chunk, sctp_chunk_t *chunk, int priority)
int priority)
{ {
sctp_ulpevent_t *event; sctp_ulpevent_t *event;
struct sctp_sndrcvinfo *info; struct sctp_sndrcvinfo *info;
...@@ -818,23 +814,33 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a ...@@ -818,23 +814,33 @@ static void sctp_ulpevent_set_owner_r(struct sk_buff *skb, sctp_association_t *a
asoc->rwnd_over = skb->len - asoc->rwnd; asoc->rwnd_over = skb->len - asoc->rwnd;
asoc->rwnd = 0; asoc->rwnd = 0;
} }
SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n", SCTP_DEBUG_PRINTK("rwnd decreased by %d to (%u, %u)\n",
skb->len, asoc->rwnd, asoc->rwnd_over); skb->len, asoc->rwnd, asoc->rwnd_over);
} }
/* A simple destructor to give up the reference to the association. */
static void sctp_ulpevent_rfree(struct sk_buff *skb)
{
sctp_ulpevent_t *event;
event = (sctp_ulpevent_t *)skb->cb;
sctp_association_put(event->asoc);
}
/* Hold the association in case the msg_name needs read out of
* the association.
*/
static void sctp_ulpevent_set_owner(struct sk_buff *skb,
const sctp_association_t *asoc)
{
sctp_ulpevent_t *event;
/* Cast away the const, as we are just wanting to
* bump the reference count.
*/
sctp_association_hold((sctp_association_t *)asoc);
skb->sk = asoc->base.sk;
event = (sctp_ulpevent_t *)skb->cb;
event->asoc = (sctp_association_t *)asoc;
skb->destructor = sctp_ulpevent_rfree;
}
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