@@ -92,6 +92,18 @@ static u8 dccp_feat_type(u8 feat_num)
92
92
return dccp_feat_table [idx ].reconciliation ;
93
93
}
94
94
95
+ static 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
107
/* copy constructor, fval must not already contain allocated memory */
96
108
static 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
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
+ */
177
+ static 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
+ */
208
+ static 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
+
158
227
static inline void dccp_feat_list_pop (struct dccp_feat_entry * entry )
159
228
{
160
229
list_del (& entry -> node );
@@ -190,6 +259,95 @@ int dccp_feat_clone_list(struct list_head const *from, struct list_head *to)
190
259
return - ENOMEM ;
191
260
}
192
261
262
+ static 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 */
274
+ static 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
+
293
+ static 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
+ */
311
+ static 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
+ */
336
+ static 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
+
193
351
int dccp_feat_change (struct dccp_minisock * dmsk , u8 type , u8 feature ,
194
352
u8 * val , u8 len , gfp_t gfp )
195
353
{
@@ -726,42 +884,30 @@ int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
726
884
727
885
EXPORT_SYMBOL_GPL (dccp_feat_clone );
728
886
729
- static int __dccp_feat_init (struct dccp_minisock * dmsk , u8 type , u8 feat ,
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
-
743
- int dccp_feat_init (struct dccp_minisock * dmsk )
887
+ int dccp_feat_init (struct sock * sk )
744
888
{
889
+ struct dccp_sock * dp = dccp_sk (sk );
890
+ struct dccp_minisock * dmsk = dccp_msk (sk );
745
891
int rc ;
746
892
747
- INIT_LIST_HEAD (& dmsk -> dccpms_pending );
748
- INIT_LIST_HEAD (& dmsk -> dccpms_conf );
893
+ INIT_LIST_HEAD (& dmsk -> dccpms_pending ); /* XXX no longer used */
894
+ INIT_LIST_HEAD (& dmsk -> dccpms_conf ); /* XXX no longer used */
749
895
750
896
/* CCID L */
751
- rc = __dccp_feat_init ( dmsk , DCCPO_CHANGE_L , DCCPF_CCID ,
752
- & dmsk -> dccpms_tx_ccid , 1 );
897
+ rc = __feat_register_sp ( & dp -> dccps_featneg , DCCPF_CCID , 1 , 0 ,
898
+ & dmsk -> dccpms_tx_ccid , 1 );
753
899
if (rc )
754
900
goto out ;
755
901
756
902
/* CCID R */
757
- rc = __dccp_feat_init ( dmsk , DCCPO_CHANGE_R , DCCPF_CCID ,
758
- & dmsk -> dccpms_rx_ccid , 1 );
903
+ rc = __feat_register_sp ( & dp -> dccps_featneg , DCCPF_CCID , 0 , 0 ,
904
+ & dmsk -> dccpms_rx_ccid , 1 );
759
905
if (rc )
760
906
goto out ;
761
907
762
908
/* Ack ratio */
763
- rc = __dccp_feat_init ( dmsk , DCCPO_CHANGE_L , DCCPF_ACK_RATIO ,
764
- & dmsk -> dccpms_ack_ratio , 1 );
909
+ rc = __feat_register_nn ( & dp -> dccps_featneg , DCCPF_ACK_RATIO , 0 ,
910
+ dmsk -> dccpms_ack_ratio );
765
911
out :
766
912
return rc ;
767
913
}
0 commit comments