aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/feat.c180
-rw-r--r--net/dccp/feat.h4
-rw-r--r--net/dccp/options.c23
3 files changed, 189 insertions, 18 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index fe6d557328d6..283c7fb8c7dc 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -237,6 +237,40 @@ static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
237 return 0; 237 return 0;
238} 238}
239 239
240/**
241 * dccp_feat_push_confirm - Add a Confirm entry to the FN list
242 * @fn_list: feature-negotiation list to add to
243 * @feat: one of %dccp_feature_numbers
244 * @local: whether local (1) or remote (0) @feat_num is being confirmed
245 * @fval: pointer to NN/SP value to be inserted or NULL
246 * Returns 0 on success, a Reset code for further processing otherwise.
247 */
248static int dccp_feat_push_confirm(struct list_head *fn_list, u8 feat, u8 local,
249 dccp_feat_val *fval)
250{
251 struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
252
253 if (new == NULL)
254 return DCCP_RESET_CODE_TOO_BUSY;
255
256 new->feat_num = feat;
257 new->is_local = local;
258 new->state = FEAT_STABLE; /* transition in 6.6.2 */
259 new->needs_confirm = 1;
260 new->empty_confirm = (fval == NULL);
261 new->val.nn = 0; /* zeroes the whole structure */
262 if (!new->empty_confirm)
263 new->val = *fval;
264 new->needs_mandatory = 0;
265
266 return 0;
267}
268
269static int dccp_push_empty_confirm(struct list_head *fn_list, u8 feat, u8 local)
270{
271 return dccp_feat_push_confirm(fn_list, feat, local, NULL);
272}
273
240static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) 274static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
241{ 275{
242 list_del(&entry->node); 276 list_del(&entry->node);
@@ -955,7 +989,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
955 989
956 return 0; 990 return 0;
957} 991}
958#endif /* (later) */
959 992
960static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 993static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
961 u8 type, u8 feature) 994 u8 type, u8 feature)
@@ -1066,6 +1099,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1066} 1099}
1067 1100
1068EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 1101EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
1102#endif /* (later) */
1069 1103
1070int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 1104int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
1071 u8 *val, u8 len) 1105 u8 *val, u8 len)
@@ -1206,6 +1240,150 @@ out_clean:
1206 1240
1207EXPORT_SYMBOL_GPL(dccp_feat_clone); 1241EXPORT_SYMBOL_GPL(dccp_feat_clone);
1208 1242
1243/**
1244 * dccp_feat_change_recv - Process incoming ChangeL/R options
1245 * @fn: feature-negotiation list to update
1246 * @is_mandatory: whether the Change was preceded by a Mandatory option
1247 * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
1248 * @feat: one of %dccp_feature_numbers
1249 * @val: NN value or SP value/preference list
1250 * @len: length of @val in bytes
1251 * @server: whether this node is the server (1) or the client (0)
1252 */
1253static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
1254 u8 feat, u8 *val, u8 len, const bool server)
1255{
1256 u8 defval, type = dccp_feat_type(feat);
1257 const bool local = (opt == DCCPO_CHANGE_R);
1258 struct dccp_feat_entry *entry;
1259 dccp_feat_val fval;
1260
1261 if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */
1262 goto unknown_feature_or_value;
1263
1264 /*
1265 * Negotiation of NN features: Change R is invalid, so there is no
1266 * simultaneous negotiation; hence we do not look up in the list.
1267 */
1268 if (type == FEAT_NN) {
1269 if (local || len > sizeof(fval.nn))
1270 goto unknown_feature_or_value;
1271
1272 /* 6.3.2: "The feature remote MUST accept any valid value..." */
1273 fval.nn = dccp_decode_value_var(val, len);
1274 if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
1275 goto unknown_feature_or_value;
1276
1277 return dccp_feat_push_confirm(fn, feat, local, &fval);
1278 }
1279
1280 /*
1281 * Unidirectional/simultaneous negotiation of SP features (6.3.1)
1282 */
1283 entry = dccp_feat_list_lookup(fn, feat, local);
1284 if (entry == NULL) {
1285 /*
1286 * No particular preferences have been registered. We deal with
1287 * this situation by assuming that all valid values are equally
1288 * acceptable, and apply the following checks:
1289 * - if the peer's list is a singleton, we accept a valid value;
1290 * - if we are the server, we first try to see if the peer (the
1291 * client) advertises the default value. If yes, we use it,
1292 * otherwise we accept the preferred value;
1293 * - else if we are the client, we use the first list element.
1294 */
1295 if (dccp_feat_clone_sp_val(&fval, val, 1))
1296 return DCCP_RESET_CODE_TOO_BUSY;
1297
1298 if (len > 1 && server) {
1299 defval = dccp_feat_default_value(feat);
1300 if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
1301 fval.sp.vec[0] = defval;
1302 } else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
1303 kfree(fval.sp.vec);
1304 goto unknown_feature_or_value;
1305 }
1306
1307 /* Treat unsupported CCIDs like invalid values */
1308 if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
1309 kfree(fval.sp.vec);
1310 goto not_valid_or_not_known;
1311 }
1312
1313 return dccp_feat_push_confirm(fn, feat, local, &fval);
1314
1315 } else if (entry->state == FEAT_UNSTABLE) { /* 6.6.2 */
1316 return 0;
1317 }
1318
1319 if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
1320 entry->empty_confirm = 0;
1321 } else if (is_mandatory) {
1322 return DCCP_RESET_CODE_MANDATORY_ERROR;
1323 } else if (entry->state == FEAT_INITIALISING) {
1324 /*
1325 * Failed simultaneous negotiation (server only): try to `save'
1326 * the connection by checking whether entry contains the default
1327 * value for @feat. If yes, send an empty Confirm to signal that
1328 * the received Change was not understood - which implies using
1329 * the default value.
1330 * If this also fails, we use Reset as the last resort.
1331 */
1332 WARN_ON(!server);
1333 defval = dccp_feat_default_value(feat);
1334 if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
1335 return DCCP_RESET_CODE_OPTION_ERROR;
1336 entry->empty_confirm = 1;
1337 }
1338 entry->needs_confirm = 1;
1339 entry->needs_mandatory = 0;
1340 entry->state = FEAT_STABLE;
1341 return 0;
1342
1343unknown_feature_or_value:
1344 if (!is_mandatory)
1345 return dccp_push_empty_confirm(fn, feat, local);
1346
1347not_valid_or_not_known:
1348 return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
1349 : DCCP_RESET_CODE_OPTION_ERROR;
1350}
1351
1352/**
1353 * dccp_feat_parse_options - Process Feature-Negotiation Options
1354 * @sk: for general use and used by the client during connection setup
1355 * @dreq: used by the server during connection setup
1356 * @mandatory: whether @opt was preceded by a Mandatory option
1357 * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
1358 * @feat: one of %dccp_feature_numbers
1359 * @val: value contents of @opt
1360 * @len: length of @val in bytes
1361 * Returns 0 on success, a Reset code for ending the connection otherwise.
1362 */
1363int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
1364 u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
1365{
1366 struct dccp_sock *dp = dccp_sk(sk);
1367 struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
1368 bool server = false;
1369
1370 switch (sk->sk_state) {
1371 /*
1372 * Negotiation during connection setup
1373 */
1374 case DCCP_LISTEN:
1375 server = true; /* fall through */
1376 case DCCP_REQUESTING:
1377 switch (opt) {
1378 case DCCPO_CHANGE_L:
1379 case DCCPO_CHANGE_R:
1380 return dccp_feat_change_recv(fn, mandatory, opt, feat,
1381 val, len, server);
1382 }
1383 }
1384 return 0; /* ignore FN options in all other states */
1385}
1386
1209int dccp_feat_init(struct sock *sk) 1387int dccp_feat_init(struct sock *sk)
1210{ 1388{
1211 struct dccp_sock *dp = dccp_sk(sk); 1389 struct dccp_sock *dp = dccp_sk(sk);
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 7efb2025f6bf..8dc4b42ef172 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -116,8 +116,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
116extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, 116extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
117 u8 const *list, u8 len); 117 u8 const *list, u8 len);
118extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); 118extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
119extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, 119extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
120 u8 *val, u8 len); 120 u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
121extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 121extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
122 u8 *val, u8 len); 122 u8 *val, u8 len);
123extern void dccp_feat_clean(struct dccp_minisock *dmsk); 123extern void dccp_feat_clean(struct dccp_minisock *dmsk);
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 86c7a20d39b2..2c444c199725 100644
--- a/net/dccp/options.c
+++ b/net/dccp/options.c
@@ -135,22 +135,13 @@ int dccp_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
135 (unsigned long long)opt_recv->dccpor_ndp); 135 (unsigned long long)opt_recv->dccpor_ndp);
136 break; 136 break;
137 case DCCPO_CHANGE_L: 137 case DCCPO_CHANGE_L:
138 /* fall through */
139 case DCCPO_CHANGE_R: 138 case DCCPO_CHANGE_R:
140 if (pkt_type == DCCP_PKT_DATA) 139 if (pkt_type == DCCP_PKT_DATA)
141 break; 140 break;
142 if (len < 2) 141 rc = dccp_feat_parse_options(sk, dreq, mandatory, opt,
143 goto out_invalid_option; 142 *value, value + 1, len - 1);
144 rc = dccp_feat_change_recv(sk, opt, *value, value + 1, 143 if (rc)
145 len - 1); 144 goto out_featneg_failed;
146 /*
147 * When there is a change error, change_recv is
148 * responsible for dealing with it. i.e. reply with an
149 * empty confirm.
150 * If the change was mandatory, then we need to die.
151 */
152 if (rc && mandatory)
153 goto out_invalid_option;
154 break; 145 break;
155 case DCCPO_CONFIRM_L: 146 case DCCPO_CONFIRM_L:
156 /* fall through */ 147 /* fall through */
@@ -292,8 +283,10 @@ out_nonsensical_length:
292 283
293out_invalid_option: 284out_invalid_option:
294 DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT); 285 DCCP_INC_STATS_BH(DCCP_MIB_INVALIDOPT);
295 DCCP_SKB_CB(skb)->dccpd_reset_code = DCCP_RESET_CODE_OPTION_ERROR; 286 rc = DCCP_RESET_CODE_OPTION_ERROR;
296 DCCP_WARN("DCCP(%p): invalid option %d, len=%d", sk, opt, len); 287out_featneg_failed:
288 DCCP_WARN("DCCP(%p): Option %d (len=%d) error=%u\n", sk, opt, len, rc);
289 DCCP_SKB_CB(skb)->dccpd_reset_code = rc;
297 DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt; 290 DCCP_SKB_CB(skb)->dccpd_reset_data[0] = opt;
298 DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0; 291 DCCP_SKB_CB(skb)->dccpd_reset_data[1] = len > 0 ? value[0] : 0;
299 DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0; 292 DCCP_SKB_CB(skb)->dccpd_reset_data[2] = len > 1 ? value[1] : 0;