diff options
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r-- | net/dccp/feat.c | 232 |
1 files changed, 179 insertions, 53 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c index 4152308958ab..b04160a2eea5 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -25,6 +25,11 @@ | |||
25 | #include "ccid.h" | 25 | #include "ccid.h" |
26 | #include "feat.h" | 26 | #include "feat.h" |
27 | 27 | ||
28 | /* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */ | ||
29 | unsigned long sysctl_dccp_sequence_window __read_mostly = 100; | ||
30 | int sysctl_dccp_rx_ccid __read_mostly = 2, | ||
31 | sysctl_dccp_tx_ccid __read_mostly = 2; | ||
32 | |||
28 | /* | 33 | /* |
29 | * Feature activation handlers. | 34 | * Feature activation handlers. |
30 | * | 35 | * |
@@ -51,8 +56,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx) | |||
51 | 56 | ||
52 | static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx) | 57 | static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx) |
53 | { | 58 | { |
54 | if (!rx) | 59 | struct dccp_sock *dp = dccp_sk(sk); |
55 | dccp_msk(sk)->dccpms_sequence_window = seq_win; | 60 | |
61 | if (rx) { | ||
62 | dp->dccps_r_seq_win = seq_win; | ||
63 | /* propagate changes to update SWL/SWH */ | ||
64 | dccp_update_gsr(sk, dp->dccps_gsr); | ||
65 | } else { | ||
66 | dp->dccps_l_seq_win = seq_win; | ||
67 | /* propagate changes to update AWL */ | ||
68 | dccp_update_gss(sk, dp->dccps_gss); | ||
69 | } | ||
56 | return 0; | 70 | return 0; |
57 | } | 71 | } |
58 | 72 | ||
@@ -194,6 +208,100 @@ static int dccp_feat_default_value(u8 feat_num) | |||
194 | return idx < 0 ? 0 : dccp_feat_table[idx].default_value; | 208 | return idx < 0 ? 0 : dccp_feat_table[idx].default_value; |
195 | } | 209 | } |
196 | 210 | ||
211 | /* | ||
212 | * Debugging and verbose-printing section | ||
213 | */ | ||
214 | static const char *dccp_feat_fname(const u8 feat) | ||
215 | { | ||
216 | static const char *feature_names[] = { | ||
217 | [DCCPF_RESERVED] = "Reserved", | ||
218 | [DCCPF_CCID] = "CCID", | ||
219 | [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", | ||
220 | [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", | ||
221 | [DCCPF_ECN_INCAPABLE] = "ECN Incapable", | ||
222 | [DCCPF_ACK_RATIO] = "Ack Ratio", | ||
223 | [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", | ||
224 | [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", | ||
225 | [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", | ||
226 | [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", | ||
227 | }; | ||
228 | if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) | ||
229 | return feature_names[DCCPF_RESERVED]; | ||
230 | |||
231 | if (feat == DCCPF_SEND_LEV_RATE) | ||
232 | return "Send Loss Event Rate"; | ||
233 | if (feat >= DCCPF_MIN_CCID_SPECIFIC) | ||
234 | return "CCID-specific"; | ||
235 | |||
236 | return feature_names[feat]; | ||
237 | } | ||
238 | |||
239 | static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING", | ||
240 | "UNSTABLE", "STABLE" }; | ||
241 | |||
242 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
243 | static const char *dccp_feat_oname(const u8 opt) | ||
244 | { | ||
245 | switch (opt) { | ||
246 | case DCCPO_CHANGE_L: return "Change_L"; | ||
247 | case DCCPO_CONFIRM_L: return "Confirm_L"; | ||
248 | case DCCPO_CHANGE_R: return "Change_R"; | ||
249 | case DCCPO_CONFIRM_R: return "Confirm_R"; | ||
250 | } | ||
251 | return NULL; | ||
252 | } | ||
253 | |||
254 | static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val) | ||
255 | { | ||
256 | u8 i, type = dccp_feat_type(feat_num); | ||
257 | |||
258 | if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL)) | ||
259 | dccp_pr_debug_cat("(NULL)"); | ||
260 | else if (type == FEAT_SP) | ||
261 | for (i = 0; i < val->sp.len; i++) | ||
262 | dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]); | ||
263 | else if (type == FEAT_NN) | ||
264 | dccp_pr_debug_cat("%llu", (unsigned long long)val->nn); | ||
265 | else | ||
266 | dccp_pr_debug_cat("unknown type %u", type); | ||
267 | } | ||
268 | |||
269 | static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len) | ||
270 | { | ||
271 | u8 type = dccp_feat_type(feat_num); | ||
272 | dccp_feat_val fval = { .sp.vec = list, .sp.len = len }; | ||
273 | |||
274 | if (type == FEAT_NN) | ||
275 | fval.nn = dccp_decode_value_var(list, len); | ||
276 | dccp_feat_printval(feat_num, &fval); | ||
277 | } | ||
278 | |||
279 | static void dccp_feat_print_entry(struct dccp_feat_entry const *entry) | ||
280 | { | ||
281 | dccp_debug(" * %s %s = ", entry->is_local ? "local" : "remote", | ||
282 | dccp_feat_fname(entry->feat_num)); | ||
283 | dccp_feat_printval(entry->feat_num, &entry->val); | ||
284 | dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state], | ||
285 | entry->needs_confirm ? "(Confirm pending)" : ""); | ||
286 | } | ||
287 | |||
288 | #define dccp_feat_print_opt(opt, feat, val, len, mandatory) do { \ | ||
289 | dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\ | ||
290 | dccp_feat_printvals(feat, val, len); \ | ||
291 | dccp_pr_debug_cat(") %s\n", mandatory ? "!" : ""); } while (0) | ||
292 | |||
293 | #define dccp_feat_print_fnlist(fn_list) { \ | ||
294 | const struct dccp_feat_entry *___entry; \ | ||
295 | \ | ||
296 | dccp_pr_debug("List Dump:\n"); \ | ||
297 | list_for_each_entry(___entry, fn_list, node) \ | ||
298 | dccp_feat_print_entry(___entry); \ | ||
299 | } | ||
300 | #else /* ! CONFIG_IP_DCCP_DEBUG */ | ||
301 | #define dccp_feat_print_opt(opt, feat, val, len, mandatory) | ||
302 | #define dccp_feat_print_fnlist(fn_list) | ||
303 | #endif | ||
304 | |||
197 | static int __dccp_feat_activate(struct sock *sk, const int idx, | 305 | static int __dccp_feat_activate(struct sock *sk, const int idx, |
198 | const bool is_local, dccp_feat_val const *fval) | 306 | const bool is_local, dccp_feat_val const *fval) |
199 | { | 307 | { |
@@ -226,6 +334,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx, | |||
226 | /* Location is RX if this is a local-RX or remote-TX feature */ | 334 | /* Location is RX if this is a local-RX or remote-TX feature */ |
227 | rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX)); | 335 | rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX)); |
228 | 336 | ||
337 | dccp_debug(" -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX", | ||
338 | dccp_feat_fname(dccp_feat_table[idx].feat_num), | ||
339 | fval ? "" : "default ", (unsigned long long)val); | ||
340 | |||
229 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); | 341 | return dccp_feat_table[idx].activation_hdlr(sk, val, rx); |
230 | } | 342 | } |
231 | 343 | ||
@@ -530,6 +642,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq, | |||
530 | return -1; | 642 | return -1; |
531 | } | 643 | } |
532 | } | 644 | } |
645 | dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0); | ||
533 | 646 | ||
534 | if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) | 647 | if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt)) |
535 | return -1; | 648 | return -1; |
@@ -783,6 +896,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp) | |||
783 | while (i--) | 896 | while (i--) |
784 | if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i)) | 897 | if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i)) |
785 | return -1; | 898 | return -1; |
899 | dccp_feat_print_fnlist(fn); | ||
786 | return 0; | 900 | return 0; |
787 | } | 901 | } |
788 | 902 | ||
@@ -901,6 +1015,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt, | |||
901 | if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */ | 1015 | if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */ |
902 | goto unknown_feature_or_value; | 1016 | goto unknown_feature_or_value; |
903 | 1017 | ||
1018 | dccp_feat_print_opt(opt, feat, val, len, is_mandatory); | ||
1019 | |||
904 | /* | 1020 | /* |
905 | * Negotiation of NN features: Change R is invalid, so there is no | 1021 | * Negotiation of NN features: Change R is invalid, so there is no |
906 | * simultaneous negotiation; hence we do not look up in the list. | 1022 | * simultaneous negotiation; hence we do not look up in the list. |
@@ -1006,6 +1122,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt, | |||
1006 | const bool local = (opt == DCCPO_CONFIRM_R); | 1122 | const bool local = (opt == DCCPO_CONFIRM_R); |
1007 | struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local); | 1123 | struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local); |
1008 | 1124 | ||
1125 | dccp_feat_print_opt(opt, feat, val, len, is_mandatory); | ||
1126 | |||
1009 | if (entry == NULL) { /* nothing queued: ignore or handle error */ | 1127 | if (entry == NULL) { /* nothing queued: ignore or handle error */ |
1010 | if (is_mandatory && type == FEAT_UNKNOWN) | 1128 | if (is_mandatory && type == FEAT_UNKNOWN) |
1011 | return DCCP_RESET_CODE_MANDATORY_ERROR; | 1129 | return DCCP_RESET_CODE_MANDATORY_ERROR; |
@@ -1115,23 +1233,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1115 | return 0; /* ignore FN options in all other states */ | 1233 | return 0; /* ignore FN options in all other states */ |
1116 | } | 1234 | } |
1117 | 1235 | ||
1236 | /** | ||
1237 | * dccp_feat_init - Seed feature negotiation with host-specific defaults | ||
1238 | * This initialises global defaults, depending on the value of the sysctls. | ||
1239 | * These can later be overridden by registering changes via setsockopt calls. | ||
1240 | * The last link in the chain is finalise_settings, to make sure that between | ||
1241 | * here and the start of actual feature negotiation no inconsistencies enter. | ||
1242 | * | ||
1243 | * All features not appearing below use either defaults or are otherwise | ||
1244 | * later adjusted through dccp_feat_finalise_settings(). | ||
1245 | */ | ||
1118 | int dccp_feat_init(struct sock *sk) | 1246 | int dccp_feat_init(struct sock *sk) |
1119 | { | 1247 | { |
1120 | struct dccp_sock *dp = dccp_sk(sk); | 1248 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; |
1121 | struct dccp_minisock *dmsk = dccp_msk(sk); | 1249 | u8 on = 1, off = 0; |
1122 | int rc; | 1250 | int rc; |
1251 | struct { | ||
1252 | u8 *val; | ||
1253 | u8 len; | ||
1254 | } tx, rx; | ||
1255 | |||
1256 | /* Non-negotiable (NN) features */ | ||
1257 | rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0, | ||
1258 | sysctl_dccp_sequence_window); | ||
1259 | if (rc) | ||
1260 | return rc; | ||
1261 | |||
1262 | /* Server-priority (SP) features */ | ||
1263 | |||
1264 | /* Advertise that short seqnos are not supported (7.6.1) */ | ||
1265 | rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1); | ||
1266 | if (rc) | ||
1267 | return rc; | ||
1123 | 1268 | ||
1124 | INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ | 1269 | /* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */ |
1125 | INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ | 1270 | rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1); |
1271 | if (rc) | ||
1272 | return rc; | ||
1273 | |||
1274 | /* | ||
1275 | * We advertise the available list of CCIDs and reorder according to | ||
1276 | * preferences, to avoid failure resulting from negotiating different | ||
1277 | * singleton values (which always leads to failure). | ||
1278 | * These settings can still (later) be overridden via sockopts. | ||
1279 | */ | ||
1280 | if (ccid_get_builtin_ccids(&tx.val, &tx.len) || | ||
1281 | ccid_get_builtin_ccids(&rx.val, &rx.len)) | ||
1282 | return -ENOBUFS; | ||
1283 | |||
1284 | if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) || | ||
1285 | !dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len)) | ||
1286 | goto free_ccid_lists; | ||
1287 | |||
1288 | rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len); | ||
1289 | if (rc) | ||
1290 | goto free_ccid_lists; | ||
1291 | |||
1292 | rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len); | ||
1126 | 1293 | ||
1127 | /* Ack ratio */ | 1294 | free_ccid_lists: |
1128 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, | 1295 | kfree(tx.val); |
1129 | dp->dccps_l_ack_ratio); | 1296 | kfree(rx.val); |
1130 | return rc; | 1297 | return rc; |
1131 | } | 1298 | } |
1132 | 1299 | ||
1133 | EXPORT_SYMBOL_GPL(dccp_feat_init); | ||
1134 | |||
1135 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) | 1300 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) |
1136 | { | 1301 | { |
1137 | struct dccp_sock *dp = dccp_sk(sk); | 1302 | struct dccp_sock *dp = dccp_sk(sk); |
@@ -1156,9 +1321,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) | |||
1156 | goto activation_failed; | 1321 | goto activation_failed; |
1157 | } | 1322 | } |
1158 | if (cur->state != FEAT_STABLE) { | 1323 | if (cur->state != FEAT_STABLE) { |
1159 | DCCP_CRIT("Negotiation of %s %u failed in state %u", | 1324 | DCCP_CRIT("Negotiation of %s %s failed in state %s", |
1160 | cur->is_local ? "local" : "remote", | 1325 | cur->is_local ? "local" : "remote", |
1161 | cur->feat_num, cur->state); | 1326 | dccp_feat_fname(cur->feat_num), |
1327 | dccp_feat_sname[cur->state]); | ||
1162 | goto activation_failed; | 1328 | goto activation_failed; |
1163 | } | 1329 | } |
1164 | fvals[idx][cur->is_local] = &cur->val; | 1330 | fvals[idx][cur->is_local] = &cur->val; |
@@ -1199,43 +1365,3 @@ activation_failed: | |||
1199 | dp->dccps_hc_rx_ackvec = NULL; | 1365 | dp->dccps_hc_rx_ackvec = NULL; |
1200 | return -1; | 1366 | return -1; |
1201 | } | 1367 | } |
1202 | |||
1203 | #ifdef CONFIG_IP_DCCP_DEBUG | ||
1204 | const char *dccp_feat_typename(const u8 type) | ||
1205 | { | ||
1206 | switch(type) { | ||
1207 | case DCCPO_CHANGE_L: return("ChangeL"); | ||
1208 | case DCCPO_CONFIRM_L: return("ConfirmL"); | ||
1209 | case DCCPO_CHANGE_R: return("ChangeR"); | ||
1210 | case DCCPO_CONFIRM_R: return("ConfirmR"); | ||
1211 | /* the following case must not appear in feature negotation */ | ||
1212 | default: dccp_pr_debug("unknown type %d [BUG!]\n", type); | ||
1213 | } | ||
1214 | return NULL; | ||
1215 | } | ||
1216 | |||
1217 | const char *dccp_feat_name(const u8 feat) | ||
1218 | { | ||
1219 | static const char *feature_names[] = { | ||
1220 | [DCCPF_RESERVED] = "Reserved", | ||
1221 | [DCCPF_CCID] = "CCID", | ||
1222 | [DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos", | ||
1223 | [DCCPF_SEQUENCE_WINDOW] = "Sequence Window", | ||
1224 | [DCCPF_ECN_INCAPABLE] = "ECN Incapable", | ||
1225 | [DCCPF_ACK_RATIO] = "Ack Ratio", | ||
1226 | [DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector", | ||
1227 | [DCCPF_SEND_NDP_COUNT] = "Send NDP Count", | ||
1228 | [DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage", | ||
1229 | [DCCPF_DATA_CHECKSUM] = "Send Data Checksum", | ||
1230 | }; | ||
1231 | if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC) | ||
1232 | return feature_names[DCCPF_RESERVED]; | ||
1233 | |||
1234 | if (feat == DCCPF_SEND_LEV_RATE) | ||
1235 | return "Send Loss Event Rate"; | ||
1236 | if (feat >= DCCPF_MIN_CCID_SPECIFIC) | ||
1237 | return "CCID-specific"; | ||
1238 | |||
1239 | return feature_names[feat]; | ||
1240 | } | ||
1241 | #endif /* CONFIG_IP_DCCP_DEBUG */ | ||