Commit d85f5793 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* 'master' of master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [PPP_MPPE]: Don't put InterimKey on the stack
  SCTP : Add paramters validity check for ASCONF chunk
  SCTP: Discard OOTB packetes with bundled INIT early.
  SCTP: Clean up OOTB handling and fix infinite loop processing
  SCTP: Explicitely discard OOTB chunks
  SCTP: Send ABORT chunk with correct tag in response to INIT ACK
  SCTP: Validate buffer room when processing sequential chunks
  [PATCH] mac80211: fix initialisation when built-in
  [PATCH] net/mac80211/wme.c: fix sparse warning
  [PATCH] cfg80211: fix initialisation if built-in
  [PATCH] net/wireless/sysfs.c: Shut up build warning
parents acbbe6c2 45dfd5b5
...@@ -136,7 +136,7 @@ struct ppp_mppe_state { ...@@ -136,7 +136,7 @@ struct ppp_mppe_state {
* Key Derivation, from RFC 3078, RFC 3079. * Key Derivation, from RFC 3078, RFC 3079.
* Equivalent to Get_Key() for MS-CHAP as described in RFC 3079. * Equivalent to Get_Key() for MS-CHAP as described in RFC 3079.
*/ */
static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *InterimKey) static void get_new_key_from_sha(struct ppp_mppe_state * state)
{ {
struct hash_desc desc; struct hash_desc desc;
struct scatterlist sg[4]; struct scatterlist sg[4];
...@@ -153,8 +153,6 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I ...@@ -153,8 +153,6 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I
desc.flags = 0; desc.flags = 0;
crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest); crypto_hash_digest(&desc, sg, nbytes, state->sha1_digest);
memcpy(InterimKey, state->sha1_digest, state->keylen);
} }
/* /*
...@@ -163,21 +161,21 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I ...@@ -163,21 +161,21 @@ static void get_new_key_from_sha(struct ppp_mppe_state * state, unsigned char *I
*/ */
static void mppe_rekey(struct ppp_mppe_state * state, int initial_key) static void mppe_rekey(struct ppp_mppe_state * state, int initial_key)
{ {
unsigned char InterimKey[MPPE_MAX_KEY_LEN];
struct scatterlist sg_in[1], sg_out[1]; struct scatterlist sg_in[1], sg_out[1];
struct blkcipher_desc desc = { .tfm = state->arc4 }; struct blkcipher_desc desc = { .tfm = state->arc4 };
get_new_key_from_sha(state, InterimKey); get_new_key_from_sha(state);
if (!initial_key) { if (!initial_key) {
crypto_blkcipher_setkey(state->arc4, InterimKey, state->keylen); crypto_blkcipher_setkey(state->arc4, state->sha1_digest,
setup_sg(sg_in, InterimKey, state->keylen); state->keylen);
setup_sg(sg_in, state->sha1_digest, state->keylen);
setup_sg(sg_out, state->session_key, state->keylen); setup_sg(sg_out, state->session_key, state->keylen);
if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in, if (crypto_blkcipher_encrypt(&desc, sg_out, sg_in,
state->keylen) != 0) { state->keylen) != 0) {
printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n"); printk(KERN_WARNING "mppe_rekey: cipher_encrypt failed\n");
} }
} else { } else {
memcpy(state->session_key, InterimKey, state->keylen); memcpy(state->session_key, state->sha1_digest, state->keylen);
} }
if (state->keylen == 8) { if (state->keylen == 8) {
/* See RFC 3078 */ /* See RFC 3078 */
......
...@@ -114,7 +114,6 @@ sctp_state_fn_t sctp_sf_do_4_C; ...@@ -114,7 +114,6 @@ sctp_state_fn_t sctp_sf_do_4_C;
sctp_state_fn_t sctp_sf_eat_data_6_2; sctp_state_fn_t sctp_sf_eat_data_6_2;
sctp_state_fn_t sctp_sf_eat_data_fast_4_4; sctp_state_fn_t sctp_sf_eat_data_fast_4_4;
sctp_state_fn_t sctp_sf_eat_sack_6_2; sctp_state_fn_t sctp_sf_eat_sack_6_2;
sctp_state_fn_t sctp_sf_tabort_8_4_8;
sctp_state_fn_t sctp_sf_operr_notify; sctp_state_fn_t sctp_sf_operr_notify;
sctp_state_fn_t sctp_sf_t1_init_timer_expire; sctp_state_fn_t sctp_sf_t1_init_timer_expire;
sctp_state_fn_t sctp_sf_t1_cookie_timer_expire; sctp_state_fn_t sctp_sf_t1_cookie_timer_expire;
...@@ -247,6 +246,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *, ...@@ -247,6 +246,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
int, __be16); int, __be16);
struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
union sctp_addr *addr); union sctp_addr *addr);
int sctp_verify_asconf(const struct sctp_association *asoc,
struct sctp_paramhdr *param_hdr, void *chunk_end,
struct sctp_paramhdr **errp);
struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
struct sctp_chunk *asconf); struct sctp_chunk *asconf);
int sctp_process_asconf_ack(struct sctp_association *asoc, int sctp_process_asconf_ack(struct sctp_association *asoc,
......
...@@ -421,6 +421,7 @@ struct sctp_signed_cookie { ...@@ -421,6 +421,7 @@ struct sctp_signed_cookie {
* internally. * internally.
*/ */
union sctp_addr_param { union sctp_addr_param {
struct sctp_paramhdr p;
struct sctp_ipv4addr_param v4; struct sctp_ipv4addr_param v4;
struct sctp_ipv6addr_param v6; struct sctp_ipv6addr_param v6;
}; };
......
...@@ -5259,7 +5259,7 @@ static void __exit ieee80211_exit(void) ...@@ -5259,7 +5259,7 @@ static void __exit ieee80211_exit(void)
} }
module_init(ieee80211_init); subsys_initcall(ieee80211_init);
module_exit(ieee80211_exit); module_exit(ieee80211_exit);
MODULE_DESCRIPTION("IEEE 802.11 subsystem"); MODULE_DESCRIPTION("IEEE 802.11 subsystem");
......
...@@ -431,7 +431,7 @@ static void __exit rate_control_simple_exit(void) ...@@ -431,7 +431,7 @@ static void __exit rate_control_simple_exit(void)
} }
module_init(rate_control_simple_init); subsys_initcall(rate_control_simple_init);
module_exit(rate_control_simple_exit); module_exit(rate_control_simple_exit);
MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211"); MODULE_DESCRIPTION("Simple rate control algorithm for ieee80211");
......
...@@ -424,7 +424,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt) ...@@ -424,7 +424,7 @@ static int wme_qdiscop_init(struct Qdisc *qd, struct rtattr *opt)
skb_queue_head_init(&q->requeued[i]); skb_queue_head_init(&q->requeued[i]);
q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops, q->queues[i] = qdisc_create_dflt(qd->dev, &pfifo_qdisc_ops,
qd->handle); qd->handle);
if (q->queues[i] == 0) { if (!q->queues[i]) {
q->queues[i] = &noop_qdisc; q->queues[i] = &noop_qdisc;
printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i); printk(KERN_ERR "%s child qdisc %i creation failed", dev->name, i);
} }
......
...@@ -622,6 +622,14 @@ static int sctp_rcv_ootb(struct sk_buff *skb) ...@@ -622,6 +622,14 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type) if (SCTP_CID_SHUTDOWN_COMPLETE == ch->type)
goto discard; goto discard;
/* RFC 4460, 2.11.2
* This will discard packets with INIT chunk bundled as
* subsequent chunks in the packet. When INIT is first,
* the normal INIT processing will discard the chunk.
*/
if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data)
goto discard;
/* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR /* RFC 8.4, 7) If the packet contains a "Stale cookie" ERROR
* or a COOKIE ACK the SCTP Packet should be silently * or a COOKIE ACK the SCTP Packet should be silently
* discarded. * discarded.
......
...@@ -130,6 +130,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) ...@@ -130,6 +130,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
/* Force chunk->skb->data to chunk->chunk_end. */ /* Force chunk->skb->data to chunk->chunk_end. */
skb_pull(chunk->skb, skb_pull(chunk->skb,
chunk->chunk_end - chunk->skb->data); chunk->chunk_end - chunk->skb->data);
/* Verify that we have at least chunk headers
* worth of buffer left.
*/
if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) {
sctp_chunk_free(chunk);
chunk = queue->in_progress = NULL;
}
} }
} }
......
...@@ -2499,6 +2499,52 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc, ...@@ -2499,6 +2499,52 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
return SCTP_ERROR_NO_ERROR; return SCTP_ERROR_NO_ERROR;
} }
/* Verify the ASCONF packet before we process it. */
int sctp_verify_asconf(const struct sctp_association *asoc,
struct sctp_paramhdr *param_hdr, void *chunk_end,
struct sctp_paramhdr **errp) {
sctp_addip_param_t *asconf_param;
union sctp_params param;
int length, plen;
param.v = (sctp_paramhdr_t *) param_hdr;
while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) {
length = ntohs(param.p->length);
*errp = param.p;
if (param.v > chunk_end - length ||
length < sizeof(sctp_paramhdr_t))
return 0;
switch (param.p->type) {
case SCTP_PARAM_ADD_IP:
case SCTP_PARAM_DEL_IP:
case SCTP_PARAM_SET_PRIMARY:
asconf_param = (sctp_addip_param_t *)param.v;
plen = ntohs(asconf_param->param_hdr.length);
if (plen < sizeof(sctp_addip_param_t) +
sizeof(sctp_paramhdr_t))
return 0;
break;
case SCTP_PARAM_SUCCESS_REPORT:
case SCTP_PARAM_ADAPTATION_LAYER_IND:
if (length != sizeof(sctp_addip_param_t))
return 0;
break;
default:
break;
}
param.v += WORD_ROUND(length);
}
if (param.v != chunk_end)
return 0;
return 1;
}
/* Process an incoming ASCONF chunk with the next expected serial no. and /* Process an incoming ASCONF chunk with the next expected serial no. and
* return an ASCONF_ACK chunk to be sent in response. * return an ASCONF_ACK chunk to be sent in response.
*/ */
......
...@@ -90,6 +90,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, ...@@ -90,6 +90,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
sctp_cmd_seq_t *commands); sctp_cmd_seq_t *commands);
static sctp_disposition_t sctp_sf_tabort_8_4_8(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); static struct sctp_sackhdr *sctp_sm_pull_sack(struct sctp_chunk *chunk);
static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
...@@ -98,6 +103,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands, ...@@ -98,6 +103,7 @@ static sctp_disposition_t sctp_stop_t1_and_abort(sctp_cmd_seq_t *commands,
struct sctp_transport *transport); struct sctp_transport *transport);
static sctp_disposition_t sctp_sf_abort_violation( static sctp_disposition_t sctp_sf_abort_violation(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
void *arg, void *arg,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
...@@ -111,6 +117,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen( ...@@ -111,6 +117,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
void *arg, void *arg,
sctp_cmd_seq_t *commands); sctp_cmd_seq_t *commands);
static sctp_disposition_t sctp_sf_violation_paramlen(
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_violation_ctsn( static sctp_disposition_t sctp_sf_violation_ctsn(
const struct sctp_endpoint *ep, const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
...@@ -118,6 +131,13 @@ static sctp_disposition_t sctp_sf_violation_ctsn( ...@@ -118,6 +131,13 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
void *arg, void *arg,
sctp_cmd_seq_t *commands); sctp_cmd_seq_t *commands);
static sctp_disposition_t sctp_sf_violation_chunk(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands);
/* Small helper function that checks if the chunk length /* Small helper function that checks if the chunk length
* is of the appropriate length. The 'required_length' argument * is of the appropriate length. The 'required_length' argument
* is set to be the size of a specific chunk we are testing. * is set to be the size of a specific chunk we are testing.
...@@ -181,16 +201,21 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep, ...@@ -181,16 +201,21 @@ sctp_disposition_t sctp_sf_do_4_C(const struct sctp_endpoint *ep,
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
struct sctp_ulpevent *ev; struct sctp_ulpevent *ev;
if (!sctp_vtag_verify_either(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* RFC 2960 6.10 Bundling /* RFC 2960 6.10 Bundling
* *
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
*/ */
if (!chunk->singleton) if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION; return sctp_sf_violation_chunk(ep, asoc, type, arg, commands);
if (!sctp_vtag_verify_either(chunk, asoc)) /* Make sure that the SHUTDOWN_COMPLETE chunk has a valid length. */
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
/* RFC 2960 10.2 SCTP-to-ULP /* RFC 2960 10.2 SCTP-to-ULP
* *
...@@ -450,17 +475,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep, ...@@ -450,17 +475,17 @@ sctp_disposition_t sctp_sf_do_5_1C_ack(const struct sctp_endpoint *ep,
if (!sctp_vtag_verify(chunk, asoc)) if (!sctp_vtag_verify(chunk, asoc))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); 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 /* 6.10 Bundling
* An endpoint MUST NOT bundle INIT, INIT ACK or * An endpoint MUST NOT bundle INIT, INIT ACK or
* SHUTDOWN COMPLETE with any other chunks. * SHUTDOWN COMPLETE with any other chunks.
*/ */
if (!chunk->singleton) if (!chunk->singleton)
return SCTP_DISPOSITION_VIOLATION; return sctp_sf_violation_chunk(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);
/* Grab the INIT header. */ /* Grab the INIT header. */
chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data; chunk->subh.init_hdr = (sctp_inithdr_t *) chunk->skb->data;
...@@ -585,7 +610,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep, ...@@ -585,7 +610,7 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(const struct sctp_endpoint *ep,
* control endpoint, respond with an ABORT. * control endpoint, respond with an ABORT.
*/ */
if (ep == sctp_sk((sctp_get_ctl_sock()))->ep) if (ep == sctp_sk((sctp_get_ctl_sock()))->ep)
return sctp_sf_ootb(ep, asoc, type, arg, commands); return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
/* Make sure that the COOKIE_ECHO chunk has a valid length. /* Make sure that the COOKIE_ECHO chunk has a valid length.
* In this case, we check that we have enough for at least a * In this case, we check that we have enough for at least a
...@@ -2496,6 +2521,11 @@ sctp_disposition_t sctp_sf_do_9_2_reshutack(const struct sctp_endpoint *ep, ...@@ -2496,6 +2521,11 @@ 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 *chunk = (struct sctp_chunk *) arg;
struct sctp_chunk *reply; struct sctp_chunk *reply;
/* Make sure that the 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);
/* Since we are not going to really process this INIT, there /* Since we are not going to really process this INIT, there
* is no point in verifying chunk boundries. Just generate * is no point in verifying chunk boundries. Just generate
* the SHUTDOWN ACK. * the SHUTDOWN ACK.
...@@ -2929,7 +2959,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep, ...@@ -2929,7 +2959,7 @@ sctp_disposition_t sctp_sf_eat_sack_6_2(const struct sctp_endpoint *ep,
* *
* The return value is the disposition of the chunk. * The return value is the disposition of the chunk.
*/ */
sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, static sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
const sctp_subtype_t type, const sctp_subtype_t type,
void *arg, void *arg,
...@@ -2965,6 +2995,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep, ...@@ -2965,6 +2995,7 @@ sctp_disposition_t sctp_sf_tabort_8_4_8(const struct sctp_endpoint *ep,
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME; return SCTP_DISPOSITION_CONSUME;
} }
...@@ -3125,14 +3156,14 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, ...@@ -3125,14 +3156,14 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
ch = (sctp_chunkhdr_t *) chunk->chunk_hdr; ch = (sctp_chunkhdr_t *) chunk->chunk_hdr;
do { do {
/* Break out if chunk length is less then minimal. */ /* Report violation if the chunk is less then minimal */
if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t)) if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
break; return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (ch_end > skb_tail_pointer(skb))
break;
/* Now that we know we at least have a chunk header,
* do things that are type appropriate.
*/
if (SCTP_CID_SHUTDOWN_ACK == ch->type) if (SCTP_CID_SHUTDOWN_ACK == ch->type)
ootb_shut_ack = 1; ootb_shut_ack = 1;
...@@ -3144,15 +3175,19 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep, ...@@ -3144,15 +3175,19 @@ sctp_disposition_t sctp_sf_ootb(const struct sctp_endpoint *ep,
if (SCTP_CID_ABORT == ch->type) if (SCTP_CID_ABORT == ch->type)
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
/* Report violation if chunk len overflows */
ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
if (ch_end > skb_tail_pointer(skb))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
ch = (sctp_chunkhdr_t *) ch_end; ch = (sctp_chunkhdr_t *) ch_end;
} while (ch_end < skb_tail_pointer(skb)); } while (ch_end < skb_tail_pointer(skb));
if (ootb_shut_ack) if (ootb_shut_ack)
sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands); return sctp_sf_shut_8_4_5(ep, asoc, type, arg, commands);
else else
sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands); return sctp_sf_tabort_8_4_8(ep, asoc, type, arg, commands);
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
} }
/* /*
...@@ -3218,7 +3253,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep, ...@@ -3218,7 +3253,11 @@ static sctp_disposition_t sctp_sf_shut_8_4_5(const struct sctp_endpoint *ep,
if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t))) if (!sctp_chunk_length_valid(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_pdiscard(ep, asoc, type, arg, commands); return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
return SCTP_DISPOSITION_CONSUME; /* We need to discard the rest of the packet to prevent
* potential bomming attacks from additional bundled chunks.
* This is documented in SCTP Threats ID.
*/
return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
} }
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
...@@ -3241,6 +3280,13 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep, ...@@ -3241,6 +3280,13 @@ sctp_disposition_t sctp_sf_do_8_5_1_E_sa(const struct sctp_endpoint *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg;
/* 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);
/* Although we do have an association in this case, it corresponds /* Although we do have an association in this case, it corresponds
* to a restarted association. So the packet is treated as an OOTB * to a restarted association. So the packet is treated as an OOTB
* packet and the state function that handles OOTB SHUTDOWN_ACK is * packet and the state function that handles OOTB SHUTDOWN_ACK is
...@@ -3257,8 +3303,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, ...@@ -3257,8 +3303,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
{ {
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
struct sctp_chunk *asconf_ack = NULL; struct sctp_chunk *asconf_ack = NULL;
struct sctp_paramhdr *err_param = NULL;
sctp_addiphdr_t *hdr; sctp_addiphdr_t *hdr;
union sctp_addr_param *addr_param;
__u32 serial; __u32 serial;
int length;
if (!sctp_vtag_verify(chunk, asoc)) { if (!sctp_vtag_verify(chunk, asoc)) {
sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
...@@ -3274,6 +3323,20 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, ...@@ -3274,6 +3323,20 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
hdr = (sctp_addiphdr_t *)chunk->skb->data; hdr = (sctp_addiphdr_t *)chunk->skb->data;
serial = ntohl(hdr->serial); serial = ntohl(hdr->serial);
addr_param = (union sctp_addr_param *)hdr->params;
length = ntohs(addr_param->p.length);
if (length < sizeof(sctp_paramhdr_t))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)addr_param, commands);
/* Verify the ASCONF chunk before processing it. */
if (!sctp_verify_asconf(asoc,
(sctp_paramhdr_t *)((void *)addr_param + length),
(void *)chunk->chunk_end,
&err_param))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)&err_param, commands);
/* ADDIP 4.2 C1) Compare the value of the serial number to the value /* ADDIP 4.2 C1) Compare the value of the serial number to the value
* the endpoint stored in a new association variable * the endpoint stored in a new association variable
* 'Peer-Serial-Number'. * 'Peer-Serial-Number'.
...@@ -3328,6 +3391,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, ...@@ -3328,6 +3391,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
struct sctp_chunk *asconf_ack = arg; struct sctp_chunk *asconf_ack = arg;
struct sctp_chunk *last_asconf = asoc->addip_last_asconf; struct sctp_chunk *last_asconf = asoc->addip_last_asconf;
struct sctp_chunk *abort; struct sctp_chunk *abort;
struct sctp_paramhdr *err_param = NULL;
sctp_addiphdr_t *addip_hdr; sctp_addiphdr_t *addip_hdr;
__u32 sent_serial, rcvd_serial; __u32 sent_serial, rcvd_serial;
...@@ -3345,6 +3409,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, ...@@ -3345,6 +3409,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data; addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
rcvd_serial = ntohl(addip_hdr->serial); rcvd_serial = ntohl(addip_hdr->serial);
/* Verify the ASCONF-ACK chunk before processing it. */
if (!sctp_verify_asconf(asoc,
(sctp_paramhdr_t *)addip_hdr->params,
(void *)asconf_ack->chunk_end,
&err_param))
return sctp_sf_violation_paramlen(ep, asoc, type,
(void *)&err_param, commands);
if (last_asconf) { if (last_asconf) {
addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
sent_serial = ntohl(addip_hdr->serial); sent_serial = ntohl(addip_hdr->serial);
...@@ -3655,6 +3727,16 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep, ...@@ -3655,6 +3727,16 @@ sctp_disposition_t sctp_sf_discard_chunk(const struct sctp_endpoint *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg;
/* 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(chunk, sizeof(sctp_chunkhdr_t)))
return sctp_sf_violation_chunklen(ep, asoc, type, arg,
commands);
SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk); SCTP_DEBUG_PRINTK("Chunk %d is discarded\n", type.chunk);
return SCTP_DISPOSITION_DISCARD; return SCTP_DISPOSITION_DISCARD;
} }
...@@ -3710,6 +3792,13 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, ...@@ -3710,6 +3792,13 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
void *arg, void *arg,
sctp_cmd_seq_t *commands) sctp_cmd_seq_t *commands)
{ {
struct sctp_chunk *chunk = arg;
/* Make sure that the 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);
return SCTP_DISPOSITION_VIOLATION; return SCTP_DISPOSITION_VIOLATION;
} }
...@@ -3717,12 +3806,14 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep, ...@@ -3717,12 +3806,14 @@ sctp_disposition_t sctp_sf_violation(const struct sctp_endpoint *ep,
* Common function to handle a protocol violation. * Common function to handle a protocol violation.
*/ */
static sctp_disposition_t sctp_sf_abort_violation( static sctp_disposition_t sctp_sf_abort_violation(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc, const struct sctp_association *asoc,
void *arg, void *arg,
sctp_cmd_seq_t *commands, sctp_cmd_seq_t *commands,
const __u8 *payload, const __u8 *payload,
const size_t paylen) const size_t paylen)
{ {
struct sctp_packet *packet = NULL;
struct sctp_chunk *chunk = arg; struct sctp_chunk *chunk = arg;
struct sctp_chunk *abort = NULL; struct sctp_chunk *abort = NULL;
...@@ -3731,30 +3822,51 @@ static sctp_disposition_t sctp_sf_abort_violation( ...@@ -3731,30 +3822,51 @@ static sctp_disposition_t sctp_sf_abort_violation(
if (!abort) if (!abort)
goto nomem; goto nomem;
sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); if (asoc) {
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort));
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) { if (asoc->state <= SCTP_STATE_COOKIE_ECHOED) {
sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT)); SCTP_TO(SCTP_EVENT_TIMEOUT_T1_INIT));
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
SCTP_ERROR(ECONNREFUSED)); SCTP_ERROR(ECONNREFUSED));
sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED, sctp_add_cmd_sf(commands, SCTP_CMD_INIT_FAILED,
SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
} else {
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR,
SCTP_ERROR(ECONNABORTED));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED,
SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION));
SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
}
} else { } else {
sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, packet = sctp_ootb_pkt_new(asoc, chunk);
SCTP_ERROR(ECONNABORTED));
sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, if (!packet)
SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); goto nomem_pkt;
SCTP_DEC_STATS(SCTP_MIB_CURRESTAB);
if (sctp_test_T_bit(abort))
packet->vtag = ntohl(chunk->sctp_hdr->vtag);
abort->skb->sk = ep->base.sk;
sctp_packet_append_chunk(packet, abort);
sctp_add_cmd_sf(commands, SCTP_CMD_SEND_PKT,
SCTP_PACKET(packet));
SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS);
} }
sctp_add_cmd_sf(commands, SCTP_CMD_DISCARD_PACKET, SCTP_NULL()); sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands);
SCTP_INC_STATS(SCTP_MIB_ABORTEDS); SCTP_INC_STATS(SCTP_MIB_ABORTEDS);
return SCTP_DISPOSITION_ABORT; return SCTP_DISPOSITION_ABORT;
nomem_pkt:
sctp_chunk_free(abort);
nomem: nomem:
return SCTP_DISPOSITION_NOMEM; return SCTP_DISPOSITION_NOMEM;
} }
...@@ -3787,7 +3899,24 @@ static sctp_disposition_t sctp_sf_violation_chunklen( ...@@ -3787,7 +3899,24 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
{ {
char err_str[]="The following chunk had invalid length:"; char err_str[]="The following chunk had invalid length:";
return sctp_sf_abort_violation(asoc, arg, commands, err_str, return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
}
/*
* Handle a protocol violation when the parameter length is invalid.
* "Invalid" length is identified as smaller then the minimal length a
* given parameter can be.
*/
static sctp_disposition_t sctp_sf_violation_paramlen(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands) {
char err_str[] = "The following parameter had invalid length:";
return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str)); sizeof(err_str));
} }
...@@ -3806,10 +3935,31 @@ static sctp_disposition_t sctp_sf_violation_ctsn( ...@@ -3806,10 +3935,31 @@ static sctp_disposition_t sctp_sf_violation_ctsn(
{ {
char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:"; char err_str[]="The cumulative tsn ack beyond the max tsn currently sent:";
return sctp_sf_abort_violation(asoc, arg, commands, err_str, return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str)); sizeof(err_str));
} }
/* Handle protocol violation of an invalid chunk bundling. For example,
* when we have an association and we recieve bundled INIT-ACK, or
* SHUDOWN-COMPLETE, our peer is clearly violationg the "MUST NOT bundle"
* statement from the specs. Additinally, there might be an attacker
* on the path and we may not want to continue this communication.
*/
static sctp_disposition_t sctp_sf_violation_chunk(
const struct sctp_endpoint *ep,
const struct sctp_association *asoc,
const sctp_subtype_t type,
void *arg,
sctp_cmd_seq_t *commands)
{
char err_str[]="The following chunk violates protocol:";
if (!asoc)
return sctp_sf_violation(ep, asoc, type, arg, commands);
return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
sizeof(err_str));
}
/*************************************************************************** /***************************************************************************
* These are the state functions for handling primitive (Section 10) events. * These are the state functions for handling primitive (Section 10) events.
***************************************************************************/ ***************************************************************************/
...@@ -5176,7 +5326,22 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc ...@@ -5176,7 +5326,22 @@ static struct sctp_packet *sctp_ootb_pkt_new(const struct sctp_association *asoc
* association exists, otherwise, use the peer's vtag. * association exists, otherwise, use the peer's vtag.
*/ */
if (asoc) { if (asoc) {
vtag = asoc->peer.i.init_tag; /* Special case the INIT-ACK as there is no peer's vtag
* yet.
*/
switch(chunk->chunk_hdr->type) {
case SCTP_CID_INIT_ACK:
{
sctp_initack_chunk_t *initack;
initack = (sctp_initack_chunk_t *)chunk->chunk_hdr;
vtag = ntohl(initack->init_hdr.init_tag);
break;
}
default:
vtag = asoc->peer.i.init_tag;
break;
}
} else { } else {
/* Special case the INIT and stale COOKIE_ECHO as there is no /* Special case the INIT and stale COOKIE_ECHO as there is no
* vtag yet. * vtag yet.
......
...@@ -110,7 +110,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -110,7 +110,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -173,7 +173,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -173,7 +173,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -194,7 +194,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -194,7 +194,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -216,7 +216,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -216,7 +216,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_violation), \ TYPE_SCTP_FUNC(sctp_sf_violation), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -258,7 +258,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -258,7 +258,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -300,7 +300,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type, ...@@ -300,7 +300,7 @@ const sctp_sm_table_entry_t *sctp_sm_lookup_event(sctp_event_t event_type,
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -499,7 +499,7 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_ ...@@ -499,7 +499,7 @@ static const sctp_sm_table_entry_t addip_chunk_event_table[SCTP_NUM_ADDIP_CHUNK_
/* SCTP_STATE_EMPTY */ \ /* SCTP_STATE_EMPTY */ \
TYPE_SCTP_FUNC(sctp_sf_ootb), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_CLOSED */ \ /* SCTP_STATE_CLOSED */ \
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), \ TYPE_SCTP_FUNC(sctp_sf_ootb), \
/* SCTP_STATE_COOKIE_WAIT */ \ /* SCTP_STATE_COOKIE_WAIT */ \
TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \ TYPE_SCTP_FUNC(sctp_sf_discard_chunk), \
/* SCTP_STATE_COOKIE_ECHOED */ \ /* SCTP_STATE_COOKIE_ECHOED */ \
...@@ -528,7 +528,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = { ...@@ -528,7 +528,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM_STATES] = {
/* SCTP_STATE_EMPTY */ /* SCTP_STATE_EMPTY */
TYPE_SCTP_FUNC(sctp_sf_ootb), TYPE_SCTP_FUNC(sctp_sf_ootb),
/* SCTP_STATE_CLOSED */ /* SCTP_STATE_CLOSED */
TYPE_SCTP_FUNC(sctp_sf_tabort_8_4_8), TYPE_SCTP_FUNC(sctp_sf_ootb),
/* SCTP_STATE_COOKIE_WAIT */ /* SCTP_STATE_COOKIE_WAIT */
TYPE_SCTP_FUNC(sctp_sf_unk_chunk), TYPE_SCTP_FUNC(sctp_sf_unk_chunk),
/* SCTP_STATE_COOKIE_ECHOED */ /* SCTP_STATE_COOKIE_ECHOED */
......
...@@ -213,7 +213,7 @@ out_fail_notifier: ...@@ -213,7 +213,7 @@ out_fail_notifier:
out_fail_sysfs: out_fail_sysfs:
return err; return err;
} }
module_init(cfg80211_init); subsys_initcall(cfg80211_init);
static void cfg80211_exit(void) static void cfg80211_exit(void)
{ {
......
...@@ -52,12 +52,14 @@ static void wiphy_dev_release(struct device *dev) ...@@ -52,12 +52,14 @@ static void wiphy_dev_release(struct device *dev)
cfg80211_dev_free(rdev); cfg80211_dev_free(rdev);
} }
#ifdef CONFIG_HOTPLUG
static int wiphy_uevent(struct device *dev, char **envp, static int wiphy_uevent(struct device *dev, char **envp,
int num_envp, char *buf, int size) int num_envp, char *buf, int size)
{ {
/* TODO, we probably need stuff here */ /* TODO, we probably need stuff here */
return 0; return 0;
} }
#endif
struct class ieee80211_class = { struct class ieee80211_class = {
.name = "ieee80211", .name = "ieee80211",
......
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