diff options
-rw-r--r-- | include/linux/dccp.h | 19 | ||||
-rw-r--r-- | net/dccp/feat.c | 65 | ||||
-rw-r--r-- | net/dccp/feat.h | 2 |
3 files changed, 57 insertions, 29 deletions
diff --git a/include/linux/dccp.h b/include/linux/dccp.h index 61734e27abb7..990e97fa1f07 100644 --- a/include/linux/dccp.h +++ b/include/linux/dccp.h | |||
@@ -369,28 +369,9 @@ static inline unsigned int dccp_hdr_len(const struct sk_buff *skb) | |||
369 | * Will be used to pass the state from dccp_request_sock to dccp_sock. | 369 | * Will be used to pass the state from dccp_request_sock to dccp_sock. |
370 | * | 370 | * |
371 | * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2) | 371 | * @dccpms_sequence_window - Sequence Window Feature (section 7.5.2) |
372 | * @dccpms_pending - List of features being negotiated | ||
373 | * @dccpms_conf - | ||
374 | */ | 372 | */ |
375 | struct dccp_minisock { | 373 | struct dccp_minisock { |
376 | __u64 dccpms_sequence_window; | 374 | __u64 dccpms_sequence_window; |
377 | struct list_head dccpms_pending; | ||
378 | struct list_head dccpms_conf; | ||
379 | }; | ||
380 | |||
381 | struct dccp_opt_conf { | ||
382 | __u8 *dccpoc_val; | ||
383 | __u8 dccpoc_len; | ||
384 | }; | ||
385 | |||
386 | struct dccp_opt_pend { | ||
387 | struct list_head dccpop_node; | ||
388 | __u8 dccpop_type; | ||
389 | __u8 dccpop_feat; | ||
390 | __u8 *dccpop_val; | ||
391 | __u8 dccpop_len; | ||
392 | int dccpop_conf; | ||
393 | struct dccp_opt_conf *dccpop_sc; | ||
394 | }; | 375 | }; |
395 | 376 | ||
396 | extern void dccp_minisock_init(struct dccp_minisock *dmsk); | 377 | extern void dccp_minisock_init(struct dccp_minisock *dmsk); |
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4152308958ab..67ffac9905f8 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -1115,23 +1115,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1115 | return 0; /* ignore FN options in all other states */ | 1115 | return 0; /* ignore FN options in all other states */ |
1116 | } | 1116 | } |
1117 | 1117 | ||
1118 | /** | ||
1119 | * dccp_feat_init - Seed feature negotiation with host-specific defaults | ||
1120 | * This initialises global defaults, depending on the value of the sysctls. | ||
1121 | * These can later be overridden by registering changes via setsockopt calls. | ||
1122 | * The last link in the chain is finalise_settings, to make sure that between | ||
1123 | * here and the start of actual feature negotiation no inconsistencies enter. | ||
1124 | * | ||
1125 | * All features not appearing below use either defaults or are otherwise | ||
1126 | * later adjusted through dccp_feat_finalise_settings(). | ||
1127 | */ | ||
1118 | int dccp_feat_init(struct sock *sk) | 1128 | int dccp_feat_init(struct sock *sk) |
1119 | { | 1129 | { |
1120 | struct dccp_sock *dp = dccp_sk(sk); | 1130 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; |
1121 | struct dccp_minisock *dmsk = dccp_msk(sk); | 1131 | u8 on = 1, off = 0; |
1122 | int rc; | 1132 | int rc; |
1133 | struct { | ||
1134 | u8 *val; | ||
1135 | u8 len; | ||
1136 | } tx, rx; | ||
1137 | |||
1138 | /* Non-negotiable (NN) features */ | ||
1139 | rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0, | ||
1140 | sysctl_dccp_feat_sequence_window); | ||
1141 | if (rc) | ||
1142 | return rc; | ||
1143 | |||
1144 | /* Server-priority (SP) features */ | ||
1145 | |||
1146 | /* Advertise that short seqnos are not supported (7.6.1) */ | ||
1147 | rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1); | ||
1148 | if (rc) | ||
1149 | return rc; | ||
1123 | 1150 | ||
1124 | INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ | 1151 | /* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */ |
1125 | INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ | 1152 | rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1); |
1153 | if (rc) | ||
1154 | return rc; | ||
1155 | |||
1156 | /* | ||
1157 | * We advertise the available list of CCIDs and reorder according to | ||
1158 | * preferences, to avoid failure resulting from negotiating different | ||
1159 | * singleton values (which always leads to failure). | ||
1160 | * These settings can still (later) be overridden via sockopts. | ||
1161 | */ | ||
1162 | if (ccid_get_builtin_ccids(&tx.val, &tx.len) || | ||
1163 | ccid_get_builtin_ccids(&rx.val, &rx.len)) | ||
1164 | return -ENOBUFS; | ||
1126 | 1165 | ||
1127 | /* Ack ratio */ | 1166 | if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) || |
1128 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, | 1167 | !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len)) |
1129 | dp->dccps_l_ack_ratio); | 1168 | goto free_ccid_lists; |
1169 | |||
1170 | rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len); | ||
1171 | if (rc) | ||
1172 | goto free_ccid_lists; | ||
1173 | |||
1174 | rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len); | ||
1175 | |||
1176 | free_ccid_lists: | ||
1177 | kfree(tx.val); | ||
1178 | kfree(rx.val); | ||
1130 | return rc; | 1179 | return rc; |
1131 | } | 1180 | } |
1132 | 1181 | ||
1133 | EXPORT_SYMBOL_GPL(dccp_feat_init); | ||
1134 | |||
1135 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) | 1182 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) |
1136 | { | 1183 | { |
1137 | struct dccp_sock *dp = dccp_sk(sk); | 1184 | struct dccp_sock *dp = dccp_sk(sk); |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 9b46e2a7866e..5e7b8481cd04 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -113,13 +113,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) | |||
113 | #define dccp_feat_debug(type, feat, val) | 113 | #define dccp_feat_debug(type, feat, val) |
114 | #endif /* CONFIG_IP_DCCP_DEBUG */ | 114 | #endif /* CONFIG_IP_DCCP_DEBUG */ |
115 | 115 | ||
116 | extern int dccp_feat_init(struct sock *sk); | ||
116 | extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, | 117 | extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, |
117 | u8 const *list, u8 len); | 118 | u8 const *list, u8 len); |
118 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); | 119 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); |
119 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, | 120 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, |
120 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); | 121 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); |
121 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | 122 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); |
122 | extern int dccp_feat_init(struct sock *sk); | ||
123 | 123 | ||
124 | /* | 124 | /* |
125 | * Encoding variable-length options and their maximum length. | 125 | * Encoding variable-length options and their maximum length. |