aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--net/dccp/feat.c146
-rw-r--r--net/dccp/feat.h4
-rw-r--r--net/dccp/options.c23
3 files changed, 155 insertions, 18 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index d53077bd40bf..01b4da7007b2 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -983,7 +983,6 @@ static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
983 983
984 return 0; 984 return 0;
985} 985}
986#endif /* (later) */
987 986
988static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk, 987static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
989 u8 type, u8 feature) 988 u8 type, u8 feature)
@@ -1094,6 +1093,7 @@ int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1094} 1093}
1095 1094
1096EXPORT_SYMBOL_GPL(dccp_feat_change_recv); 1095EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
1096#endif /* (later) */
1097 1097
1098int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 1098int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
1099 u8 *val, u8 len) 1099 u8 *val, u8 len)
@@ -1234,6 +1234,150 @@ out_clean:
1234 1234
1235EXPORT_SYMBOL_GPL(dccp_feat_clone); 1235EXPORT_SYMBOL_GPL(dccp_feat_clone);
1236 1236
1237/**
1238 * dccp_feat_change_recv - Process incoming ChangeL/R options
1239 * @fn: feature-negotiation list to update
1240 * @is_mandatory: whether the Change was preceded by a Mandatory option
1241 * @opt: %DCCPO_CHANGE_L or %DCCPO_CHANGE_R
1242 * @feat: one of %dccp_feature_numbers
1243 * @val: NN value or SP value/preference list
1244 * @len: length of @val in bytes
1245 * @server: whether this node is the server (1) or the client (0)
1246 */
1247static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
1248 u8 feat, u8 *val, u8 len, const bool server)
1249{
1250 u8 defval, type = dccp_feat_type(feat);
1251 const bool local = (opt == DCCPO_CHANGE_R);
1252 struct dccp_feat_entry *entry;
1253 dccp_feat_val fval;
1254
1255 if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */
1256 goto unknown_feature_or_value;
1257
1258 /*
1259 * Negotiation of NN features: Change R is invalid, so there is no
1260 * simultaneous negotiation; hence we do not look up in the list.
1261 */
1262 if (type == FEAT_NN) {
1263 if (local || len > sizeof(fval.nn))
1264 goto unknown_feature_or_value;
1265
1266 /* 6.3.2: "The feature remote MUST accept any valid value..." */
1267 fval.nn = dccp_decode_value_var(val, len);
1268 if (!dccp_feat_is_valid_nn_val(feat, fval.nn))
1269 goto unknown_feature_or_value;
1270
1271 return dccp_feat_push_confirm(fn, feat, local, &fval);
1272 }
1273
1274 /*
1275 * Unidirectional/simultaneous negotiation of SP features (6.3.1)
1276 */
1277 entry = dccp_feat_list_lookup(fn, feat, local);
1278 if (entry == NULL) {
1279 /*
1280 * No particular preferences have been registered. We deal with
1281 * this situation by assuming that all valid values are equally
1282 * acceptable, and apply the following checks:
1283 * - if the peer's list is a singleton, we accept a valid value;
1284 * - if we are the server, we first try to see if the peer (the
1285 * client) advertises the default value. If yes, we use it,
1286 * otherwise we accept the preferred value;
1287 * - else if we are the client, we use the first list element.
1288 */
1289 if (dccp_feat_clone_sp_val(&fval, val, 1))
1290 return DCCP_RESET_CODE_TOO_BUSY;
1291
1292 if (len > 1 && server) {
1293 defval = dccp_feat_default_value(feat);
1294 if (dccp_feat_preflist_match(&defval, 1, val, len) > -1)
1295 fval.sp.vec[0] = defval;
1296 } else if (!dccp_feat_is_valid_sp_val(feat, fval.sp.vec[0])) {
1297 kfree(fval.sp.vec);
1298 goto unknown_feature_or_value;
1299 }
1300
1301 /* Treat unsupported CCIDs like invalid values */
1302 if (feat == DCCPF_CCID && !ccid_support_check(fval.sp.vec, 1)) {
1303 kfree(fval.sp.vec);
1304 goto not_valid_or_not_known;
1305 }
1306
1307 return dccp_feat_push_confirm(fn, feat, local, &fval);
1308
1309 } else if (entry->state == FEAT_UNSTABLE) { /* 6.6.2 */
1310 return 0;
1311 }
1312
1313 if (dccp_feat_reconcile(&entry->val, val, len, server, true)) {
1314 entry->empty_confirm = 0;
1315 } else if (is_mandatory) {
1316 return DCCP_RESET_CODE_MANDATORY_ERROR;
1317 } else if (entry->state == FEAT_INITIALISING) {
1318 /*
1319 * Failed simultaneous negotiation (server only): try to `save'
1320 * the connection by checking whether entry contains the default
1321 * value for @feat. If yes, send an empty Confirm to signal that
1322 * the received Change was not understood - which implies using
1323 * the default value.
1324 * If this also fails, we use Reset as the last resort.
1325 */
1326 WARN_ON(!server);
1327 defval = dccp_feat_default_value(feat);
1328 if (!dccp_feat_reconcile(&entry->val, &defval, 1, server, true))
1329 return DCCP_RESET_CODE_OPTION_ERROR;
1330 entry->empty_confirm = 1;
1331 }
1332 entry->needs_confirm = 1;
1333 entry->needs_mandatory = 0;
1334 entry->state = FEAT_STABLE;
1335 return 0;
1336
1337unknown_feature_or_value:
1338 if (!is_mandatory)
1339 return dccp_push_empty_confirm(fn, feat, local);
1340
1341not_valid_or_not_known:
1342 return is_mandatory ? DCCP_RESET_CODE_MANDATORY_ERROR
1343 : DCCP_RESET_CODE_OPTION_ERROR;
1344}
1345
1346/**
1347 * dccp_feat_parse_options - Process Feature-Negotiation Options
1348 * @sk: for general use and used by the client during connection setup
1349 * @dreq: used by the server during connection setup
1350 * @mandatory: whether @opt was preceded by a Mandatory option
1351 * @opt: %DCCPO_CHANGE_L | %DCCPO_CHANGE_R | %DCCPO_CONFIRM_L | %DCCPO_CONFIRM_R
1352 * @feat: one of %dccp_feature_numbers
1353 * @val: value contents of @opt
1354 * @len: length of @val in bytes
1355 * Returns 0 on success, a Reset code for ending the connection otherwise.
1356 */
1357int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
1358 u8 mandatory, u8 opt, u8 feat, u8 *val, u8 len)
1359{
1360 struct dccp_sock *dp = dccp_sk(sk);
1361 struct list_head *fn = dreq ? &dreq->dreq_featneg : &dp->dccps_featneg;
1362 bool server = false;
1363
1364 switch (sk->sk_state) {
1365 /*
1366 * Negotiation during connection setup
1367 */
1368 case DCCP_LISTEN:
1369 server = true; /* fall through */
1370 case DCCP_REQUESTING:
1371 switch (opt) {
1372 case DCCPO_CHANGE_L:
1373 case DCCPO_CHANGE_R:
1374 return dccp_feat_change_recv(fn, mandatory, opt, feat,
1375 val, len, server);
1376 }
1377 }
1378 return 0; /* ignore FN options in all other states */
1379}
1380
1237int dccp_feat_init(struct sock *sk) 1381int dccp_feat_init(struct sock *sk)
1238{ 1382{
1239 struct dccp_sock *dp = dccp_sk(sk); 1383 struct dccp_sock *dp = dccp_sk(sk);
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 8e863839ed91..ce97f3fe7687 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -115,8 +115,8 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
115extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, 115extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
116 u8 const *list, u8 len); 116 u8 const *list, u8 len);
117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); 117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
118extern int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, 118extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
119 u8 *val, u8 len); 119 u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
120extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature, 120extern int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
121 u8 *val, u8 len); 121 u8 *val, u8 len);
122extern void dccp_feat_clean(struct dccp_minisock *dmsk); 122extern void dccp_feat_clean(struct dccp_minisock *dmsk);
diff --git a/net/dccp/options.c b/net/dccp/options.c
index 0e277114cb23..fb8466ea467a 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;