> + /* Type-check Boolean feature values: */
> + case DCCPF_SHORT_SEQNOS:
> + case DCCPF_ECN_INCAPABLE:
> + case DCCPF_SEND_ACK_VECTOR:
> + case DCCPF_SEND_NDP_COUNT:
> + case DCCPF_DATA_CHECKSUM:
> + case DCCPF_SEND_LEV_RATE:
> + return val < 2;
> + case DCCPF_MIN_CSUM_COVER:
> + return val < 16;
> + }
> + return 0; /* feature unknown */
> +}
> +
> +static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
> +{
> + if (sp_list == NULL || sp_len < 1)
> + return 0;
> + while (sp_len--)
> + if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
> + return 0;
> + return 1;
> +}
> +
> +/**
> + * __feat_register_nn - Register new NN value on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an NN feature from %dccp_feature_numbers
> + * @mandatory: use Mandatory option if 1
> + * @nn_val: value to register (restricted to 4 bytes)
> + * Note that NN features are local by definition (RFC 4340, 6.3.2).
> + */
> +static int __feat_register_nn(struct list_head *fn, u8 feat,
> + u8 mandatory, u64 nn_val)
> +{
> + dccp_feat_val fval = { .nn = nn_val };
> +
> + if (dccp_feat_type(feat) != FEAT_NN ||
> + !dccp_feat_is_valid_nn_val(feat, nn_val))
> + return -EINVAL;
> +
> + /* Don't bother with default values, they will be activated anyway. */
> + if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
> + return 0;
> +
> + return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
> +}
> +
> +/**
> + * __feat_register_sp - Register new SP value/list on socket
> + * @fn: feature-negotiation list to register with
> + * @feat: an SP feature from %dccp_feature_numbers
> + * @is_local: whether the local (1) or the remote (0) @feat is meant
> + * @mandatory: use Mandatory option if 1
> + * @sp_val: SP value followed by optional preference list
> + * @sp_len: length of @sp_val in bytes
> + */
> +static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
> + u8 mandatory, u8 const *sp_val, u8 sp_len)
> +{
> + dccp_feat_val fval;
> +
> + if (dccp_feat_type(feat) != FEAT_SP ||
> + !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
> + return -EINVAL;
> +
> + if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
> + return -ENOMEM;
> +
> + return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
> +}
> +
> int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
> u8 *val, u8 len, gfp_t gfp)
> {
> @@ -833,42 +922,30 @@ out_clean:
>
> EXPORT_SYMBOL_GPL(dccp_feat_clone);
>
> -static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat,
> - u8 *val, u8 len)
> -{
> - int rc = -ENOMEM;
> - u8 *copy = kmemdup(val, len, GFP_KERNEL);
> -
> - if (copy != NULL) {
> - rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
> - if (rc)
> - kfree(copy);
> - }
> - return rc;
> -}
> -
> -int dccp_feat_init(struct dccp_minisock *dmsk)
> +int dccp_feat_init(struct sock *sk)
> {
> + struct dccp_sock *dp = dccp_sk(sk);
> + struct dccp_minisock *dmsk = dccp_msk(sk);
> int rc;
>
> - INIT_LIST_HEAD(&dmsk->dccpms_pending);
> - INIT_LIST_HEAD(&dmsk->dccpms_conf);
> + INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */
> + INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */
>
> /* CCID L */
> - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID,
> - &dmsk->dccpms_tx_ccid, 1);
> + rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
> + &dmsk->dccpms_tx_ccid, 1);
> if (rc)
> goto out;
>
> /* CCID R */
> - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID,
> - &dmsk->dccpms_rx_ccid, 1);
> + rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
> + &dmsk->dccpms_rx_ccid, 1);
> if (rc)
> goto out;
>
> /* Ack ratio */
> - rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO,
> - &dmsk->dccpms_ack_ratio, 1);
> + rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
> + dmsk->dccpms_ack_ratio);
> out:
> return rc;
> }
> --- a/net/dccp/feat.h
> +++ b/net/dccp/feat.h
> @@ -14,6 +14,15 @@
> #include <linux/types.h>
> #include "dccp.h"
>
> +/*
> + * Known limits of feature values.
> + */
> +/* Ack Ratio takes 2-byte integer values (11.3) */
> +#define DCCPF_ACK_RATIO_MAX 0xFFFF
> +/* Wmin=32 and Wmax=2^46-1 from 7.5.2 */
> +#define DCCPF_SEQ_WMIN 32
> +#define DCCPF_SEQ_WMAX 0x3FFFFFFFFFFFull
> +
> enum dccp_feat_type {
> FEAT_AT_RX = 1, /* located at RX side of half-connection */
> FEAT_AT_TX = 2, /* located at TX side of half-connection */
> @@ -74,6 +83,20 @@ static inline u8 dccp_feat_genopt(struct dccp_feat_entry *entry)
> return entry->is_local ? DCCPO_CHANGE_L : DCCPO_CHANGE_R;
> }
>
> +/**
> + * struct ccid_dependency - Track changes resulting from choosing a CCID
> + * @dependent_feat: one of %dccp_feature_numbers
> + * @is_local: local (1) or remote (0) @dependent_feat
> + * @is_mandatory: whether presence of @dependent_feat is mission-critical or not
> + * @val: corresponding default value for @dependent_feat (u8 is sufficient here)
> + */
> +struct ccid_dependency {
> + u8 dependent_feat;
> + bool is_local:1,
> + is_mandatory:1;
> + u8 val;
> +};
> +
> #ifdef CONFIG_IP_DCCP_DEBUG
> extern const char *dccp_feat_typename(const u8 type);
> extern const char *dccp_feat_name(const u8 feat);
> @@ -96,6 +119,6 @@ extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
> extern void dccp_feat_clean(struct dccp_minisock *dmsk);
> extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
> extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
> -extern int dccp_feat_init(struct dccp_minisock *dmsk);
> +extern int dccp_feat_init(struct sock *sk);
>
> #endif /* _DCCP_FEAT_H */
> --- a/net/dccp/proto.c
> +++ b/net/dccp/proto.c
> @@ -202,7 +202,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
> * setsockopt(CCIDs-I-want/accept). -acme
> */
> if (likely(ctl_sock_initialized)) {
> - int rc = dccp_feat_init(dmsk);
> + int rc = dccp_feat_init(sk);
>
> if (rc)
> return rc;
> --
> 1.6.0.rc2
>
> --
> To unsubscribe from this list: send the line "unsubscribe dccp" in
> the body of a message to
majordomo@vger.kernel.org
> More majordomo info at
http://vger.kernel.org/majordomo-info.html