Commit cabbb4de authored by David S. Miller's avatar David S. Miller

Merge http://linux-lksctp.bkbits.net/lksctp-2.5.work

into nuts.davemloft.net:/disk1/BK/net-2.6
parents c7e670c0 a271fa8b
......@@ -364,7 +364,7 @@ typedef struct sctp_heartbeat_chunk {
*/
typedef struct sctp_abort_chunk {
sctp_chunkhdr_t uh;
} __attribute__((packed)) sctp_abort_chunkt_t;
} __attribute__((packed)) sctp_abort_chunk_t;
/* For the graceful shutdown we must carry the tag (in common header)
......
......@@ -189,11 +189,6 @@ typedef struct {
} sctp_cmd_seq_t;
/* Create a new sctp_command_sequence.
* Return NULL if creating a new sequence fails.
*/
sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp);
/* Initialize a block of memory as a command sequence.
* Return 0 if the initialization fails.
*/
......@@ -207,18 +202,10 @@ int sctp_init_cmd_seq(sctp_cmd_seq_t *seq);
*/
int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj);
/* Rewind an sctp_cmd_seq_t to iterate from the start.
* Return 0 if the rewind fails.
*/
int sctp_rewind_sequence(sctp_cmd_seq_t *seq);
/* Return the next command structure in an sctp_cmd_seq.
* Return NULL at the end of the sequence.
*/
sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq);
/* Dispose of a command sequence. */
void sctp_free_cmd_seq(sctp_cmd_seq_t *seq);
#endif /* __net_sctp_command_h__ */
......@@ -105,9 +105,10 @@ typedef enum {
typedef enum {
SCTP_EVENT_NO_PENDING_TSN = 0,
SCTP_EVENT_ICMP_PROTO_UNREACH,
} sctp_event_other_t;
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_NO_PENDING_TSN
#define SCTP_EVENT_OTHER_MAX SCTP_EVENT_ICMP_PROTO_UNREACH
#define SCTP_NUM_OTHER_TYPES (SCTP_EVENT_OTHER_MAX + 1)
/* These are primitive requests from the ULP. */
......@@ -155,10 +156,6 @@ SCTP_SUBTYPE_CONSTRUCTOR(PRIMITIVE, sctp_event_primitive_t, primitive)
- (unsigned long)(c->chunk_hdr)\
- sizeof(sctp_data_chunk_t)))
/* This is a table of printable names of sctp_param_t's. */
extern const char *sctp_param_tbl[];
#define SCTP_MAX_ERROR_CAUSE SCTP_ERROR_NONEXIST_IP
#define SCTP_NUM_ERROR_CAUSE 10
......@@ -179,6 +176,7 @@ typedef enum {
SCTP_IERROR_IGNORE_TSN,
SCTP_IERROR_NO_DATA,
SCTP_IERROR_BAD_STREAM,
SCTP_IERROR_BAD_PORTS,
} sctp_ierror_t;
......
......@@ -162,17 +162,9 @@ __u32 sctp_update_copy_cksum(__u8 *, __u8 *, __u16 count, __u32 cksum);
int sctp_rcv(struct sk_buff *skb);
void sctp_v4_err(struct sk_buff *skb, u32 info);
void sctp_hash_established(struct sctp_association *);
void __sctp_hash_established(struct sctp_association *);
void sctp_unhash_established(struct sctp_association *);
void __sctp_unhash_established(struct sctp_association *);
void sctp_hash_endpoint(struct sctp_endpoint *);
void __sctp_hash_endpoint(struct sctp_endpoint *);
void sctp_unhash_endpoint(struct sctp_endpoint *);
void __sctp_unhash_endpoint(struct sctp_endpoint *);
struct sctp_association *__sctp_lookup_association(
const union sctp_addr *,
const union sctp_addr *,
struct sctp_transport **);
struct sock *sctp_err_lookup(int family, struct sk_buff *,
struct sctphdr *, struct sctp_endpoint **,
struct sctp_association **,
......@@ -181,6 +173,10 @@ void sctp_err_finish(struct sock *, struct sctp_endpoint *,
struct sctp_association *);
void sctp_icmp_frag_needed(struct sock *, struct sctp_association *,
struct sctp_transport *t, __u32 pmtu);
void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
struct sctp_transport *t);
/*
* Section: Macros, externs, and inlines
......@@ -310,8 +306,6 @@ static inline int sctp_sysctl_jiffies_ms(ctl_table *table, int __user *name, int
int sctp_v6_init(void);
void sctp_v6_exit(void);
void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info);
#else /* #ifdef defined(CONFIG_IPV6) */
......@@ -455,7 +449,8 @@ _sctp_walk_params((pos), (chunk), WORD_ROUND(ntohs((chunk)->chunk_hdr.length)),
#define _sctp_walk_params(pos, chunk, end, member)\
for (pos.v = chunk->member;\
pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)); \
pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)) &&\
ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\
pos.v += WORD_ROUND(ntohs(pos.p->length)))
#define sctp_walk_errors(err, chunk_hdr)\
......@@ -465,10 +460,9 @@ _sctp_walk_errors((err), (chunk_hdr), ntohs((chunk_hdr)->length))
for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \
sizeof(sctp_chunkhdr_t));\
(void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\
(void *)err <= (void *)chunk_hdr + end - \
WORD_ROUND(ntohs(err->length));\
err = (sctp_errhdr_t *)((void *)err + \
WORD_ROUND(ntohs(err->length))))
(void *)err <= (void *)chunk_hdr + end - WORD_ROUND(ntohs(err->length)) &&\
ntohs(err->length) >= sizeof(sctp_errhdr_t); \
err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length))))
#define sctp_walk_fwdtsn(pos, chunk)\
_sctp_walk_fwdtsn((pos), (chunk), ntohs((chunk)->chunk_hdr->length) - sizeof(struct sctp_fwdtsn_chunk))
......
......@@ -128,9 +128,9 @@ sctp_state_fn_t sctp_sf_do_9_2_shutdown;
sctp_state_fn_t sctp_sf_do_ecn_cwr;
sctp_state_fn_t sctp_sf_do_ecne;
sctp_state_fn_t sctp_sf_ootb;
sctp_state_fn_t sctp_sf_shut_8_4_5;
sctp_state_fn_t sctp_sf_pdiscard;
sctp_state_fn_t sctp_sf_violation;
sctp_state_fn_t sctp_sf_violation_chunklen;
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_2_dupinit;
......@@ -138,7 +138,6 @@ sctp_state_fn_t sctp_sf_do_5_2_4_dupcook;
sctp_state_fn_t sctp_sf_unk_chunk;
sctp_state_fn_t sctp_sf_do_8_5_1_E_sa;
sctp_state_fn_t sctp_sf_cookie_echoed_err;
sctp_state_fn_t sctp_sf_do_5_2_6_stale;
sctp_state_fn_t sctp_sf_do_asconf;
sctp_state_fn_t sctp_sf_do_asconf_ack;
sctp_state_fn_t sctp_sf_do_9_2_reshutack;
......@@ -167,6 +166,7 @@ sctp_state_fn_t sctp_sf_do_prm_asconf;
sctp_state_fn_t sctp_sf_do_9_2_start_shutdown;
sctp_state_fn_t sctp_sf_do_9_2_shutdown_ack;
sctp_state_fn_t sctp_sf_ignore_other;
sctp_state_fn_t sctp_sf_cookie_wait_icmp_abort;
/* Prototypes for timeout event state functions. */
sctp_state_fn_t sctp_sf_do_6_3_3_rtx;
......@@ -200,19 +200,10 @@ struct sctp_chunk *sctp_make_cookie_ack(const struct sctp_association *,
struct sctp_chunk *sctp_make_cwr(const struct sctp_association *,
const __u32 lowest_tsn,
const struct sctp_chunk *);
struct sctp_chunk *sctp_make_datafrag(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 *data,
__u8 flags, __u16 ssn);
struct sctp_chunk * sctp_make_datafrag_empty(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 flags,
__u16 ssn);
struct sctp_chunk *sctp_make_data(struct sctp_association *,
const struct sctp_sndrcvinfo *sinfo,
int len, const __u8 *data);
struct sctp_chunk *sctp_make_data_empty(struct sctp_association *,
const struct sctp_sndrcvinfo *, int len);
struct sctp_chunk *sctp_make_ecne(const struct sctp_association *,
const __u32);
struct sctp_chunk *sctp_make_sack(const struct sctp_association *);
......@@ -232,6 +223,10 @@ struct sctp_chunk *sctp_make_abort_no_data(const struct sctp_association *,
struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *,
const struct sctp_chunk *,
const struct msghdr *);
struct sctp_chunk *sctp_make_abort_violation(const struct sctp_association *,
const struct sctp_chunk *,
const __u8 *,
const size_t );
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *,
const struct sctp_transport *,
const void *payload,
......@@ -246,17 +241,12 @@ struct sctp_chunk *sctp_make_op_error(const struct sctp_association *,
const void *payload,
size_t paylen);
struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
union sctp_addr *addr,
int vparam_len);
struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
union sctp_addr *,
struct sockaddr *,
int, __u16);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr);
struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
__u32 serial, int vparam_len);
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf);
int sctp_process_asconf_ack(struct sctp_association *asoc,
......@@ -268,6 +258,8 @@ struct sctp_chunk *sctp_make_fwdtsn(const struct sctp_association *asoc,
void sctp_chunk_assign_tsn(struct sctp_chunk *);
void sctp_chunk_assign_ssn(struct sctp_chunk *);
void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error);
/* Prototypes for statetable processing. */
int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
......@@ -277,71 +269,26 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
void *event_arg,
int gfp);
int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp);
/* 2nd level prototypes */
int sctp_cmd_interpreter(sctp_event_t, sctp_subtype_t, sctp_state_t,
struct sctp_endpoint *, struct sctp_association *,
void *event_arg, sctp_disposition_t,
sctp_cmd_seq_t *retval, int gfp);
int sctp_gen_sack(struct sctp_association *, int force, sctp_cmd_seq_t *);
void sctp_generate_t3_rtx_event(unsigned long peer);
void sctp_generate_heartbeat_event(unsigned long peer);
sctp_sackhdr_t *sctp_sm_pull_sack(struct sctp_chunk *);
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 *);
struct sctp_cookie_param *
sctp_pack_cookie(const struct sctp_endpoint *, const struct sctp_association *,
const struct sctp_chunk *, int *cookie_len,
const __u8 *, int addrs_len);
struct sctp_association *sctp_unpack_cookie(const struct sctp_endpoint *,
const struct sctp_association *,
struct sctp_chunk *, int gfp, int *err,
struct sctp_chunk **err_chk_p);
int sctp_addip_addr_config(struct sctp_association *, sctp_param_t,
struct sockaddr_storage*, int);
void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands,
struct sctp_chunk *err_chunk);
int sctp_eat_data(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands);
/* 3rd level prototypes */
__u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const struct sctp_endpoint *);
/* Extern declarations for major data structures. */
const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t, sctp_state_t);
extern const sctp_sm_table_entry_t
primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
extern const sctp_sm_table_entry_t
other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
extern const sctp_sm_table_entry_t
timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
extern sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES];
/* These are some handy utility macros... */
/* Get the size of a DATA chunk payload. */
static inline __u16 sctp_data_size(struct sctp_chunk *chunk)
......
......@@ -322,10 +322,19 @@ struct sctp_cookie {
/* This holds the originating address of the INIT packet. */
union sctp_addr peer_addr;
/* IG Section 2.35.3
* Include the source port of the INIT-ACK
*/
__u16 my_port;
__u8 prsctp_capable;
/* Padding for future use */
__u8 padding;
__u32 adaption_ind;
/* This is a shim for my peer's INIT packet, followed by
* a copy of the raw address list of the association.
* The length of the raw address list is saved in the
......@@ -406,7 +415,6 @@ struct sctp_ssnmap {
int malloced;
};
struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *, __u16, __u16);
struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp);
void sctp_ssnmap_free(struct sctp_ssnmap *map);
void sctp_ssnmap_clear(struct sctp_ssnmap *map);
......@@ -538,12 +546,9 @@ struct sctp_datamsg {
struct sctp_datamsg *sctp_datamsg_from_user(struct sctp_association *,
struct sctp_sndrcvinfo *,
struct msghdr *, int len);
struct sctp_datamsg *sctp_datamsg_new(int gfp);
void sctp_datamsg_put(struct sctp_datamsg *);
void sctp_datamsg_hold(struct sctp_datamsg *);
void sctp_datamsg_free(struct sctp_datamsg *);
void sctp_datamsg_track(struct sctp_chunk *);
void sctp_datamsg_assign(struct sctp_datamsg *, struct sctp_chunk *);
void sctp_chunk_fail(struct sctp_chunk *, int error);
int sctp_chunk_abandoned(struct sctp_chunk *);
......@@ -651,8 +656,6 @@ void sctp_chunk_hold(struct sctp_chunk *);
void sctp_chunk_put(struct sctp_chunk *);
int sctp_user_addto_chunk(struct sctp_chunk *chunk, int off, int len,
struct iovec *data);
struct sctp_chunk *sctp_make_chunk(const struct sctp_association *, __u8 type,
__u8 flags, int size);
void sctp_chunk_free(struct sctp_chunk *);
void *sctp_addto_chunk(struct sctp_chunk *, int len, const void *data);
struct sctp_chunk *sctp_chunkify(struct sk_buff *,
......@@ -853,12 +856,6 @@ struct sctp_transport {
/* Error count : The current error count for this destination. */
unsigned short error_count;
/* Error : Current error threshold for this destination
* Threshold : i.e. what value marks the destination down if
* : errorCount reaches this value.
*/
unsigned short error_threshold;
/* This is the max_retrans value for the transport and will
* be initialized to proto.max_retrans.path. This can be changed
* using SCTP_SET_PEER_ADDR_PARAMS socket option.
......@@ -922,15 +919,12 @@ struct sctp_transport {
};
struct sctp_transport *sctp_transport_new(const union sctp_addr *, int);
struct sctp_transport *sctp_transport_init(struct sctp_transport *,
const union sctp_addr *, int);
void sctp_transport_set_owner(struct sctp_transport *,
struct sctp_association *);
void sctp_transport_route(struct sctp_transport *, union sctp_addr *,
struct sctp_opt *);
void sctp_transport_pmtu(struct sctp_transport *);
void sctp_transport_free(struct sctp_transport *);
void sctp_transport_destroy(struct sctp_transport *);
void sctp_transport_reset_timers(struct sctp_transport *);
void sctp_transport_hold(struct sctp_transport *);
void sctp_transport_put(struct sctp_transport *);
......@@ -961,7 +955,6 @@ struct sctp_inq {
int malloced; /* Is this structure kfree()able? */
};
struct sctp_inq *sctp_inq_new(void);
void sctp_inq_init(struct sctp_inq *);
void sctp_inq_free(struct sctp_inq *);
void sctp_inq_push(struct sctp_inq *, struct sctp_chunk *packet);
......@@ -1029,7 +1022,6 @@ struct sctp_outq {
char malloced;
};
struct sctp_outq *sctp_outq_new(struct sctp_association *);
void sctp_outq_init(struct sctp_association *, struct sctp_outq *);
void sctp_outq_teardown(struct sctp_outq *);
void sctp_outq_free(struct sctp_outq*);
......@@ -1070,7 +1062,6 @@ struct sctp_bind_addr {
int malloced; /* Are we kfree()able? */
};
struct sctp_bind_addr *sctp_bind_addr_new(int gfp_mask);
void sctp_bind_addr_init(struct sctp_bind_addr *, __u16 port);
void sctp_bind_addr_free(struct sctp_bind_addr *);
int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
......@@ -1220,8 +1211,6 @@ static inline struct sctp_endpoint *sctp_ep(struct sctp_ep_common *base)
/* These are function signatures for manipulating endpoints. */
struct sctp_endpoint *sctp_endpoint_new(struct sock *, int);
struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *,
struct sock *, int gfp);
void sctp_endpoint_free(struct sctp_endpoint *);
void sctp_endpoint_put(struct sctp_endpoint *);
void sctp_endpoint_hold(struct sctp_endpoint *);
......@@ -1243,8 +1232,6 @@ int sctp_verify_init(const struct sctp_association *asoc, sctp_cid_t,
int sctp_process_init(struct sctp_association *, sctp_cid_t cid,
const union sctp_addr *peer,
sctp_init_chunk_t *init, int gfp);
int sctp_process_param(struct sctp_association *, union sctp_params param,
const union sctp_addr *from, int gfp);
__u32 sctp_generate_tag(const struct sctp_endpoint *);
__u32 sctp_generate_tsn(const struct sctp_endpoint *);
......@@ -1690,10 +1677,6 @@ static inline struct sctp_association *sctp_assoc(struct sctp_ep_common *base)
struct sctp_association *
sctp_association_new(const struct sctp_endpoint *, const struct sock *,
sctp_scope_t scope, int gfp);
struct sctp_association *
sctp_association_init(struct sctp_association *, const struct sctp_endpoint *,
const struct sock *, sctp_scope_t scope,
int gfp);
void sctp_association_free(struct sctp_association *);
void sctp_association_put(struct sctp_association *);
void sctp_association_hold(struct sctp_association *);
......@@ -1722,7 +1705,6 @@ void sctp_assoc_update(struct sctp_association *old,
struct sctp_association *new);
__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 *, unsigned);
......@@ -1736,7 +1718,6 @@ int sctp_assoc_set_bind_addr_from_cookie(struct sctp_association *,
int sctp_cmp_addr_exact(const union sctp_addr *ss1,
const union sctp_addr *ss2);
struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc);
struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc);
/* A convenience structure to parse out SCTP specific CMSGs. */
typedef struct sctp_cmsgs {
......
......@@ -120,12 +120,6 @@ struct sctp_tsnmap_iter {
__u32 start;
};
/* Create a new tsnmap. */
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 init_tsn, int gfp);
/* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *);
/* This macro assists in creation of external storage for variable length
* internal buffers. We double allocate so the overflow map works.
*/
......@@ -210,14 +204,4 @@ void sctp_tsnmap_renege(struct sctp_tsnmap *, __u32 tsn);
/* Is there a gap in the TSN map? */
int sctp_tsnmap_has_gap(const struct sctp_tsnmap *);
/* Initialize a gap ack block interator from user-provided memory. */
void sctp_tsnmap_iter_init(const struct sctp_tsnmap *,
struct sctp_tsnmap_iter *);
/* Get the next gap ack blocks. We return 0 if there are no more
* gap ack blocks.
*/
int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *,
struct sctp_tsnmap_iter *,__u16 *start, __u16 *end);
#endif /* __sctp_tsnmap_h__ */
......@@ -77,8 +77,6 @@ static inline struct sctp_ulpevent *sctp_skb2event(struct sk_buff *skb)
return (struct sctp_ulpevent *)skb->cb;
}
struct sctp_ulpevent *sctp_ulpevent_new(int size, int flags, int gfp);
void sctp_ulpevent_init(struct sctp_ulpevent *, int flags);
void sctp_ulpevent_free(struct sctp_ulpevent *);
int sctp_ulpevent_is_notification(const struct sctp_ulpevent *);
void sctp_queue_purge_ulpevents(struct sk_buff_head *list);
......
......@@ -57,7 +57,6 @@ struct sctp_ulpq {
};
/* Prototypes. */
struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp);
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *,
struct sctp_association *);
void sctp_ulpq_free(struct sctp_ulpq *);
......
......@@ -66,33 +66,8 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc);
/* 1st Level Abstractions. */
/* Allocate and initialize a new association */
struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
const struct sock *sk,
sctp_scope_t scope, int gfp)
{
struct sctp_association *asoc;
asoc = t_new(struct sctp_association, gfp);
if (!asoc)
goto fail;
if (!sctp_association_init(asoc, ep, sk, scope, gfp))
goto fail_init;
asoc->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(assoc);
return asoc;
fail_init:
kfree(asoc);
fail:
return NULL;
}
/* Initialize a new association from provided memory. */
struct sctp_association *sctp_association_init(struct sctp_association *asoc,
static struct sctp_association *sctp_association_init(struct sctp_association *asoc,
const struct sctp_endpoint *ep,
const struct sock *sk,
sctp_scope_t scope,
......@@ -204,6 +179,7 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
asoc->c.peer_vtag = 0;
asoc->c.my_ttag = 0;
asoc->c.peer_ttag = 0;
asoc->c.my_port = ep->base.bind_addr.port;
asoc->c.initial_tsn = sctp_generate_tsn(ep);
......@@ -296,6 +272,31 @@ struct sctp_association *sctp_association_init(struct sctp_association *asoc,
return NULL;
}
/* Allocate and initialize a new association */
struct sctp_association *sctp_association_new(const struct sctp_endpoint *ep,
const struct sock *sk,
sctp_scope_t scope, int gfp)
{
struct sctp_association *asoc;
asoc = t_new(struct sctp_association, gfp);
if (!asoc)
goto fail;
if (!sctp_association_init(asoc, ep, sk, scope, gfp))
goto fail_init;
asoc->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(assoc);
return asoc;
fail_init:
kfree(asoc);
fail:
return NULL;
}
/* Free this association if possible. There may still be users, so
* the actual deallocation may be delayed.
*/
......@@ -500,7 +501,6 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->partial_bytes_acked = 0;
peer->flight_size = 0;
peer->error_threshold = peer->max_retrans;
/* By default, enable heartbeat for peer address. */
peer->hb_allowed = 1;
......@@ -511,7 +511,7 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc,
peer->hb_interval = msecs_to_jiffies(sp->paddrparam.spp_hbinterval);
/* Set the path max_retrans. */
peer->max_retrans = asoc->max_retrans;
peer->max_retrans = sp->paddrparam.spp_pathmaxrxt;
/* Set the transport's RTO.initial value */
peer->rto = asoc->rto_initial;
......@@ -714,18 +714,6 @@ __u32 sctp_association_get_next_tsn(struct sctp_association *asoc)
return retval;
}
/* Allocate 'num' TSNs by incrementing the association's TSN by num. */
__u32 sctp_association_get_tsn_block(struct sctp_association *asoc, int num)
{
__u32 retval = asoc->next_tsn;
asoc->next_tsn += num;
asoc->unack_data += num;
return retval;
}
/* Compare two addresses to see if they match. Wildcard addresses
* only match themselves.
*/
......@@ -760,14 +748,6 @@ struct sctp_chunk *sctp_get_ecne_prepend(struct sctp_association *asoc)
return chunk;
}
/* Use this function for the packet prepend callback when no ECNE
* packet is desired (e.g. some packets don't like to be bundled).
*/
struct sctp_chunk *sctp_get_no_prepend(struct sctp_association *asoc)
{
return NULL;
}
/*
* Find which transport this TSN was sent on.
*/
......@@ -861,7 +841,8 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
struct sctp_chunk *chunk;
struct sock *sk;
struct sctp_inq *inqueue;
int state, subtype;
int state;
sctp_subtype_t subtype;
int error = 0;
/* The association should be held so we should be safe. */
......@@ -872,7 +853,7 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
sctp_association_hold(asoc);
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
state = asoc->state;
subtype = chunk->chunk_hdr->type;
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
/* Remember where the last DATA chunk came from so we
* know where to send the SACK.
......@@ -886,7 +867,7 @@ static void sctp_assoc_bh_rcv(struct sctp_association *asoc)
chunk->transport->last_time_heard = jiffies;
/* Run through the state machine. */
error = sctp_do_sm(SCTP_EVENT_T_CHUNK, SCTP_ST_CHUNK(subtype),
error = sctp_do_sm(SCTP_EVENT_T_CHUNK, subtype,
state, ep, asoc, chunk, GFP_ATOMIC);
/* Check to see if the association is freed in response to
......
......@@ -104,23 +104,6 @@ int sctp_bind_addr_copy(struct sctp_bind_addr *dest,
return error;
}
/* Create a new SCTP_bind_addr from nothing. */
struct sctp_bind_addr *sctp_bind_addr_new(int gfp)
{
struct sctp_bind_addr *retval;
retval = t_new(struct sctp_bind_addr, gfp);
if (!retval)
goto nomem;
sctp_bind_addr_init(retval, 0);
retval->malloced = 1;
SCTP_DBG_OBJCNT_INC(bind_addr);
nomem:
return retval;
}
/* Initialize the SCTP_bind_addr structure for either an endpoint or
* an association.
*/
......
......@@ -51,7 +51,7 @@
*/
/* Initialize datamsg from memory. */
void sctp_datamsg_init(struct sctp_datamsg *msg)
static void sctp_datamsg_init(struct sctp_datamsg *msg)
{
atomic_set(&msg->refcnt, 1);
msg->send_failed = 0;
......@@ -62,7 +62,7 @@ void sctp_datamsg_init(struct sctp_datamsg *msg)
}
/* Allocate and initialize datamsg. */
struct sctp_datamsg *sctp_datamsg_new(int gfp)
SCTP_STATIC struct sctp_datamsg *sctp_datamsg_new(int gfp)
{
struct sctp_datamsg *msg;
msg = kmalloc(sizeof(struct sctp_datamsg), gfp);
......@@ -124,7 +124,7 @@ static void sctp_datamsg_destroy(struct sctp_datamsg *msg)
}
/* Hold a reference. */
void sctp_datamsg_hold(struct sctp_datamsg *msg)
static void sctp_datamsg_hold(struct sctp_datamsg *msg)
{
atomic_inc(&msg->refcnt);
}
......@@ -151,7 +151,7 @@ void sctp_datamsg_track(struct sctp_chunk *chunk)
}
/* Assign a chunk to this datamsg. */
void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
static void sctp_datamsg_assign(struct sctp_datamsg *msg, struct sctp_chunk *chunk)
{
sctp_datamsg_hold(msg);
chunk->msg = msg;
......
......@@ -42,17 +42,6 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
/* Create a new sctp_command_sequence. */
sctp_cmd_seq_t *sctp_new_cmd_seq(int gfp)
{
sctp_cmd_seq_t *retval = t_new(sctp_cmd_seq_t, gfp);
if (retval)
sctp_init_cmd_seq(retval);
return retval;
}
/* Initialize a block of memory as a command sequence. */
int sctp_init_cmd_seq(sctp_cmd_seq_t *seq)
{
......@@ -77,13 +66,6 @@ int sctp_add_cmd(sctp_cmd_seq_t *seq, sctp_verb_t verb, sctp_arg_t obj)
return 0;
}
/* Rewind an sctp_cmd_seq_t to iterate from the start. */
int sctp_rewind_sequence(sctp_cmd_seq_t *seq)
{
seq->next_cmd = 0;
return 1; /* We always succeed. */
}
/* Return the next command structure in a sctp_cmd_seq.
* Returns NULL at the end of the sequence.
*/
......@@ -97,8 +79,3 @@ sctp_cmd_t *sctp_next_cmd(sctp_cmd_seq_t *seq)
return retval;
}
/* Dispose of a command sequence. */
void sctp_free_cmd_seq(sctp_cmd_seq_t *seq)
{
kfree(seq);
}
......@@ -98,23 +98,6 @@ const char *sctp_cname(const sctp_subtype_t cid)
return "unknown chunk";
}
/* These are printable form of variable-length parameters. */
const char *sctp_param_tbl[SCTP_PARAM_ECN_CAPABLE + 1] = {
"",
"PARAM_HEARTBEAT_INFO",
"",
"",
"",
"PARAM_IPV4_ADDRESS",
"PARAM_IPV6_ADDRESS",
"PARAM_STATE_COOKIE",
"PARAM_UNRECOGNIZED_PARAMETERS",
"PARAM_COOKIE_PRESERVATIVE",
"",
"PARAM_HOST_NAME_ADDRESS",
"PARAM_SUPPORTED_ADDRESS_TYPES",
};
/* These are printable forms of the states. */
const char *sctp_state_tbl[SCTP_STATE_NUM_STATES] = {
"STATE_EMPTY",
......@@ -171,6 +154,7 @@ const char *sctp_pname(const sctp_subtype_t id)
static const char *sctp_other_tbl[] = {
"NO_PENDING_TSN",
"ICMP_PROTO_UNREACH",
};
/* Lookup "other" debug name. */
......@@ -178,7 +162,7 @@ const char *sctp_oname(const sctp_subtype_t id)
{
if (id.other < 0)
return "illegal 'other' event";
if (id.other < SCTP_EVENT_OTHER_MAX)
if (id.other <= SCTP_EVENT_OTHER_MAX)
return sctp_other_tbl[id.other];
return "unknown 'other' event";
}
......
......@@ -63,34 +63,11 @@
/* Forward declarations for internal helpers. */
static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep);
/* Create a sctp_endpoint with all that boring stuff initialized.
* Returns NULL if there isn't enough memory.
*/
struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
{
struct sctp_endpoint *ep;
/* Build a local endpoint. */
ep = t_new(struct sctp_endpoint, gfp);
if (!ep)
goto fail;
if (!sctp_endpoint_init(ep, sk, gfp))
goto fail_init;
ep->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(ep);
return ep;
fail_init:
kfree(ep);
fail:
return NULL;
}
/*
* Initialize the base fields of the endpoint structure.
*/
struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
struct sock *sk, int gfp)
static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
struct sock *sk, int gfp)
{
struct sctp_opt *sp = sctp_sk(sk);
memset(ep, 0, sizeof(struct sctp_endpoint));
......@@ -160,6 +137,29 @@ struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
return ep;
}
/* Create a sctp_endpoint with all that boring stuff initialized.
* Returns NULL if there isn't enough memory.
*/
struct sctp_endpoint *sctp_endpoint_new(struct sock *sk, int gfp)
{
struct sctp_endpoint *ep;
/* Build a local endpoint. */
ep = t_new(struct sctp_endpoint, gfp);
if (!ep)
goto fail;
if (!sctp_endpoint_init(ep, sk, gfp))
goto fail_init;
ep->base.malloced = 1;
SCTP_DBG_OBJCNT_INC(ep);
return ep;
fail_init:
kfree(ep);
fail:
return NULL;
}
/* Add an association to an endpoint. */
void sctp_endpoint_add_asoc(struct sctp_endpoint *ep,
struct sctp_association *asoc)
......@@ -184,7 +184,7 @@ void sctp_endpoint_free(struct sctp_endpoint *ep)
}
/* Final destructor for endpoint. */
void sctp_endpoint_destroy(struct sctp_endpoint *ep)
static void sctp_endpoint_destroy(struct sctp_endpoint *ep)
{
SCTP_ASSERT(ep->base.dead, "Endpoint is not dead", return);
......@@ -257,7 +257,7 @@ struct sctp_endpoint *sctp_endpoint_is_match(struct sctp_endpoint *ep,
* We do a linear search of the associations for this endpoint.
* We return the matching transport address too.
*/
struct sctp_association *__sctp_endpoint_lookup_assoc(
static struct sctp_association *__sctp_endpoint_lookup_assoc(
const struct sctp_endpoint *ep,
const union sctp_addr *paddr,
struct sctp_transport **transport)
......@@ -345,7 +345,7 @@ static void sctp_endpoint_bh_rcv(struct sctp_endpoint *ep)
sk = ep->base.sk;
while (NULL != (chunk = sctp_inq_pop(inqueue))) {
subtype.chunk = chunk->chunk_hdr->type;
subtype = SCTP_ST_CHUNK(chunk->chunk_hdr->type);
/* We might have grown an association since last we
* looked, so try again.
......
......@@ -63,11 +63,15 @@
/* Forward declarations for internal helpers. */
static int sctp_rcv_ootb(struct sk_buff *);
struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *laddr,
const union sctp_addr *paddr,
struct sctp_transport **transportp);
struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr);
static struct sctp_association *__sctp_lookup_association(
const union sctp_addr *local,
const union sctp_addr *peer,
struct sctp_transport **pt);
/* Calculate the SCTP checksum of an SCTP packet. */
......@@ -130,6 +134,10 @@ int sctp_rcv(struct sk_buff *skb)
skb_pull(skb, sizeof(struct sctphdr));
/* Make sure we at least have chunk headers worth of data left. */
if (skb->len < sizeof(struct sctp_chunkhdr))
goto discard_it;
family = ipver2af(skb->nh.iph->version);
af = sctp_get_af_specific(family);
if (unlikely(!af))
......@@ -284,6 +292,31 @@ void sctp_icmp_frag_needed(struct sock *sk, struct sctp_association *asoc,
}
}
/*
* SCTP Implementer's Guide, 2.37 ICMP handling procedures
*
* ICMP8) If the ICMP code is a "Unrecognized next header type encountered"
* or a "Protocol Unreachable" treat this message as an abort
* with the T bit set.
*
* This function sends an event to the state machine, which will abort the
* association.
*
*/
void sctp_icmp_proto_unreachable(struct sock *sk,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
struct sctp_transport *t)
{
SCTP_DEBUG_PRINTK("%s\n", __FUNCTION__);
sctp_do_sm(SCTP_EVENT_T_OTHER,
SCTP_ST_OTHER(SCTP_EVENT_ICMP_PROTO_UNREACH),
asoc->state, asoc->ep, asoc, NULL,
GFP_ATOMIC);
}
/* Common lookup code for icmp/icmpv6 error handler. */
struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
struct sctphdr *sctphdr,
......@@ -326,11 +359,12 @@ struct sock *sctp_err_lookup(int family, struct sk_buff *skb,
}
if (asoc) {
sk = asoc->base.sk;
if (ntohl(sctphdr->vtag) != asoc->c.peer_vtag) {
ICMP_INC_STATS_BH(ICMP_MIB_INERRORS);
goto out;
}
sk = asoc->base.sk;
} else
sk = ep->base.sk;
......@@ -432,7 +466,13 @@ void sctp_v4_err(struct sk_buff *skb, __u32 info)
sctp_icmp_frag_needed(sk, asoc, transport, info);
goto out_unlock;
}
else {
if (ICMP_PROT_UNREACH == code) {
sctp_icmp_proto_unreachable(sk, ep, asoc,
transport);
goto out_unlock;
}
}
err = icmp_err_convert[code].errno;
break;
case ICMP_TIME_EXCEEDED:
......@@ -479,10 +519,10 @@ int sctp_rcv_ootb(struct sk_buff *skb)
sctp_errhdr_t *err;
ch = (sctp_chunkhdr_t *) skb->data;
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
/* Scan through all the chunks in the packet. */
do {
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
while (ch_end > (__u8 *)ch && ch_end < skb->tail) {
/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
* receiver MUST silently discard the OOTB packet and take no
......@@ -513,7 +553,8 @@ int sctp_rcv_ootb(struct sk_buff *skb)
}
ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb->tail);
ch_end = ((__u8 *) ch) + WORD_ROUND(ntohs(ch->length));
}
return 0;
......@@ -522,7 +563,7 @@ int sctp_rcv_ootb(struct sk_buff *skb)
}
/* Insert endpoint into the hash table. */
void __sctp_hash_endpoint(struct sctp_endpoint *ep)
static void __sctp_hash_endpoint(struct sctp_endpoint *ep)
{
struct sctp_ep_common **epp;
struct sctp_ep_common *epb;
......@@ -552,7 +593,7 @@ void sctp_hash_endpoint(struct sctp_endpoint *ep)
}
/* Remove endpoint from the hash table. */
void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
static void __sctp_unhash_endpoint(struct sctp_endpoint *ep)
{
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
......@@ -584,7 +625,7 @@ void sctp_unhash_endpoint(struct sctp_endpoint *ep)
}
/* Look up an endpoint. */
struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
static struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
{
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
......@@ -610,16 +651,8 @@ struct sctp_endpoint *__sctp_rcv_lookup_endpoint(const union sctp_addr *laddr)
return ep;
}
/* Add an association to the hash. Local BH-safe. */
void sctp_hash_established(struct sctp_association *asoc)
{
sctp_local_bh_disable();
__sctp_hash_established(asoc);
sctp_local_bh_enable();
}
/* Insert association into the hash table. */
void __sctp_hash_established(struct sctp_association *asoc)
static void __sctp_hash_established(struct sctp_association *asoc)
{
struct sctp_ep_common **epp;
struct sctp_ep_common *epb;
......@@ -642,16 +675,16 @@ void __sctp_hash_established(struct sctp_association *asoc)
sctp_write_unlock(&head->lock);
}
/* Remove association from the hash table. Local BH-safe. */
void sctp_unhash_established(struct sctp_association *asoc)
/* Add an association to the hash. Local BH-safe. */
void sctp_hash_established(struct sctp_association *asoc)
{
sctp_local_bh_disable();
__sctp_unhash_established(asoc);
__sctp_hash_established(asoc);
sctp_local_bh_enable();
}
/* Remove association from the hash table. */
void __sctp_unhash_established(struct sctp_association *asoc)
static void __sctp_unhash_established(struct sctp_association *asoc)
{
struct sctp_hashbucket *head;
struct sctp_ep_common *epb;
......@@ -675,8 +708,16 @@ void __sctp_unhash_established(struct sctp_association *asoc)
sctp_write_unlock(&head->lock);
}
/* Remove association from the hash table. Local BH-safe. */
void sctp_unhash_established(struct sctp_association *asoc)
{
sctp_local_bh_disable();
__sctp_unhash_established(asoc);
sctp_local_bh_enable();
}
/* Look up an association. */
struct sctp_association *__sctp_lookup_association(
static struct sctp_association *__sctp_lookup_association(
const union sctp_addr *local,
const union sctp_addr *peer,
struct sctp_transport **pt)
......@@ -713,8 +754,9 @@ struct sctp_association *__sctp_lookup_association(
}
/* Look up an association. BH-safe. */
SCTP_STATIC
struct sctp_association *sctp_lookup_association(const union sctp_addr *laddr,
const union sctp_addr *paddr,
const union sctp_addr *paddr,
struct sctp_transport **transportp)
{
struct sctp_association *asoc;
......@@ -784,6 +826,14 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
return NULL;
}
/* The code below will attempt to walk the chunk and extract
* parameter information. Before we do that, we need to verify
* that the chunk length doesn't cause overflow. Otherwise, we'll
* walk off the end.
*/
if (WORD_ROUND(ntohs(ch->length)) > skb->len)
return NULL;
/*
* This code will NOT touch anything inside the chunk--it is
* strictly READ-ONLY.
......@@ -821,7 +871,7 @@ static struct sctp_association *__sctp_rcv_init_lookup(struct sk_buff *skb,
}
/* Lookup an association for an inbound skb. */
struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
static struct sctp_association *__sctp_rcv_lookup(struct sk_buff *skb,
const union sctp_addr *paddr,
const union sctp_addr *laddr,
struct sctp_transport **transportp)
......
......@@ -59,19 +59,6 @@ void sctp_inq_init(struct sctp_inq *queue)
queue->malloced = 0;
}
/* Create an initialized sctp_inq. */
struct sctp_inq *sctp_inq_new(void)
{
struct sctp_inq *retval;
retval = t_new(struct sctp_inq, GFP_ATOMIC);
if (retval) {
sctp_inq_init(retval);
retval->malloced = 1;
}
return retval;
}
/* Release the memory associated with an SCTP inqueue. */
void sctp_inq_free(struct sctp_inq *queue)
{
......@@ -157,14 +144,36 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
}
chunk->chunk_hdr = ch;
chunk->chunk_end = ((__u8 *) ch)
+ WORD_ROUND(ntohs(ch->length));
chunk->chunk_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
/* In the unlikely case of an IP reassembly, the skb could be
* non-linear. If so, update chunk_end so that it doesn't go past
* the skb->tail.
*/
if (unlikely(skb_is_nonlinear(chunk->skb))) {
if (chunk->chunk_end > chunk->skb->tail)
chunk->chunk_end = chunk->skb->tail;
}
skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
chunk->subh.v = NULL; /* Subheader is no longer valid. */
if (chunk->chunk_end < chunk->skb->tail) {
/* This is not a singleton */
chunk->singleton = 0;
} else if (chunk->chunk_end > chunk->skb->tail) {
/* RFC 2960, Section 6.10 Bundling
*
* Partial chunks MUST NOT be placed in an SCTP packet.
* If the receiver detects a partial chunk, it MUST drop
* the chunk.
*
* Since the end of the chunk is past the end of our buffer
* (which contains the whole packet, we can freely discard
* the whole packet.
*/
sctp_chunk_free(chunk);
chunk = queue->in_progress = NULL;
return NULL;
} else {
/* We are at the end of the packet, so mark the chunk
* in case we need to send a SACK.
......
......@@ -84,8 +84,8 @@ static struct notifier_block sctp_inet6addr_notifier = {
};
/* ICMP error handler. */
void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
SCTP_STATIC void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
int type, int code, int offset, __u32 info)
{
struct inet6_dev *idev;
struct ipv6hdr *iph = (struct ipv6hdr *)skb->data;
......@@ -122,6 +122,12 @@ void sctp_v6_err(struct sk_buff *skb, struct inet6_skb_parm *opt,
case ICMPV6_PKT_TOOBIG:
sctp_icmp_frag_needed(sk, asoc, transport, ntohl(info));
goto out_unlock;
case ICMPV6_PARAMPROB:
if (ICMPV6_UNK_NEXTHDR == code) {
sctp_icmp_proto_unreachable(sk, ep, asoc, transport);
goto out_unlock;
}
break;
default:
break;
}
......@@ -188,9 +194,9 @@ static int sctp_v6_xmit(struct sk_buff *skb, struct sctp_transport *transport,
/* Returns the dst cache entry for the given source and destination ip
* addresses.
*/
struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
static struct dst_entry *sctp_v6_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct dst_entry *dst;
struct flowi fl;
......@@ -251,8 +257,10 @@ static inline int sctp_v6_addr_match_len(union sctp_addr *s1,
/* Fills in the source address(saddr) based on the destination address(daddr)
* and asoc's bind address list.
*/
void sctp_v6_get_saddr(struct sctp_association *asoc, struct dst_entry *dst,
union sctp_addr *daddr, union sctp_addr *saddr)
static void sctp_v6_get_saddr(struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct sctp_bind_addr *bp;
rwlock_t *addr_lock;
......@@ -577,8 +585,8 @@ static sctp_scope_t sctp_v6_scope(union sctp_addr *addr)
}
/* 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)
static struct sock *sctp_v6_create_accept_sk(struct sock *sk,
struct sctp_association *asoc)
{
struct inet_sock *inet = inet_sk(sk);
struct sock *newsk;
......
......@@ -62,7 +62,7 @@ SCTP_DBG_OBJCNT(datamsg);
/* An array to make it easy to pretty print the debug information
* to the proc fs.
*/
sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
static sctp_dbg_objcnt_entry_t sctp_dbg_objcnt[] = {
SCTP_DBG_OBJCNT_ENTRY(sock),
SCTP_DBG_OBJCNT_ENTRY(ep),
SCTP_DBG_OBJCNT_ENTRY(assoc),
......
......@@ -190,19 +190,6 @@ static inline int sctp_cacc_skip(struct sctp_transport *primary,
return 0;
}
/* Generate a new outqueue. */
struct sctp_outq *sctp_outq_new(struct sctp_association *asoc)
{
struct sctp_outq *q;
q = t_new(struct sctp_outq, GFP_KERNEL);
if (q) {
sctp_outq_init(asoc, q);
q->malloced = 1;
}
return q;
}
/* Initialize an existing sctp_outq. This does the boring stuff.
* You still need to define handlers if you really want to DO
* something with this structure...
......@@ -362,7 +349,7 @@ int sctp_outq_tail(struct sctp_outq *q, struct sctp_chunk *chunk)
/* Insert a chunk into the sorted list based on the TSNs. The retransmit list
* and the abandoned list are in ascending order.
*/
void sctp_insert_list(struct list_head *head, struct list_head *new)
static void sctp_insert_list(struct list_head *head, struct list_head *new)
{
struct list_head *pos;
struct sctp_chunk *nchunk, *lchunk;
......
......@@ -39,7 +39,7 @@
#include <linux/init.h>
#include <net/sctp/sctp.h>
struct snmp_mib sctp_snmp_list[] = {
static struct snmp_mib sctp_snmp_list[] = {
SNMP_MIB_ITEM("SctpCurrEstab", SCTP_MIB_CURRESTAB),
SNMP_MIB_ITEM("SctpActiveEstabs", SCTP_MIB_ACTIVEESTABS),
SNMP_MIB_ITEM("SctpPassiveEstabs", SCTP_MIB_PASSIVEESTABS),
......
......@@ -95,7 +95,7 @@ struct sock *sctp_get_ctl_sock(void)
}
/* Set up the proc fs entry for the SCTP protocol. */
__init int sctp_proc_init(void)
static __init int sctp_proc_init(void)
{
if (!proc_net_sctp) {
struct proc_dir_entry *ent;
......@@ -124,7 +124,7 @@ __init int sctp_proc_init(void)
* Note: Do not make this __exit as it is used in the init error
* path.
*/
void sctp_proc_exit(void)
static void sctp_proc_exit(void)
{
sctp_snmp_proc_exit();
sctp_eps_proc_exit();
......@@ -428,9 +428,9 @@ static sctp_scope_t sctp_v4_scope(union sctp_addr *addr)
* addresses. If an association is passed, trys to get a dst entry with a
* source address that matches an address in the bind address list.
*/
struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
static struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct rtable *rt;
struct flowi fl;
......@@ -520,10 +520,10 @@ struct dst_entry *sctp_v4_get_dst(struct sctp_association *asoc,
/* For v4, the source address is cached in the route entry(dst). So no need
* to cache it separately and hence this is an empty routine.
*/
void sctp_v4_get_saddr(struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
static void sctp_v4_get_saddr(struct sctp_association *asoc,
struct dst_entry *dst,
union sctp_addr *daddr,
union sctp_addr *saddr)
{
struct rtable *rt = (struct rtable *)dst;
......@@ -547,8 +547,8 @@ static int sctp_v4_is_ce(const struct sk_buff *skb)
}
/* 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)
static struct sock *sctp_v4_create_accept_sk(struct sock *sk,
struct sctp_association *asoc)
{
struct sock *newsk;
struct inet_sock *inet = inet_sk(sk);
......@@ -639,7 +639,7 @@ int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
* Initialize the control inode/socket with a control endpoint data
* structure. This endpoint is reserved exclusively for the OOTB processing.
*/
int sctp_ctl_sock_init(void)
static int sctp_ctl_sock_init(void)
{
int err;
sa_family_t family;
......@@ -808,7 +808,7 @@ static inline int sctp_v4_xmit(struct sk_buff *skb,
return ip_queue_xmit(skb, ipfragok);
}
struct sctp_af sctp_ipv4_specific;
static struct sctp_af sctp_ipv4_specific;
static struct sctp_pf sctp_pf_inet = {
.event_msgname = sctp_inet_event_msgname,
......@@ -829,7 +829,7 @@ static struct notifier_block sctp_inetaddr_notifier = {
};
/* Socket operations. */
struct proto_ops inet_seqpacket_ops = {
static struct proto_ops inet_seqpacket_ops = {
.family = PF_INET,
.owner = THIS_MODULE,
.release = inet_release, /* Needs to be wrapped... */
......@@ -878,7 +878,7 @@ static struct net_protocol sctp_protocol = {
};
/* IPv4 address related functions. */
struct sctp_af sctp_ipv4_specific = {
static struct sctp_af sctp_ipv4_specific = {
.sctp_xmit = sctp_v4_xmit,
.setsockopt = ip_setsockopt,
.getsockopt = ip_getsockopt,
......@@ -959,7 +959,7 @@ static void cleanup_sctp_mibs(void)
}
/* Initialize the universe into something sensible. */
__init int sctp_init(void)
SCTP_STATIC __init int sctp_init(void)
{
int i;
int status = -EINVAL;
......@@ -1196,7 +1196,7 @@ __init int sctp_init(void)
}
/* Exit handler for the SCTP protocol. */
__exit void sctp_exit(void)
SCTP_STATIC __exit void sctp_exit(void)
{
/* BUG. This should probably do something useful like clean
* up all the remaining associations and all that memory.
......
......@@ -67,6 +67,19 @@
extern kmem_cache_t *sctp_chunk_cachep;
SCTP_STATIC
struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen);
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *init_chunk,
int *cookie_len,
const __u8 *raw_addrs, int addrs_len);
static int sctp_process_param(struct sctp_association *asoc,
union sctp_params param,
const union sctp_addr *peer_addr,
int gfp);
/* What was the inbound interface for this chunk? */
int sctp_chunk_iif(const struct sctp_chunk *chunk)
{
......@@ -559,52 +572,6 @@ struct sctp_chunk *sctp_make_datafrag_empty(struct sctp_association *asoc,
return retval;
}
/* Make a DATA chunk for the given association. Populate the data
* payload.
*/
struct sctp_chunk *sctp_make_datafrag(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo,
int data_len, const __u8 *data,
__u8 flags, __u16 ssn)
{
struct sctp_chunk *retval;
retval = sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, ssn);
if (retval)
sctp_addto_chunk(retval, data_len, data);
return retval;
}
/* Make a DATA chunk for the given association to ride on stream id
* 'stream', with a payload id of 'payload', and a body of 'data'.
*/
struct sctp_chunk *sctp_make_data(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo,
int data_len, const __u8 *data)
{
struct sctp_chunk *retval = NULL;
retval = sctp_make_data_empty(asoc, sinfo, data_len);
if (retval)
sctp_addto_chunk(retval, data_len, data);
return retval;
}
/* Make a DATA chunk for the given association to ride on stream id
* 'stream', with a payload id of 'payload', and a body big enough to
* hold 'data_len' octets of data. We use this version when we need
* to build the message AFTER allocating memory.
*/
struct sctp_chunk *sctp_make_data_empty(struct sctp_association *asoc,
const struct sctp_sndrcvinfo *sinfo,
int data_len)
{
__u8 flags = SCTP_DATA_NOT_FRAG;
return sctp_make_datafrag_empty(asoc, sinfo, data_len, flags, 0);
}
/* Create a selective ackowledgement (SACK) for the given
* association. This reports on which TSN's we've seen to date,
* including duplicates and gaps.
......@@ -881,6 +848,31 @@ struct sctp_chunk *sctp_make_abort_user(const struct sctp_association *asoc,
return retval;
}
/* Make an ABORT chunk with a PROTOCOL VIOLATION cause code. */
struct sctp_chunk *sctp_make_abort_violation(
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
const __u8 *payload,
const size_t paylen)
{
struct sctp_chunk *retval;
struct sctp_paramhdr phdr;
retval = sctp_make_abort(asoc, chunk, sizeof(sctp_errhdr_t) + paylen
+ sizeof(sctp_chunkhdr_t));
if (!retval)
goto end;
sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, payload, paylen);
phdr.type = htons(chunk->chunk_hdr->type);
phdr.length = chunk->chunk_hdr->length;
sctp_addto_chunk(retval, sizeof(sctp_paramhdr_t), &phdr);
end:
return retval;
}
/* Make a HEARTBEAT chunk. */
struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc,
const struct sctp_transport *transport,
......@@ -933,7 +925,7 @@ struct sctp_chunk *sctp_make_heartbeat_ack(const struct sctp_association *asoc,
/* Create an Operation Error chunk with the specified space reserved.
* This routine can be used for containing multiple causes in the chunk.
*/
struct sctp_chunk *sctp_make_op_error_space(
static struct sctp_chunk *sctp_make_op_error_space(
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
size_t size)
......@@ -1034,7 +1026,6 @@ struct sctp_chunk *sctp_chunkify(struct sk_buff *skb,
SCTP_DBG_OBJCNT_INC(chunk);
atomic_set(&retval->refcnt, 1);
nodata:
return retval;
}
......@@ -1062,6 +1053,7 @@ const union sctp_addr *sctp_source(const struct sctp_chunk *chunk)
/* Create a new chunk, setting the type and flags headers from the
* arguments, reserving enough space for a 'paylen' byte payload.
*/
SCTP_STATIC
struct sctp_chunk *sctp_make_chunk(const struct sctp_association *asoc,
__u8 type, __u8 flags, int paylen)
{
......@@ -1261,7 +1253,7 @@ struct sctp_association *sctp_make_temp_asoc(const struct sctp_endpoint *ep,
/* Build a cookie representing asoc.
* This INCLUDES the param header needed to put the cookie in the INIT ACK.
*/
sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
static sctp_cookie_param_t *sctp_pack_cookie(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *init_chunk,
int *cookie_len,
......@@ -1409,6 +1401,24 @@ struct sctp_association *sctp_unpack_cookie(
}
no_hmac:
/* IG Section 2.35.2:
* 3) Compare the port numbers and the verification tag contained
* within the COOKIE ECHO chunk to the actual port numbers and the
* verification tag within the SCTP common header of the received
* packet. If these values do not match the packet MUST be silently
* discarded,
*/
if (ntohl(chunk->sctp_hdr->vtag) != bear_cookie->my_vtag) {
*error = -SCTP_IERROR_BAD_TAG;
goto fail;
}
if (ntohs(chunk->sctp_hdr->source) != bear_cookie->peer_addr.v4.sin_port ||
ntohs(chunk->sctp_hdr->dest) != bear_cookie->my_port) {
*error = -SCTP_IERROR_BAD_PORTS;
goto fail;
}
/* Check to see if the cookie is stale. If there is already
* an association, there is no need to check cookie's expiration
* for init collision case of lost COOKIE ACK.
......@@ -1547,6 +1557,30 @@ static int sctp_process_inv_mandatory(const struct sctp_association *asoc,
return 0;
}
static int sctp_process_inv_paramlength(const struct sctp_association *asoc,
struct sctp_paramhdr *param,
const struct sctp_chunk *chunk,
struct sctp_chunk **errp)
{
char error[] = "The following parameter had invalid length:";
size_t payload_len = WORD_ROUND(sizeof(error)) +
sizeof(sctp_paramhdr_t);
/* Create an error chunk and fill it in with our payload. */
if (!*errp)
*errp = sctp_make_op_error_space(asoc, chunk, payload_len);
if (*errp) {
sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, error,
sizeof(error));
sctp_addto_chunk(*errp, sizeof(sctp_paramhdr_t), param);
}
return 0;
}
/* Do not attempt to handle the HOST_NAME parm. However, do
* send back an indicator to the peer.
*/
......@@ -1725,6 +1759,18 @@ int sctp_verify_init(const struct sctp_association *asoc,
} /* for (loop through all parameters) */
/* There is a possibility that a parameter length was bad and
* in that case we would have stoped walking the parameters.
* The current param.p would point at the bad one.
* Current consensus on the mailing list is to generate a PROTOCOL
* VIOLATION error. We build the ERROR chunk here and let the normal
* error handling code build and send the packet.
*/
if (param.v < (void*)chunk->chunk_end - sizeof(sctp_paramhdr_t)) {
sctp_process_inv_paramlength(asoc, param.p, chunk, errp);
return 0;
}
/* The only missing mandatory param possible today is
* the state cookie for an INIT-ACK chunk.
*/
......@@ -1912,8 +1958,10 @@ int sctp_process_init(struct sctp_association *asoc, sctp_cid_t cid,
* work we do. In particular, we should not build transport
* structures for the addresses.
*/
int sctp_process_param(struct sctp_association *asoc, union sctp_params param,
const union sctp_addr *peer_addr, int gfp)
static int sctp_process_param(struct sctp_association *asoc,
union sctp_params param,
const union sctp_addr *peer_addr,
int gfp)
{
union sctp_addr addr;
int i;
......@@ -2078,8 +2126,9 @@ __u32 sctp_generate_tsn(const struct sctp_endpoint *ep)
*
* Address Parameter and other parameter will not be wrapped in this function
*/
struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
union sctp_addr *addr, int vparam_len)
static struct sctp_chunk *sctp_make_asconf(struct sctp_association *asoc,
union sctp_addr *addr,
int vparam_len)
{
sctp_addiphdr_t asconf;
struct sctp_chunk *retval;
......@@ -2248,8 +2297,8 @@ struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
*
* Create an ASCONF_ACK chunk with enough space for the parameter responses.
*/
struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
__u32 serial, int vparam_len)
static struct sctp_chunk *sctp_make_asconf_ack(const struct sctp_association *asoc,
__u32 serial, int vparam_len)
{
sctp_addiphdr_t asconf;
struct sctp_chunk *retval;
......
......@@ -55,6 +55,24 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp);
static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp);
/********************************************************************
* Helper functions
********************************************************************/
......@@ -134,8 +152,8 @@ static void sctp_do_ecn_cwr_work(struct sctp_association *asoc,
}
/* Generate SACK if necessary. We call this at the end of a packet. */
int sctp_gen_sack(struct sctp_association *asoc, int force,
sctp_cmd_seq_t *commands)
static int sctp_gen_sack(struct sctp_association *asoc, int force,
sctp_cmd_seq_t *commands)
{
__u32 ctsn, max_tsn_seen;
struct sctp_chunk *sack;
......@@ -276,31 +294,31 @@ static void sctp_generate_timeout_event(struct sctp_association *asoc,
sctp_association_put(asoc);
}
void sctp_generate_t1_cookie_event(unsigned long data)
static void sctp_generate_t1_cookie_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_COOKIE);
}
void sctp_generate_t1_init_event(unsigned long data)
static void sctp_generate_t1_init_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T1_INIT);
}
void sctp_generate_t2_shutdown_event(unsigned long data)
static void sctp_generate_t2_shutdown_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T2_SHUTDOWN);
}
void sctp_generate_t4_rto_event(unsigned long data)
static void sctp_generate_t4_rto_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_T4_RTO);
}
void sctp_generate_t5_shutdown_guard_event(unsigned long data)
static void sctp_generate_t5_shutdown_guard_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *)data;
sctp_generate_timeout_event(asoc,
......@@ -308,7 +326,7 @@ void sctp_generate_t5_shutdown_guard_event(unsigned long data)
} /* sctp_generate_t5_shutdown_guard_event() */
void sctp_generate_autoclose_event(unsigned long data)
static void sctp_generate_autoclose_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_AUTOCLOSE);
......@@ -353,7 +371,7 @@ void sctp_generate_heartbeat_event(unsigned long data)
}
/* Inject a SACK Timeout event into the state machine. */
void sctp_generate_sack_event(unsigned long data)
static void sctp_generate_sack_event(unsigned long data)
{
struct sctp_association *asoc = (struct sctp_association *) data;
sctp_generate_timeout_event(asoc, SCTP_EVENT_TIMEOUT_SACK);
......@@ -397,7 +415,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
asoc->overall_error_count++;
if (transport->active &&
(transport->error_count++ >= transport->error_threshold)) {
(transport->error_count++ >= transport->max_retrans)) {
SCTP_DEBUG_PRINTK("transport_strike: transport "
"IP:%d.%d.%d.%d failed.\n",
NIPQUAD(transport->ipaddr.v4.sin_addr));
......@@ -857,14 +875,14 @@ int sctp_do_sm(sctp_event_t event_type, sctp_subtype_t subtype,
/*****************************************************************
* This the master state function side effect processing function.
*****************************************************************/
int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp)
static int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp)
{
int error;
......@@ -944,11 +962,15 @@ int sctp_side_effects(sctp_event_t event_type, sctp_subtype_t subtype,
********************************************************************/
/* This is the side-effect interpreter. */
int sctp_cmd_interpreter(sctp_event_t event_type, sctp_subtype_t subtype,
sctp_state_t state, struct sctp_endpoint *ep,
struct sctp_association *asoc, void *event_arg,
sctp_disposition_t status, sctp_cmd_seq_t *commands,
int gfp)
static int sctp_cmd_interpreter(sctp_event_t event_type,
sctp_subtype_t subtype,
sctp_state_t state,
struct sctp_endpoint *ep,
struct sctp_association *asoc,
void *event_arg,
sctp_disposition_t status,
sctp_cmd_seq_t *commands,
int gfp)
{
int error = 0;
int force;
......
......@@ -65,6 +65,53 @@
#include <net/sctp/sm.h>
#include <net/sctp/structs.h>
static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
const void *payload,
size_t paylen);
static int sctp_eat_data(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands);
static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
const struct sctp_chunk *chunk);
static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands,
struct sctp_chunk *err_chunk);
static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands);
static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands);
static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
/* Small helper function that checks if the chunk length
* is of the appropriate length. The 'required_length' argument
* is set to be the size of a specific chunk we are testing.
* Return Values: 1 = Valid length
* 0 = Invalid length
*
*/
static inline int
sctp_chunk_length_valid(struct sctp_chunk *chunk,
__u16 required_length)
{
__u16 chunk_length = ntohs(chunk->chunk_hdr->length);
if (unlikely(chunk_length < required_length))
return 0;
return 1;
}
/**********************************************************
* These are the state functions for handling chunk events.
**********************************************************/
......@@ -199,9 +246,14 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*
* IG Section 2.11.2
* Furthermore, we require that the receiver of an INIT chunk MUST
* enforce these rules by silently discarding an arriving packet
* with an INIT chunk that is bundled with other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* If the packet is an OOTB packet which is temporarily on the
* control endpoint, respond with an ABORT.
......@@ -225,6 +277,14 @@ sctp_disposition_t sctp_sf_do_5_1B_init(const struct sctp_endpoint *ep,
if (chunk->sctp_hdr->vtag != 0)
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* Make sure that the INIT chunk has a valid length.
* Normally, this would cause an ABORT with a Protocol Violation
* error, but since we don't have an association, we'll
* just discard the packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Verify the INIT chunk before processing it. */
err_chunk = NULL;
if (!sctp_verify_init(asoc, chunk->chunk_hdr->type,
......@@ -376,6 +436,13 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
struct sctp_packet *packet;
sctp_disposition_t ret;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the INIT-ACK chunk has a valid length */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_initack_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
......@@ -383,9 +450,6 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
......@@ -542,6 +606,14 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands);
/* Make sure that the COOKIE_ECHO chunk has a valid length.
* In this case, we check that we have enough for at least a
* chunk header. More detailed verification is done
* in sctp_unpack_cookie().
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
*/
......@@ -687,6 +759,13 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Verify that the chunk length for the COOKIE-ACK is OK.
* If we don't do this, any bundled chunks may be junked.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* Reset init error count upon receipt of COOKIE-ACK,
* to avoid problems with the managemement of this
* counter in stale cookie situations when a transition back
......@@ -748,11 +827,11 @@ sctp_disposition_t sctp_sf_do_5_1E_ca(const struct sctp_endpoint *ep,
}
/* Generate and sendout a heartbeat packet. */
sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
static sctp_disposition_t sctp_sf_heartbeat(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_transport *transport = (struct sctp_transport *) arg;
struct sctp_chunk *reply;
......@@ -859,6 +938,11 @@ sctp_disposition_t sctp_sf_beat_8_3(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the HEARTBEAT chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* 8.3 The receiver of the HEARTBEAT should immediately
* respond with a HEARTBEAT ACK that contains the Heartbeat
* Information field copied from the received HEARTBEAT chunk.
......@@ -922,6 +1006,11 @@ sctp_disposition_t sctp_sf_backbeat_8_3(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the HEARTBEAT-ACK chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_heartbeat_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data;
from_addr = hbinfo->daddr;
link = sctp_assoc_lookup_paddr(asoc, &from_addr);
......@@ -1165,9 +1254,14 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
/* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks.
*
* IG Section 2.11.2
* Furthermore, we require that the receiver of an INIT chunk MUST
* enforce these rules by silently discarding an arriving packet
* with an INIT chunk that is bundled with other chunks.
*/
if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION;
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* 3.1 A packet containing an INIT chunk MUST have a zero Verification
* Tag.
......@@ -1175,6 +1269,13 @@ static sctp_disposition_t sctp_sf_do_unexpected_init(
if (chunk->sctp_hdr->vtag != 0)
return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* Make sure that the INIT chunk has a valid length.
* In this case, we generate a protocol violation since we have
* an association established.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_init_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
......@@ -1718,6 +1819,15 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupcook(const struct sctp_endpoint *ep,
char action;
struct sctp_chunk *err_chk_p;
/* Make sure that the chunk has a valid length from the protocol
* perspective. In this case check to make sure we have at least
* enough for the chunk header. Cookie length verification is
* done later.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* "Decode" the chunk. We have no optional parameters so we
* are in good shape.
*/
......@@ -1815,6 +1925,19 @@ sctp_disposition_t sctp_sf_shutdown_pending_abort(
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the ABORT chunk has a valid length.
* Since this is an ABORT chunk, we have to discard it
* because of the following text:
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
* Becasue the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Stop the T5-shutdown guard timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T5_SHUTDOWN_GUARD));
......@@ -1838,6 +1961,19 @@ sctp_disposition_t sctp_sf_shutdown_sent_abort(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the ABORT chunk has a valid length.
* Since this is an ABORT chunk, we have to discard it
* because of the following text:
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
* Becasue the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Stop the T2-shutdown timer. */
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T2_SHUTDOWN));
......@@ -1890,6 +2026,16 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg;
sctp_errhdr_t *err;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the ERROR chunk has a valid length.
* The parameter walking depends on this as well.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* Process the error here */
/* FUTURE FIXME: When PR-SCTP related and other optional
* parms are emitted, this will have to change to handle multiple
......@@ -1900,6 +2046,12 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
return sctp_sf_do_5_2_6_stale(ep, asoc, type,
arg, commands);
}
/* It is possible to have malformed error causes, and that
* will cause us to end the walk early. However, since
* we are discarding the packet, there should be no adverse
* affects.
*/
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
......@@ -1928,11 +2080,11 @@ sctp_disposition_t sctp_sf_cookie_echoed_err(const struct sctp_endpoint *ep,
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
static sctp_disposition_t sctp_sf_do_5_2_6_stale(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
time_t stale;
......@@ -2064,12 +2216,24 @@ sctp_disposition_t sctp_sf_do_9_1_abort(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Check that chunk header looks valid. */
/* Make sure that the ABORT chunk has a valid length.
* Since this is an ABORT chunk, we have to discard it
* because of the following text:
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
* Becasue the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* See if we have an error cause code in the chunk. */
len = ntohs(chunk->chunk_hdr->length);
if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
/* ASSOC_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, SCTP_U32(error));
SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
......@@ -2096,27 +2260,43 @@ sctp_disposition_t sctp_sf_cookie_wait_abort(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
/* Make sure that the ABORT chunk has a valid length.
* Since this is an ABORT chunk, we have to discard it
* because of the following text:
* RFC 2960, Section 3.3.7
* If an endpoint receives an ABORT with a format error or for an
* association that doesn't exist, it MUST silently discard it.
* Becasue the length is "invalid", we can't really discard just
* as we do not know its true length. So, to be safe, discard the
* packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_abort_chunk_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Check that chunk header looks valid. */
/* See if we have an error cause code in the chunk. */
len = ntohs(chunk->chunk_hdr->length);
if (len >= sizeof(struct sctp_chunkhdr) + sizeof(struct sctp_errhdr))
error = ((sctp_errhdr_t *)chunk->skb->data)->cause;
/* CMD_INIT_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, SCTP_U32(error));
sctp_stop_t1_and_abort(commands, error);
return SCTP_DISPOSITION_ABORT;
}
/*
* Process an incoming ICMP as an ABORT. (COOKIE-WAIT state)
*/
sctp_disposition_t sctp_sf_cookie_wait_icmp_abort(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
sctp_stop_t1_and_abort(commands, SCTP_ERROR_NO_ERROR);
return SCTP_DISPOSITION_ABORT;
}
/*
* Process an ABORT. (COOKIE-ECHOED state)
*
* See sctp_sf_do_9_1_abort() above.
*/
sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
......@@ -2130,6 +2310,23 @@ sctp_disposition_t sctp_sf_cookie_echoed_abort(const struct sctp_endpoint *ep,
return sctp_sf_cookie_wait_abort(ep, asoc, type, arg, commands);
}
/*
* Stop T1 timer and abort association with "INIT failed".
*
* This is common code called by several sctp_sf_*_abort() functions above.
*/
void sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, __u16 error)
{
sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE,
SCTP_STATE(SCTP_STATE_CLOSED));
SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
/* CMD_INIT_FAILED will DELETE_TCB. */
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(error));
}
/*
* sctp_sf_do_9_2_shut
*
......@@ -2174,14 +2371,20 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown(const struct sctp_endpoint *ep,
sctp_disposition_t disposition;
struct sctp_ulpevent *ev;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the SHUTDOWN chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk,
sizeof(struct sctp_shutdown_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* Convert the elaborate header. */
sdh = (sctp_shutdownhdr_t *)chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_shutdownhdr_t));
chunk->subh.shutdown_hdr = sdh;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Upon the reception of the SHUTDOWN, the peer endpoint shall
* - enter the SHUTDOWN-RECEIVED state,
* - stop accepting new data from its SCTP user
......@@ -2238,6 +2441,10 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
struct sctp_chunk *reply;
/* Since we are not going to really process this INIT, there
* is no point in verifying chunk boundries. Just generate
* the SHUTDOWN ACK.
*/
reply = sctp_make_shutdown_ack(asoc, chunk);
if (NULL == reply)
goto nomem;
......@@ -2295,6 +2502,10 @@ sctp_disposition_t sctp_sf_do_ecn_cwr(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
cwr = (sctp_cwrhdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_cwrhdr_t));
......@@ -2345,6 +2556,10 @@ sctp_disposition_t sctp_sf_do_ecne(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_ecne_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
ecne = (sctp_ecnehdr_t *) chunk->skb->data;
skb_pull(chunk->skb, sizeof(sctp_ecnehdr_t));
......@@ -2400,6 +2615,10 @@ sctp_disposition_t sctp_sf_eat_data_6_2(const struct sctp_endpoint *ep,
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
error = sctp_eat_data(asoc, chunk, commands );
switch (error) {
case SCTP_IERROR_NO_ERROR:
......@@ -2517,6 +2736,10 @@ sctp_disposition_t sctp_sf_eat_data_fast_4_4(const struct sctp_endpoint *ep,
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_data_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
error = sctp_eat_data(asoc, chunk, commands );
switch (error) {
case SCTP_IERROR_NO_ERROR:
......@@ -2598,6 +2821,11 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the SACK chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_sack_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* Pull the SACK chunk from the data buffer */
sackh = sctp_sm_pull_sack(chunk);
/* Was this a bogus SACK? */
......@@ -2700,6 +2928,14 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg;
struct sctp_ulpevent *ev;
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the ERROR chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_operr_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
while (chunk->chunk_end > chunk->skb->data) {
ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
GFP_ATOMIC);
......@@ -2744,6 +2980,11 @@ sctp_disposition_t sctp_sf_do_9_2_final(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the SHUTDOWN_ACK chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* 10.2 H) SHUTDOWN COMPLETE notification
*
* When SCTP completes the shutdown procedures (section 9.2) this
......@@ -2818,11 +3059,23 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
do {
/* Break out if chunk length is less then minimal. */
if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
break;
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (SCTP_CID_SHUTDOWN_ACK == ch->type)
ootb_shut_ack = 1;
/* RFC 2960, Section 3.3.7
* Moreover, under any circumstances, an endpoint that
* receives an ABORT MUST NOT respond to that ABORT by
* sending an ABORT of its own.
*/
if (SCTP_CID_ABORT == ch->type)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb->tail);
......@@ -2853,11 +3106,11 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
*
* The return value is the disposition of the chunk.
*/
sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_packet *packet = NULL;
struct sctp_chunk *chunk = arg;
......@@ -2885,6 +3138,12 @@ sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
/* If the chunk length is invalid, we don't want to process
* the reset of the packet.
*/
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME;
}
......@@ -2927,6 +3186,17 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
sctp_addiphdr_t *hdr;
__u32 serial;
if (!sctp_vtag_verify(chunk, asoc)) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
SCTP_NULL());
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/* Make sure that the ASCONF ADDIP chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_addip_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
hdr = (sctp_addiphdr_t *)chunk->skb->data;
serial = ntohl(hdr->serial);
......@@ -2947,7 +3217,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
/* ADDIP 4.2 C3) If the value found in the serial number is
* equal to the value stored in the 'Peer-Serial-Number'
* IMPLEMENTATION NOTE: As an optimization a receiver may wish
* to save the last ASCONF-ACK for some predetermined period of * time and instead of re-processing the ASCONF (with the same
* to save the last ASCONF-ACK for some predetermined period of
* time and instead of re-processing the ASCONF (with the same
* serial number) it may just re-transmit the ASCONF-ACK.
*/
if (asoc->addip_last_asconf_ack)
......@@ -2986,6 +3257,17 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
sctp_addiphdr_t *addip_hdr;
__u32 sent_serial, rcvd_serial;
if (!sctp_vtag_verify(asconf_ack, asoc)) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
SCTP_NULL());
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/* Make sure that the ADDIP chunk has a valid length. */
if (!sctp_chunk_length_valid(asconf_ack, sizeof(sctp_addip_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
rcvd_serial = ntohl(addip_hdr->serial);
......@@ -3084,6 +3366,11 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn(const struct sctp_endpoint *ep,
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/* Make sure that the FORWARD_TSN chunk has valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
len = ntohs(chunk->chunk_hdr->length);
......@@ -3142,6 +3429,11 @@ sctp_disposition_t sctp_sf_eat_fwd_tsn_fast(
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
}
/* Make sure that the FORWARD_TSN chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_fwdtsn_chunk)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
fwdtsn_hdr = (struct sctp_fwdtsn_hdr *)chunk->skb->data;
chunk->subh.fwdtsn_hdr = fwdtsn_hdr;
len = ntohs(chunk->chunk_hdr->length);
......@@ -3216,6 +3508,14 @@ sctp_disposition_t sctp_sf_unk_chunk(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(unk_chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the chunk has a valid length.
* Since we don't know the chunk type, we use a general
* chunkhdr structure to make a comparison.
*/
if (!sctp_chunk_length_valid(unk_chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
switch (type.chunk & SCTP_CID_ACTION_MASK) {
case SCTP_CID_ACTION_DISCARD:
/* Discard the packet. */
......@@ -3338,6 +3638,66 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
return SCTP_DISPOSITION_VIOLATION;
}
/*
* Handle a protocol violation when the chunk length is invalid.
* "Invalid" length is identified as smaller then the minimal length a
* given chunk can be. For example, a SACK chunk has invalid length
* if it's length is set to be smaller then the size of sctp_sack_chunk_t.
*
* We inform the other end by sending an ABORT with a Protocol Violation
* error code.
*
* Section: Not specified
* Verification Tag: Nothing to do
* Inputs
* (endpoint, asoc, chunk)
*
* Outputs
* (reply_msg, msg_up, counters)
*
* Generate an ABORT chunk and terminate the association.
*/
sctp_disposition_t sctp_sf_violation_chunklen(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
struct sctp_chunk *chunk = arg;
struct sctp_chunk *abort = NULL;
char err_str[]="The following chunk had invalid length:";
/* Make the abort chunk. */
abort = sctp_make_abort_violation(asoc, chunk, err_str,
sizeof(err_str));
if (!abort)
goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
} else {
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_U32(SCTP_ERROR_PROTO_VIOLATION));
SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
}
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL());
SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
return SCTP_DISPOSITION_ABORT;
nomem:
return SCTP_DISPOSITION_NOMEM;
}
/***************************************************************************
* These are the state functions for handling primitive (Section 10) events.
***************************************************************************/
......@@ -4050,6 +4410,23 @@ sctp_disposition_t sctp_sf_do_9_2_shutdown_ack(
struct sctp_chunk *chunk = (struct sctp_chunk *) arg;
struct sctp_chunk *reply;
/* There are 2 ways of getting here:
* 1) called in response to a SHUTDOWN chunk
* 2) called when SCTP_EVENT_NO_PENDING_TSN event is issued.
*
* For the case (2), the arg parameter is set to NULL. We need
* to check that we have a chunk before accessing it's fields.
*/
if (chunk) {
if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Make sure that the SHUTDOWN chunk has a valid length. */
if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_shutdown_chunk_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
}
/* If it has no more outstanding DATA chunks, the SHUTDOWN receiver
* shall send a SHUTDOWN ACK ...
*/
......@@ -4537,7 +4914,7 @@ sctp_disposition_t sctp_sf_timer_ignore(const struct sctp_endpoint *ep,
********************************************************************/
/* Pull the SACK chunk based on the SACK header. */
struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
{
struct sctp_sackhdr *sack;
unsigned int len;
......@@ -4564,7 +4941,7 @@ struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk)
/* Create an ABORT packet to be sent as a response, with the specified
* error causes.
*/
struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
static struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
struct sctp_chunk *chunk,
const void *payload,
......@@ -4600,8 +4977,8 @@ struct sctp_packet *sctp_abort_pkt_new(const struct sctp_endpoint *ep,
}
/* Allocate a packet for responding in the OOTB conditions. */
struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
const struct sctp_chunk *chunk)
static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc,
const struct sctp_chunk *chunk)
{
struct sctp_packet *packet;
struct sctp_transport *transport;
......@@ -4664,11 +5041,11 @@ void sctp_ootb_pkt_free(struct sctp_packet *packet)
}
/* Send a stale cookie error when a invalid COOKIE ECHO chunk is found */
void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands,
struct sctp_chunk *err_chunk)
static void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands,
struct sctp_chunk *err_chunk)
{
struct sctp_packet *packet;
......@@ -4694,9 +5071,9 @@ void sctp_send_stale_cookie_err(const struct sctp_endpoint *ep,
/* Process a data chunk */
int sctp_eat_data(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands)
static int sctp_eat_data(const struct sctp_association *asoc,
struct sctp_chunk *chunk,
sctp_cmd_seq_t *commands)
{
sctp_datahdr_t *data_hdr;
struct sctp_chunk *err;
......
......@@ -50,6 +50,17 @@
#include <net/sctp/sctp.h>
#include <net/sctp/sm.h>
static const sctp_sm_table_entry_t
primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES];
static const sctp_sm_table_entry_t
other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES];
static const sctp_sm_table_entry_t
timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES];
static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
sctp_state_t state);
static const sctp_sm_table_entry_t bug = {
.fn = sctp_sf_bug,
.name = "sctp_sf_bug"
......@@ -419,7 +430,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
*
* For base protocol (RFC 2960).
*/
const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
static const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_DATA,
TYPE_SCTP_INIT,
TYPE_SCTP_INIT_ACK,
......@@ -482,7 +493,7 @@ const sctp_sm_table_entry_t chunk_event_table[SCTP_NUM_BASE_CHUNK_TYPES][SCTP_ST
/* The primary index for this table is the chunk type.
* The secondary index for this table is the state.
*/
const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_ASCONF,
TYPE_SCTP_ASCONF_ACK,
}; /*state_fn_t addip_chunk_event_table[][] */
......@@ -511,7 +522,7 @@ const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_TYPES][
/* The primary index for this table is the chunk type.
* The secondary index for this table is the state.
*/
const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
static const sctp_sm_table_entry_t prsctp_chunk_event_table[SCTP_NUM_PRSCTP_CHUNK_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_FWD_TSN,
}; /*state_fn_t prsctp_chunk_event_table[][] */
......@@ -684,7 +695,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* The primary index for this table is the primitive type.
* The secondary index for this table is the state.
*/
const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
static const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_PRIMITIVE_ASSOCIATE,
TYPE_SCTP_PRIMITIVE_SHUTDOWN,
TYPE_SCTP_PRIMITIVE_ABORT,
......@@ -716,8 +727,31 @@ const sctp_sm_table_entry_t primitive_event_table[SCTP_NUM_PRIMITIVE_TYPES][SCTP
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
}
const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
#define TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH { \
/* SCTP_STATE_EMPTY */ \
{.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \
/* SCTP_STATE_CLOSED */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_COOKIE_WAIT */ \
{.fn = sctp_sf_cookie_wait_icmp_abort, \
.name = "sctp_sf_cookie_wait_icmp_abort"}, \
/* SCTP_STATE_COOKIE_ECHOED */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_ESTABLISHED */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_PENDING */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_SENT */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_RECEIVED */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
/* SCTP_STATE_SHUTDOWN_ACK_SENT */ \
{.fn = sctp_sf_ignore_other, .name = "sctp_sf_ignore_other"}, \
}
static const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_OTHER_NO_PENDING_TSN,
TYPE_SCTP_OTHER_ICMP_PROTO_UNREACH,
};
#define TYPE_SCTP_EVENT_TIMEOUT_NONE { \
......@@ -931,7 +965,7 @@ const sctp_sm_table_entry_t other_event_table[SCTP_NUM_OTHER_TYPES][SCTP_STATE_N
{.fn = sctp_sf_timer_ignore, .name = "sctp_sf_timer_ignore"}, \
}
const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
static const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STATE_NUM_STATES] = {
TYPE_SCTP_EVENT_TIMEOUT_NONE,
TYPE_SCTP_EVENT_TIMEOUT_T1_COOKIE,
TYPE_SCTP_EVENT_TIMEOUT_T1_INIT,
......@@ -944,8 +978,8 @@ const sctp_sm_table_entry_t timeout_event_table[SCTP_NUM_TIMEOUT_TYPES][SCTP_STA
TYPE_SCTP_EVENT_TIMEOUT_AUTOCLOSE,
};
const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
sctp_state_t state)
static const sctp_sm_table_entry_t *sctp_chunk_event_lookup(sctp_cid_t cid,
sctp_state_t state)
{
if (state > SCTP_STATE_MAX)
return &bug;
......
......@@ -208,7 +208,7 @@ struct sctp_association *sctp_id2assoc(struct sock *sk, sctp_assoc_t id)
* id are specified, the associations matching the address and the id should be
* the same.
*/
struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
static struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
struct sockaddr_storage *addr,
sctp_assoc_t id)
{
......@@ -245,7 +245,7 @@ struct sctp_transport *sctp_addr_id2transport(struct sock *sk,
* sockaddr_in6 [RFC 2553]),
* addr_len - the size of the address structure.
*/
int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
SCTP_STATIC int sctp_bind(struct sock *sk, struct sockaddr *uaddr, int addr_len)
{
int retval = 0;
......@@ -343,8 +343,8 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
}
/* Refresh ephemeral port. */
if (!snum)
snum = inet_sk(sk)->num;
if (!bp->port)
bp->port = inet_sk(sk)->num;
/* Add the address to the bind address list. */
sctp_local_bh_disable();
......@@ -354,8 +354,6 @@ SCTP_STATIC int sctp_do_bind(struct sock *sk, union sctp_addr *addr, int len)
addr->v4.sin_port = ntohs(addr->v4.sin_port);
ret = sctp_add_bind_addr(bp, addr, GFP_ATOMIC);
addr->v4.sin_port = htons(addr->v4.sin_port);
if (!ret && !bp->port)
bp->port = snum;
sctp_write_unlock(&ep->base.addr_lock);
sctp_local_bh_enable();
......@@ -1713,10 +1711,13 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
/* update default value for endpoint (all future associations) */
if (!params.spp_assoc_id &&
sctp_is_any(( union sctp_addr *)&params.spp_address)) {
if (params.spp_hbinterval)
/* Manual heartbeat on an endpoint is invalid. */
if (0xffffffff == params.spp_hbinterval)
return -EINVAL;
else if (params.spp_hbinterval)
sctp_sk(sk)->paddrparam.spp_hbinterval =
params.spp_hbinterval;
if (sctp_max_retrans_path)
if (params.spp_pathmaxrxt)
sctp_sk(sk)->paddrparam.spp_pathmaxrxt =
params.spp_pathmaxrxt;
return 0;
......@@ -1758,7 +1759,8 @@ static int sctp_setsockopt_peer_addr_params(struct sock *sk,
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
trans->error_threshold = params.spp_pathmaxrxt;
if (params.spp_pathmaxrxt)
trans->max_retrans = params.spp_pathmaxrxt;
return 0;
}
......@@ -2937,7 +2939,7 @@ static int sctp_getsockopt_peer_addr_params(struct sock *sk, int len,
/* spp_pathmaxrxt contains the maximum number of retransmissions
* before this address shall be considered unreachable.
*/
params.spp_pathmaxrxt = trans->error_threshold;
params.spp_pathmaxrxt = trans->max_retrans;
done:
if (copy_to_user(optval, &params, len))
......@@ -3049,6 +3051,9 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
struct list_head *pos;
struct sctp_sockaddr_entry *addr;
rwlock_t *addr_lock;
unsigned long flags;
int cnt = 0;
if (len != sizeof(sctp_assoc_t))
......@@ -3065,33 +3070,104 @@ static int sctp_getsockopt_local_addrs_num(struct sock *sk, int len,
*/
if (0 == id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
} else {
asoc = sctp_id2assoc(sk, id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;
}
sctp_read_lock(addr_lock);
/* If the endpoint is bound to 0.0.0.0 or ::0, count the valid
* addresses from the global local address list.
*/
if (sctp_list_single_entry(&bp->address_list)) {
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
list_for_each(pos, &sctp_local_addr_list) {
addr = list_entry(pos,
struct sctp_sockaddr_entry,
list);
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
continue;
cnt++;
}
sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
flags);
} else {
cnt = 1;
}
goto done;
}
list_for_each(pos, &bp->address_list) {
cnt ++;
}
done:
sctp_read_unlock(addr_lock);
return cnt;
}
/* Helper function that copies local addresses to user and returns the number
* of addresses copied.
*/
static int sctp_copy_laddrs_to_user(struct sock *sk, __u16 port, int max_addrs,
void __user *to)
{
struct list_head *pos;
struct sctp_sockaddr_entry *addr;
unsigned long flags;
union sctp_addr temp;
int cnt = 0;
int addrlen;
sctp_spin_lock_irqsave(&sctp_local_addr_lock, flags);
list_for_each(pos, &sctp_local_addr_list) {
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
if ((PF_INET == sk->sk_family) &&
(AF_INET6 == addr->a.sa.sa_family))
continue;
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sctp_sk(sk),
&temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
temp.v4.sin_port = htons(port);
if (copy_to_user(to, &temp, addrlen)) {
sctp_spin_unlock_irqrestore(&sctp_local_addr_lock,
flags);
return -EFAULT;
}
to += addrlen;
cnt ++;
if (cnt >= max_addrs) break;
}
sctp_spin_unlock_irqrestore(&sctp_local_addr_lock, flags);
return cnt;
}
static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
char __user *optval, int __user *optlen)
char __user *optval, int __user *optlen)
{
struct sctp_bind_addr *bp;
struct sctp_association *asoc;
struct list_head *pos;
int cnt = 0;
struct sctp_getaddrs getaddrs;
struct sctp_sockaddr_entry *from;
struct sctp_sockaddr_entry *addr;
void __user *to;
union sctp_addr temp;
struct sctp_opt *sp = sctp_sk(sk);
int addrlen;
rwlock_t *addr_lock;
int err = 0;
if (len != sizeof(struct sctp_getaddrs))
return -EINVAL;
......@@ -3108,33 +3184,59 @@ static int sctp_getsockopt_local_addrs(struct sock *sk, int len,
*/
if (0 == getaddrs.assoc_id) {
bp = &sctp_sk(sk)->ep->base.bind_addr;
addr_lock = &sctp_sk(sk)->ep->base.addr_lock;
} else {
asoc = sctp_id2assoc(sk, getaddrs.assoc_id);
if (!asoc)
return -EINVAL;
bp = &asoc->base.bind_addr;
addr_lock = &asoc->base.addr_lock;
}
to = getaddrs.addrs;
sctp_read_lock(addr_lock);
/* If the endpoint is bound to 0.0.0.0 or ::0, get the valid
* addresses from the global local address list.
*/
if (sctp_list_single_entry(&bp->address_list)) {
addr = list_entry(bp->address_list.next,
struct sctp_sockaddr_entry, list);
if (sctp_is_any(&addr->a)) {
cnt = sctp_copy_laddrs_to_user(sk, bp->port,
getaddrs.addr_num, to);
if (cnt < 0) {
err = cnt;
goto unlock;
}
goto copy_getaddrs;
}
}
list_for_each(pos, &bp->address_list) {
from = list_entry(pos,
struct sctp_sockaddr_entry,
list);
memcpy(&temp, &from->a, sizeof(temp));
addr = list_entry(pos, struct sctp_sockaddr_entry, list);
memcpy(&temp, &addr->a, sizeof(temp));
sctp_get_pf_specific(sk->sk_family)->addr_v4map(sp, &temp);
addrlen = sctp_get_af_specific(temp.sa.sa_family)->sockaddr_len;
temp.v4.sin_port = htons(temp.v4.sin_port);
if (copy_to_user(to, &temp, addrlen))
return -EFAULT;
if (copy_to_user(to, &temp, addrlen)) {
err = -EFAULT;
goto unlock;
}
to += addrlen;
cnt ++;
if (cnt >= getaddrs.addr_num) break;
}
copy_getaddrs:
getaddrs.addr_num = cnt;
if (copy_to_user(optval, &getaddrs, sizeof(struct sctp_getaddrs)))
return -EFAULT;
err = -EFAULT;
return 0;
unlock:
sctp_read_unlock(addr_lock);
return err;
}
/* 7.1.10 Set Primary Address (SCTP_PRIMARY_ADDR)
......
......@@ -42,6 +42,9 @@
#define MAX_KMALLOC_SIZE 131072
static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
__u16 out);
/* Storage size needed for map includes 2 headers and then the
* specific needs of in or out streams.
*/
......@@ -87,8 +90,8 @@ struct sctp_ssnmap *sctp_ssnmap_new(__u16 in, __u16 out, int gfp)
/* Initialize a block of memory as a ssnmap. */
struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
__u16 out)
static struct sctp_ssnmap *sctp_ssnmap_init(struct sctp_ssnmap *map, __u16 in,
__u16 out)
{
memset(map, 0x00, sctp_ssnmap_size(in, out));
......
......@@ -54,34 +54,10 @@
/* 1st Level Abstractions. */
/* Allocate and initialize a new transport. */
struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
{
struct sctp_transport *transport;
transport = t_new(struct sctp_transport, gfp);
if (!transport)
goto fail;
if (!sctp_transport_init(transport, addr, gfp))
goto fail_init;
transport->malloced = 1;
SCTP_DBG_OBJCNT_INC(transport);
return transport;
fail_init:
kfree(transport);
fail:
return NULL;
}
/* Initialize a new transport from provided memory. */
struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr,
int gfp)
static struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
const union sctp_addr *addr,
int gfp)
{
/* Copy in the address. */
peer->ipaddr = *addr;
......@@ -112,7 +88,6 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
/* Initialize the default path max_retrans. */
peer->max_retrans = sctp_max_retrans_path;
peer->error_threshold = 0;
peer->error_count = 0;
INIT_LIST_HEAD(&peer->transmitted);
......@@ -144,6 +119,30 @@ struct sctp_transport *sctp_transport_init(struct sctp_transport *peer,
return peer;
}
/* Allocate and initialize a new transport. */
struct sctp_transport *sctp_transport_new(const union sctp_addr *addr, int gfp)
{
struct sctp_transport *transport;
transport = t_new(struct sctp_transport, gfp);
if (!transport)
goto fail;
if (!sctp_transport_init(transport, addr, gfp))
goto fail_init;
transport->malloced = 1;
SCTP_DBG_OBJCNT_INC(transport);
return transport;
fail_init:
kfree(transport);
fail:
return NULL;
}
/* This transport is no longer needed. Free up if possible, or
* delay until it last reference count.
*/
......@@ -155,13 +154,23 @@ void sctp_transport_free(struct sctp_transport *transport)
if (del_timer(&transport->hb_timer))
sctp_transport_put(transport);
/* Delete the T3_rtx timer if it's active.
* There is no point in not doing this now and letting
* structure hang around in memory since we know
* the tranport is going away.
*/
if (timer_pending(&transport->T3_rtx_timer) &&
del_timer(&transport->T3_rtx_timer))
sctp_transport_put(transport);
sctp_transport_put(transport);
}
/* Destroy the transport data structure.
* Assumes there are no more users of this structure.
*/
void sctp_transport_destroy(struct sctp_transport *transport)
static void sctp_transport_destroy(struct sctp_transport *transport)
{
SCTP_ASSERT(transport->dead, "Transport is not dead", return);
......
......@@ -52,29 +52,6 @@ static void sctp_tsnmap_find_gap_ack(__u8 *map, __u16 off,
int *started, __u16 *start,
int *ended, __u16 *end);
/* Create a new sctp_tsnmap.
* Allocate room to store at least 'len' contiguous TSNs.
*/
struct sctp_tsnmap *sctp_tsnmap_new(__u16 len, __u32 initial_tsn, int gfp)
{
struct sctp_tsnmap *retval;
retval = kmalloc(sizeof(struct sctp_tsnmap) +
sctp_tsnmap_storage_size(len), gfp);
if (!retval)
goto fail;
if (!sctp_tsnmap_init(retval, len, initial_tsn))
goto fail_map;
retval->malloced = 1;
return retval;
fail_map:
kfree(retval);
fail:
return NULL;
}
/* Initialize a block of memory as a tsnmap. */
struct sctp_tsnmap *sctp_tsnmap_init(struct sctp_tsnmap *map, __u16 len,
__u32 initial_tsn)
......@@ -168,16 +145,9 @@ void sctp_tsnmap_mark(struct sctp_tsnmap *map, __u32 tsn)
}
/* Dispose of a tsnmap. */
void sctp_tsnmap_free(struct sctp_tsnmap *map)
{
if (map->malloced)
kfree(map);
}
/* Initialize a Gap Ack Block iterator from memory being provided. */
void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter)
SCTP_STATIC void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter)
{
/* Only start looking one past the Cumulative TSN Ack Point. */
iter->start = map->cumulative_tsn_ack_point + 1;
......@@ -186,8 +156,9 @@ void sctp_tsnmap_iter_init(const struct sctp_tsnmap *map,
/* Get the next Gap Ack Blocks. Returns 0 if there was not another block
* to get.
*/
int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter, __u16 *start, __u16 *end)
SCTP_STATIC int sctp_tsnmap_next_gap_ack(const struct sctp_tsnmap *map,
struct sctp_tsnmap_iter *iter,
__u16 *start, __u16 *end)
{
int started, ended;
__u16 _start, _end, offset;
......
......@@ -65,8 +65,16 @@ static void sctp_stub_rfree(struct sk_buff *skb)
*/
}
/* Initialize an ULP event from an given skb. */
SCTP_STATIC void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
{
memset(event, 0, sizeof(struct sctp_ulpevent));
event->msg_flags = msg_flags;
}
/* Create a new sctp_ulpevent. */
struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
SCTP_STATIC struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags,
int gfp)
{
struct sctp_ulpevent *event;
struct sk_buff *skb;
......@@ -84,13 +92,6 @@ struct sctp_ulpevent *sctp_ulpevent_new(int size, int msg_flags, int gfp)
return NULL;
}
/* Initialize an ULP event from an given skb. */
void sctp_ulpevent_init(struct sctp_ulpevent *event, int msg_flags)
{
memset(event, 0, sizeof(struct sctp_ulpevent));
event->msg_flags = msg_flags;
}
/* Is this a MSG_NOTIFICATION? */
int sctp_ulpevent_is_notification(const struct sctp_ulpevent *event)
{
......
......@@ -56,25 +56,6 @@ static struct sctp_ulpevent * sctp_ulpq_order(struct sctp_ulpq *,
/* 1st Level Abstractions */
/* Create a new ULP queue. */
struct sctp_ulpq *sctp_ulpq_new(struct sctp_association *asoc, int gfp)
{
struct sctp_ulpq *ulpq;
ulpq = kmalloc(sizeof(struct sctp_ulpq), gfp);
if (!ulpq)
goto fail;
if (!sctp_ulpq_init(ulpq, asoc))
goto fail_init;
ulpq->malloced = 1;
return ulpq;
fail_init:
kfree(ulpq);
fail:
return NULL;
}
/* Initialize a ULP queue from a block of memory. */
struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
struct sctp_association *asoc)
......@@ -92,7 +73,7 @@ struct sctp_ulpq *sctp_ulpq_init(struct sctp_ulpq *ulpq,
/* Flush the reassembly and ordering queues. */
void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
static void sctp_ulpq_flush(struct sctp_ulpq *ulpq)
{
struct sk_buff *skb;
struct sctp_ulpevent *event;
......
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