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 61734e27abb..990e97fa1f0 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 4152308958a..67ffac9905f 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 9b46e2a7866..5e7b8481cd0 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. |
