Commit 2d0817d1 authored by Arnaldo Carvalho de Melo's avatar Arnaldo Carvalho de Melo Committed by David S. Miller
Browse files

[DCCP] options: Make dccp_insert_options & friends yell on error



And not the silly LIMIT_NETDEBUG and silently return without inserting
the option requested.

Also drop some old debugging messages associated to option insertion.
Signed-off-by: default avatarArnaldo Carvalho de Melo <acme@mandriva.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 110bae4e
......@@ -81,15 +81,16 @@ int dccp_insert_option_ackvec(struct sock *sk, struct sk_buff *skb)
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
return -1;
avr = dccp_ackvec_record_new();
if (avr == NULL)
return -1;
dccp_timestamp(sk, &now);
elapsed_time = timeval_delta(&now, &av->dccpav_time) / 10;
if (elapsed_time != 0)
dccp_insert_option_elapsed_time(sk, skb, elapsed_time);
if (elapsed_time != 0 &&
dccp_insert_option_elapsed_time(sk, skb, elapsed_time))
return -1;
avr = dccp_ackvec_record_new();
if (avr == NULL)
return -1;
DCCP_SKB_CB(skb)->dccpd_opt_len += len;
......@@ -310,7 +311,6 @@ int dccp_ackvec_add(struct dccp_ackvec *av, const struct sock *sk,
av->dccpav_buf_ackno = ackno;
dccp_timestamp(sk, &av->dccpav_time);
out:
dccp_pr_debug("");
return 0;
out_duplicate:
......
......@@ -41,9 +41,9 @@ struct ccid_operations {
unsigned char option,
unsigned char len, u16 idx,
unsigned char* value);
void (*ccid_hc_rx_insert_options)(struct sock *sk,
int (*ccid_hc_rx_insert_options)(struct sock *sk,
struct sk_buff *skb);
void (*ccid_hc_tx_insert_options)(struct sock *sk,
int (*ccid_hc_tx_insert_options)(struct sock *sk,
struct sk_buff *skb);
void (*ccid_hc_tx_packet_recv)(struct sock *sk,
struct sk_buff *skb);
......@@ -146,18 +146,20 @@ static inline int ccid_hc_rx_parse_options(struct ccid *ccid, struct sock *sk,
return rc;
}
static inline void ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
struct sk_buff *skb)
static inline int ccid_hc_tx_insert_options(struct ccid *ccid, struct sock *sk,
struct sk_buff *skb)
{
if (ccid->ccid_ops->ccid_hc_tx_insert_options != NULL)
ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
return ccid->ccid_ops->ccid_hc_tx_insert_options(sk, skb);
return 0;
}
static inline void ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
struct sk_buff *skb)
static inline int ccid_hc_rx_insert_options(struct ccid *ccid, struct sock *sk,
struct sk_buff *skb)
{
if (ccid->ccid_ops->ccid_hc_rx_insert_options != NULL)
ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
return ccid->ccid_ops->ccid_hc_rx_insert_options(sk, skb);
return 0;
}
static inline void ccid_hc_rx_get_info(struct ccid *ccid, struct sock *sk,
......
......@@ -574,16 +574,15 @@ static void ccid3_hc_tx_packet_recv(struct sock *sk, struct sk_buff *skb)
}
}
static void ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
static int ccid3_hc_tx_insert_options(struct sock *sk, struct sk_buff *skb)
{
const struct ccid3_hc_tx_sock *hctx = ccid3_hc_tx_sk(sk);
BUG_ON(hctx == NULL);
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return;
DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
if (sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN)
DCCP_SKB_CB(skb)->dccpd_ccval = hctx->ccid3hctx_last_win_count;
return 0;
}
static int ccid3_hc_tx_parse_options(struct sock *sk, unsigned char option,
......@@ -774,7 +773,7 @@ static void ccid3_hc_rx_send_feedback(struct sock *sk)
dccp_send_ack(sk);
}
static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
static int ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
{
const struct ccid3_hc_rx_sock *hcrx = ccid3_hc_rx_sk(sk);
__be32 x_recv, pinv;
......@@ -782,23 +781,27 @@ static void ccid3_hc_rx_insert_options(struct sock *sk, struct sk_buff *skb)
BUG_ON(hcrx == NULL);
if (!(sk->sk_state == DCCP_OPEN || sk->sk_state == DCCP_PARTOPEN))
return;
return 0;
DCCP_SKB_CB(skb)->dccpd_ccval = hcrx->ccid3hcrx_last_counter;
if (dccp_packet_without_ack(skb))
return;
if (hcrx->ccid3hcrx_elapsed_time != 0)
dccp_insert_option_elapsed_time(sk, skb,
hcrx->ccid3hcrx_elapsed_time);
dccp_insert_option_timestamp(sk, skb);
return 0;
x_recv = htonl(hcrx->ccid3hcrx_x_recv);
pinv = htonl(hcrx->ccid3hcrx_pinv);
dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv));
dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
&x_recv, sizeof(x_recv));
if ((hcrx->ccid3hcrx_elapsed_time != 0 &&
dccp_insert_option_elapsed_time(sk, skb,
hcrx->ccid3hcrx_elapsed_time)) ||
dccp_insert_option_timestamp(sk, skb) ||
dccp_insert_option(sk, skb, TFRC_OPT_LOSS_EVENT_RATE,
&pinv, sizeof(pinv)) ||
dccp_insert_option(sk, skb, TFRC_OPT_RECEIVE_RATE,
&x_recv, sizeof(x_recv)))
return -1;
return 0;
}
/* calculate first loss interval
......
......@@ -326,13 +326,13 @@ static inline int dccp_ack_pending(const struct sock *sk)
inet_csk_ack_scheduled(sk);
}
extern void dccp_insert_options(struct sock *sk, struct sk_buff *skb);
extern void dccp_insert_option_elapsed_time(struct sock *sk,
extern int dccp_insert_options(struct sock *sk, struct sk_buff *skb);
extern int dccp_insert_option_elapsed_time(struct sock *sk,
struct sk_buff *skb,
u32 elapsed_time);
extern void dccp_insert_option_timestamp(struct sock *sk,
extern int dccp_insert_option_timestamp(struct sock *sk,
struct sk_buff *skb);
extern void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
extern int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
unsigned char option,
const void *value, unsigned char len);
......
......@@ -283,17 +283,14 @@ static inline int dccp_ndp_len(const int ndp)
return likely(ndp <= 0xFF) ? 1 : ndp <= 0xFFFF ? 2 : 3;
}
void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
int dccp_insert_option(struct sock *sk, struct sk_buff *skb,
const unsigned char option,
const void *value, const unsigned char len)
{
unsigned char *to;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN) {
LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
"%d option!\n", option);
return;
}
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len + 2 > DCCP_MAX_OPT_LEN)
return -1;
DCCP_SKB_CB(skb)->dccpd_opt_len += len + 2;
......@@ -302,11 +299,12 @@ void dccp_insert_option(struct sock *sk, struct sk_buff *skb,
*to++ = len + 2;
memcpy(to, value, len);
return 0;
}
EXPORT_SYMBOL_GPL(dccp_insert_option);
static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
static int dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
int ndp = dp->dccps_ndp_count;
......@@ -322,7 +320,7 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
const int len = ndp_len + 2;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
return;
return -1;
DCCP_SKB_CB(skb)->dccpd_opt_len += len;
......@@ -331,6 +329,8 @@ static void dccp_insert_option_ndp(struct sock *sk, struct sk_buff *skb)
*ptr++ = len;
dccp_encode_value_var(ndp, ptr, ndp_len);
}
return 0;
}
static inline int dccp_elapsed_time_len(const u32 elapsed_time)
......@@ -338,27 +338,18 @@ static inline int dccp_elapsed_time_len(const u32 elapsed_time)
return elapsed_time == 0 ? 0 : elapsed_time <= 0xFFFF ? 2 : 4;
}
void dccp_insert_option_elapsed_time(struct sock *sk,
struct sk_buff *skb,
u32 elapsed_time)
int dccp_insert_option_elapsed_time(struct sock *sk, struct sk_buff *skb,
u32 elapsed_time)
{
#ifdef CONFIG_IP_DCCP_DEBUG
struct dccp_sock *dp = dccp_sk(sk);
const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
"CLIENT TX opt: " : "server TX opt: ";
#endif
const int elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
const int len = 2 + elapsed_time_len;
unsigned char *to;
if (elapsed_time_len == 0)
return;
return 0;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to "
"insert elapsed time!\n");
return;
}
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
return -1;
DCCP_SKB_CB(skb)->dccpd_opt_len += len;
......@@ -374,10 +365,7 @@ void dccp_insert_option_elapsed_time(struct sock *sk,
memcpy(to, &var32, 4);
}
dccp_pr_debug("%sELAPSED_TIME=%u, len=%d, seqno=%llu\n",
debug_prefix, elapsed_time,
len,
(unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
return 0;
}
EXPORT_SYMBOL_GPL(dccp_insert_option_elapsed_time);
......@@ -398,7 +386,7 @@ void dccp_timestamp(const struct sock *sk, struct timeval *tv)
EXPORT_SYMBOL_GPL(dccp_timestamp);
void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
int dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
{
struct timeval tv;
__be32 now;
......@@ -408,19 +396,15 @@ void dccp_insert_option_timestamp(struct sock *sk, struct sk_buff *skb)
/* yes this will overflow but that is the point as we want a
* 10 usec 32 bit timer which mean it wraps every 11.9 hours */
dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
return dccp_insert_option(sk, skb, DCCPO_TIMESTAMP, &now, sizeof(now));
}
EXPORT_SYMBOL_GPL(dccp_insert_option_timestamp);
static void dccp_insert_option_timestamp_echo(struct sock *sk,
struct sk_buff *skb)
static int dccp_insert_option_timestamp_echo(struct sock *sk,
struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
#ifdef CONFIG_IP_DCCP_DEBUG
const char *debug_prefix = dp->dccps_role == DCCP_ROLE_CLIENT ?
"CLIENT TX opt: " : "server TX opt: ";
#endif
struct timeval now;
__be32 tstamp_echo;
u32 elapsed_time;
......@@ -432,11 +416,8 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
elapsed_time_len = dccp_elapsed_time_len(elapsed_time);
len = 6 + elapsed_time_len;
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN) {
LIMIT_NETDEBUG(KERN_INFO "DCCP: packet too small to insert "
"timestamp echo!\n");
return;
}
if (DCCP_SKB_CB(skb)->dccpd_opt_len + len > DCCP_MAX_OPT_LEN)
return -1;
DCCP_SKB_CB(skb)->dccpd_opt_len += len;
......@@ -456,14 +437,10 @@ static void dccp_insert_option_timestamp_echo(struct sock *sk,
memcpy(to, &var32, 4);
}
dccp_pr_debug("%sTIMESTAMP_ECHO=%u, len=%d, seqno=%llu\n",
debug_prefix, dp->dccps_timestamp_echo,
len,
(unsigned long long) DCCP_SKB_CB(skb)->dccpd_seq);
dp->dccps_timestamp_echo = 0;
dp->dccps_timestamp_time.tv_sec = 0;
dp->dccps_timestamp_time.tv_usec = 0;
return 0;
}
static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
......@@ -491,7 +468,7 @@ static int dccp_insert_feat_opt(struct sk_buff *skb, u8 type, u8 feat,
return 0;
}
static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
static int dccp_insert_options_feat(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_opt_pend *opt, *next;
......@@ -551,44 +528,48 @@ static void dccp_insert_feat(struct sock *sk, struct sk_buff *skb)
inet_csk_reset_xmit_timer(sk, ICSK_TIME_RETRANS,
inet_csk(sk)->icsk_rto, DCCP_RTO_MAX);
}
return 0;
}
void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
int dccp_insert_options(struct sock *sk, struct sk_buff *skb)
{
struct dccp_sock *dp = dccp_sk(sk);
DCCP_SKB_CB(skb)->dccpd_opt_len = 0;
if (dp->dccps_options.dccpo_send_ndp_count)
dccp_insert_option_ndp(sk, skb);
if (dp->dccps_options.dccpo_send_ndp_count &&
dccp_insert_option_ndp(sk, skb))
return -1;
if (!dccp_packet_without_ack(skb)) {
if (dp->dccps_options.dccpo_send_ack_vector &&
dccp_ackvec_pending(dp->dccps_hc_rx_ackvec))
dccp_insert_option_ackvec(sk, skb);
if (dp->dccps_timestamp_echo != 0)
dccp_insert_option_timestamp_echo(sk, skb);
dccp_ackvec_pending(dp->dccps_hc_rx_ackvec) &&
dccp_insert_option_ackvec(sk, skb))
return -1;
if (dp->dccps_timestamp_echo != 0 &&
dccp_insert_option_timestamp_echo(sk, skb))
return -1;
}
if (dp->dccps_hc_rx_insert_options) {
ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb);
if (ccid_hc_rx_insert_options(dp->dccps_hc_rx_ccid, sk, skb))
return -1;
dp->dccps_hc_rx_insert_options = 0;
}
if (dp->dccps_hc_tx_insert_options) {
ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb);
if (ccid_hc_tx_insert_options(dp->dccps_hc_tx_ccid, sk, skb))
return -1;
dp->dccps_hc_tx_insert_options = 0;
}
/* Feature negotiation */
switch(DCCP_SKB_CB(skb)->dccpd_type) {
/* Data packets can't do feat negotiation */
case DCCP_PKT_DATA:
case DCCP_PKT_DATAACK:
break;
default:
dccp_insert_feat(sk, skb);
break;
}
/* Data packets can't do feat negotiation */
if (DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATA &&
DCCP_SKB_CB(skb)->dccpd_type != DCCP_PKT_DATAACK &&
dccp_insert_options_feat(sk, skb))
return -1;
/* XXX: insert other options when appropriate */
......@@ -602,4 +583,6 @@ void dccp_insert_options(struct sock *sk, struct sk_buff *skb)
DCCP_SKB_CB(skb)->dccpd_opt_len += padding;
}
}
return 0;
}
......@@ -83,7 +83,11 @@ static int dccp_transmit_skb(struct sock *sk, struct sk_buff *skb)
}
dcb->dccpd_seq = dp->dccps_gss;
dccp_insert_options(sk, skb);
if (dccp_insert_options(sk, skb)) {
kfree_skb(skb);
return -EPROTO;
}
skb->h.raw = skb_push(skb, dccp_header_size);
dh = dccp_hdr(skb);
......@@ -296,7 +300,11 @@ struct sk_buff *dccp_make_response(struct sock *sk, struct dst_entry *dst,
dreq = dccp_rsk(req);
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESPONSE;
DCCP_SKB_CB(skb)->dccpd_seq = dreq->dreq_iss;
dccp_insert_options(sk, skb);
if (dccp_insert_options(sk, skb)) {
kfree_skb(skb);
return NULL;
}
skb->h.raw = skb_push(skb, dccp_header_size);
......@@ -344,7 +352,11 @@ static struct sk_buff *dccp_make_reset(struct sock *sk, struct dst_entry *dst,
DCCP_SKB_CB(skb)->dccpd_reset_code = code;
DCCP_SKB_CB(skb)->dccpd_type = DCCP_PKT_RESET;
DCCP_SKB_CB(skb)->dccpd_seq = dp->dccps_gss;
dccp_insert_options(sk, skb);
if (dccp_insert_options(sk, skb)) {
kfree_skb(skb);
return NULL;
}
skb->h.raw = skb_push(skb, dccp_header_size);
......
Supports Markdown
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