diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:31 -0400 |
commit | 5d3dac267a7fd0811ec777e76a81f97f5cdcb395 (patch) | |
tree | ef57f539a5be1c7776c73a4bcffe2d840e6883f5 | |
parent | b235dc4abbc1356284bd0dc730efa711f394e0e2 (diff) |
dccp: Initialisation framework for feature negotiation
This initialises feature negotiation from two tables, which are initialised
from sysctls.
As a novel feature, specifics of the implementation (e.g. currently short
seqnos and ECN are not supported) are advertised for robustness.
Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk>
Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
-rw-r--r-- | include/linux/dccp.h | 19 | ||||
-rw-r--r-- | net/dccp/feat.c | 66 | ||||
-rw-r--r-- | net/dccp/feat.h | 2 |
3 files changed, 57 insertions, 30 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 35a57ab3bb1e..a687740e4420 100644 --- a/net/dccp/feat.c +++ b/net/dccp/feat.c | |||
@@ -1110,24 +1110,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq, | |||
1110 | return 0; /* ignore FN options in all other states */ | 1110 | return 0; /* ignore FN options in all other states */ |
1111 | } | 1111 | } |
1112 | 1112 | ||
1113 | /** | ||
1114 | * dccp_feat_init - Seed feature negotiation with host-specific defaults | ||
1115 | * This initialises global defaults, depending on the value of the sysctls. | ||
1116 | * These can later be overridden by registering changes via setsockopt calls. | ||
1117 | * The last link in the chain is finalise_settings, to make sure that between | ||
1118 | * here and the start of actual feature negotiation no inconsistencies enter. | ||
1119 | * | ||
1120 | * All features not appearing below use either defaults or are otherwise | ||
1121 | * later adjusted through dccp_feat_finalise_settings(). | ||
1122 | */ | ||
1113 | int dccp_feat_init(struct sock *sk) | 1123 | int dccp_feat_init(struct sock *sk) |
1114 | { | 1124 | { |
1115 | struct dccp_sock *dp = dccp_sk(sk); | 1125 | struct list_head *fn = &dccp_sk(sk)->dccps_featneg; |
1116 | struct dccp_minisock *dmsk = dccp_msk(sk); | 1126 | u8 on = 1, off = 0; |
1117 | int rc; | 1127 | int rc; |
1128 | struct { | ||
1129 | u8 *val; | ||
1130 | u8 len; | ||
1131 | } tx, rx; | ||
1132 | |||
1133 | /* Non-negotiable (NN) features */ | ||
1134 | rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0, | ||
1135 | sysctl_dccp_feat_sequence_window); | ||
1136 | if (rc) | ||
1137 | return rc; | ||
1138 | |||
1139 | /* Server-priority (SP) features */ | ||
1140 | |||
1141 | /* Advertise that short seqnos are not supported (7.6.1) */ | ||
1142 | rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1); | ||
1143 | if (rc) | ||
1144 | return rc; | ||
1118 | 1145 | ||
1119 | INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */ | 1146 | /* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */ |
1120 | INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */ | 1147 | rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1); |
1148 | if (rc) | ||
1149 | return rc; | ||
1150 | |||
1151 | /* | ||
1152 | * We advertise the available list of CCIDs and reorder according to | ||
1153 | * preferences, to avoid failure resulting from negotiating different | ||
1154 | * singleton values (which always leads to failure). | ||
1155 | * These settings can still (later) be overridden via sockopts. | ||
1156 | */ | ||
1157 | if (ccid_get_builtin_ccids(&tx.val, &tx.len) || | ||
1158 | ccid_get_builtin_ccids(&rx.val, &rx.len)) | ||
1159 | return -ENOBUFS; | ||
1121 | 1160 | ||
1122 | /* Ack ratio */ | 1161 | if (!dccp_feat_prefer(sysctl_dccp_feat_tx_ccid, tx.val, tx.len) || |
1123 | rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0, | 1162 | !dccp_feat_prefer(sysctl_dccp_feat_rx_ccid, rx.val, rx.len)) |
1124 | dp->dccps_l_ack_ratio); | 1163 | goto free_ccid_lists; |
1125 | out: | 1164 | |
1165 | rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len); | ||
1166 | if (rc) | ||
1167 | goto free_ccid_lists; | ||
1168 | |||
1169 | rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len); | ||
1170 | |||
1171 | free_ccid_lists: | ||
1172 | kfree(tx.val); | ||
1173 | kfree(rx.val); | ||
1126 | return rc; | 1174 | return rc; |
1127 | } | 1175 | } |
1128 | 1176 | ||
1129 | EXPORT_SYMBOL_GPL(dccp_feat_init); | ||
1130 | |||
1131 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) | 1177 | int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list) |
1132 | { | 1178 | { |
1133 | struct dccp_sock *dp = dccp_sk(sk); | 1179 | struct dccp_sock *dp = dccp_sk(sk); |
diff --git a/net/dccp/feat.h b/net/dccp/feat.h index 177e9c39ea9f..f73b47abca93 100644 --- a/net/dccp/feat.h +++ b/net/dccp/feat.h | |||
@@ -112,13 +112,13 @@ static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val) | |||
112 | #define dccp_feat_debug(type, feat, val) | 112 | #define dccp_feat_debug(type, feat, val) |
113 | #endif /* CONFIG_IP_DCCP_DEBUG */ | 113 | #endif /* CONFIG_IP_DCCP_DEBUG */ |
114 | 114 | ||
115 | extern int dccp_feat_init(struct sock *sk); | ||
115 | extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, | 116 | extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local, |
116 | u8 const *list, u8 len); | 117 | u8 const *list, u8 len); |
117 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); | 118 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); |
118 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, | 119 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, |
119 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); | 120 | u8 mand, u8 opt, u8 feat, u8 *val, u8 len); |
120 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | 121 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); |
121 | extern int dccp_feat_init(struct sock *sk); | ||
122 | 122 | ||
123 | /* | 123 | /* |
124 | * Encoding variable-length options and their maximum length. | 124 | * Encoding variable-length options and their maximum length. |