aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp/feat.c
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-11-12 03:43:40 -0500
committerDavid S. Miller <davem@davemloft.net>2008-11-12 03:43:40 -0500
commite8ef967a54f401ac5e8637b7f7f8bddb006144c4 (patch)
tree37f7e6b384f27f30158e8f5d750fa3235951265d /net/dccp/feat.c
parentf74e91b6cca5889e667193c7e794186db73c2000 (diff)
dccp: Registration routines for changing feature values
Two registration routines, for SP and NN features, are provided by this patch, replacing a previous routine which was used for both feature types. These are internal-only routines and therefore start with `__feat_register'. It further exports the known limits of Sequence Window and Ack Ratio as symbolic constants. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/dccp/feat.c')
-rw-r--r--net/dccp/feat.c192
1 files changed, 169 insertions, 23 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index 0e789e2e0aa9..192d494a3816 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
92 return dccp_feat_table[idx].reconciliation; 92 return dccp_feat_table[idx].reconciliation;
93} 93}
94 94
95static int dccp_feat_default_value(u8 feat_num)
96{
97 int idx = dccp_feat_index(feat_num);
98 /*
99 * There are no default values for unknown features, so encountering a
100 * negative index here indicates a serious problem somewhere else.
101 */
102 DCCP_BUG_ON(idx < 0);
103
104 return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
105}
106
95/* copy constructor, fval must not already contain allocated memory */ 107/* copy constructor, fval must not already contain allocated memory */
96static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len) 108static int dccp_feat_clone_sp_val(dccp_feat_val *fval, u8 const *val, u8 len)
97{ 109{
@@ -155,6 +167,63 @@ static void dccp_feat_entry_destructor(struct dccp_feat_entry *entry)
155 * - list is sorted in increasing order of feature number (faster lookup) 167 * - list is sorted in increasing order of feature number (faster lookup)
156 */ 168 */
157 169
170/**
171 * dccp_feat_entry_new - Central list update routine (called by all others)
172 * @head: list to add to
173 * @feat: feature number
174 * @local: whether the local (1) or remote feature with number @feat is meant
175 * This is the only constructor and serves to ensure the above invariants.
176 */
177static struct dccp_feat_entry *
178 dccp_feat_entry_new(struct list_head *head, u8 feat, bool local)
179{
180 struct dccp_feat_entry *entry;
181
182 list_for_each_entry(entry, head, node)
183 if (entry->feat_num == feat && entry->is_local == local) {
184 dccp_feat_val_destructor(entry->feat_num, &entry->val);
185 return entry;
186 } else if (entry->feat_num > feat) {
187 head = &entry->node;
188 break;
189 }
190
191 entry = kmalloc(sizeof(*entry), gfp_any());
192 if (entry != NULL) {
193 entry->feat_num = feat;
194 entry->is_local = local;
195 list_add_tail(&entry->node, head);
196 }
197 return entry;
198}
199
200/**
201 * dccp_feat_push_change - Add/overwrite a Change option in the list
202 * @fn_list: feature-negotiation list to update
203 * @feat: one of %dccp_feature_numbers
204 * @local: whether local (1) or remote (0) @feat_num is meant
205 * @needs_mandatory: whether to use Mandatory feature negotiation options
206 * @fval: pointer to NN/SP value to be inserted (will be copied)
207 */
208static int dccp_feat_push_change(struct list_head *fn_list, u8 feat, u8 local,
209 u8 mandatory, dccp_feat_val *fval)
210{
211 struct dccp_feat_entry *new = dccp_feat_entry_new(fn_list, feat, local);
212
213 if (new == NULL)
214 return -ENOMEM;
215
216 new->feat_num = feat;
217 new->is_local = local;
218 new->state = FEAT_INITIALISING;
219 new->needs_confirm = 0;
220 new->empty_confirm = 0;
221 new->val = *fval;
222 new->needs_mandatory = mandatory;
223
224 return 0;
225}
226
158static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry) 227static inline void dccp_feat_list_pop(struct dccp_feat_entry *entry)
159{ 228{
160 list_del(&entry->node); 229 list_del(&entry->node);
@@ -190,6 +259,95 @@ cloning_failed:
190 return -ENOMEM; 259 return -ENOMEM;
191} 260}
192 261
262static u8 dccp_feat_is_valid_nn_val(u8 feat_num, u64 val)
263{
264 switch (feat_num) {
265 case DCCPF_ACK_RATIO:
266 return val <= DCCPF_ACK_RATIO_MAX;
267 case DCCPF_SEQUENCE_WINDOW:
268 return val >= DCCPF_SEQ_WMIN && val <= DCCPF_SEQ_WMAX;
269 }
270 return 0; /* feature unknown - so we can't tell */
271}
272
273/* check that SP values are within the ranges defined in RFC 4340 */
274static u8 dccp_feat_is_valid_sp_val(u8 feat_num, u8 val)
275{
276 switch (feat_num) {
277 case DCCPF_CCID:
278 return val == DCCPC_CCID2 || val == DCCPC_CCID3;
279 /* Type-check Boolean feature values: */
280 case DCCPF_SHORT_SEQNOS:
281 case DCCPF_ECN_INCAPABLE:
282 case DCCPF_SEND_ACK_VECTOR:
283 case DCCPF_SEND_NDP_COUNT:
284 case DCCPF_DATA_CHECKSUM:
285 case DCCPF_SEND_LEV_RATE:
286 return val < 2;
287 case DCCPF_MIN_CSUM_COVER:
288 return val < 16;
289 }
290 return 0; /* feature unknown */
291}
292
293static u8 dccp_feat_sp_list_ok(u8 feat_num, u8 const *sp_list, u8 sp_len)
294{
295 if (sp_list == NULL || sp_len < 1)
296 return 0;
297 while (sp_len--)
298 if (!dccp_feat_is_valid_sp_val(feat_num, *sp_list++))
299 return 0;
300 return 1;
301}
302
303/**
304 * __feat_register_nn - Register new NN value on socket
305 * @fn: feature-negotiation list to register with
306 * @feat: an NN feature from %dccp_feature_numbers
307 * @mandatory: use Mandatory option if 1
308 * @nn_val: value to register (restricted to 4 bytes)
309 * Note that NN features are local by definition (RFC 4340, 6.3.2).
310 */
311static int __feat_register_nn(struct list_head *fn, u8 feat,
312 u8 mandatory, u64 nn_val)
313{
314 dccp_feat_val fval = { .nn = nn_val };
315
316 if (dccp_feat_type(feat) != FEAT_NN ||
317 !dccp_feat_is_valid_nn_val(feat, nn_val))
318 return -EINVAL;
319
320 /* Don't bother with default values, they will be activated anyway. */
321 if (nn_val - (u64)dccp_feat_default_value(feat) == 0)
322 return 0;
323
324 return dccp_feat_push_change(fn, feat, 1, mandatory, &fval);
325}
326
327/**
328 * __feat_register_sp - Register new SP value/list on socket
329 * @fn: feature-negotiation list to register with
330 * @feat: an SP feature from %dccp_feature_numbers
331 * @is_local: whether the local (1) or the remote (0) @feat is meant
332 * @mandatory: use Mandatory option if 1
333 * @sp_val: SP value followed by optional preference list
334 * @sp_len: length of @sp_val in bytes
335 */
336static int __feat_register_sp(struct list_head *fn, u8 feat, u8 is_local,
337 u8 mandatory, u8 const *sp_val, u8 sp_len)
338{
339 dccp_feat_val fval;
340
341 if (dccp_feat_type(feat) != FEAT_SP ||
342 !dccp_feat_sp_list_ok(feat, sp_val, sp_len))
343 return -EINVAL;
344
345 if (dccp_feat_clone_sp_val(&fval, sp_val, sp_len))
346 return -ENOMEM;
347
348 return dccp_feat_push_change(fn, feat, is_local, mandatory, &fval);
349}
350
193int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature, 351int dccp_feat_change(struct dccp_minisock *dmsk, u8 type, u8 feature,
194 u8 *val, u8 len, gfp_t gfp) 352 u8 *val, u8 len, gfp_t gfp)
195{ 353{
@@ -726,42 +884,30 @@ out_clean:
726 884
727EXPORT_SYMBOL_GPL(dccp_feat_clone); 885EXPORT_SYMBOL_GPL(dccp_feat_clone);
728 886
729static int __dccp_feat_init(struct dccp_minisock *dmsk, u8 type, u8 feat, 887int dccp_feat_init(struct sock *sk)
730 u8 *val, u8 len)
731{
732 int rc = -ENOMEM;
733 u8 *copy = kmemdup(val, len, GFP_KERNEL);
734
735 if (copy != NULL) {
736 rc = dccp_feat_change(dmsk, type, feat, copy, len, GFP_KERNEL);
737 if (rc)
738 kfree(copy);
739 }
740 return rc;
741}
742
743int dccp_feat_init(struct dccp_minisock *dmsk)
744{ 888{
889 struct dccp_sock *dp = dccp_sk(sk);
890 struct dccp_minisock *dmsk = dccp_msk(sk);
745 int rc; 891 int rc;
746 892
747 INIT_LIST_HEAD(&dmsk->dccpms_pending); 893 INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */
748 INIT_LIST_HEAD(&dmsk->dccpms_conf); 894 INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */
749 895
750 /* CCID L */ 896 /* CCID L */
751 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_CCID, 897 rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 1, 0,
752 &dmsk->dccpms_tx_ccid, 1); 898 &dmsk->dccpms_tx_ccid, 1);
753 if (rc) 899 if (rc)
754 goto out; 900 goto out;
755 901
756 /* CCID R */ 902 /* CCID R */
757 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_R, DCCPF_CCID, 903 rc = __feat_register_sp(&dp->dccps_featneg, DCCPF_CCID, 0, 0,
758 &dmsk->dccpms_rx_ccid, 1); 904 &dmsk->dccpms_rx_ccid, 1);
759 if (rc) 905 if (rc)
760 goto out; 906 goto out;
761 907
762 /* Ack ratio */ 908 /* Ack ratio */
763 rc = __dccp_feat_init(dmsk, DCCPO_CHANGE_L, DCCPF_ACK_RATIO, 909 rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
764 &dmsk->dccpms_ack_ratio, 1); 910 dmsk->dccpms_ack_ratio);
765out: 911out:
766 return rc; 912 return rc;
767} 913}