: Preference list reconciliation
PATCH 8/11 : Preference list reconciliation
[DCCP]: Preference list reconciliation
This provides two functions to
* reconcile preference lists (with appropriate return codes) and
* reorder the preference list if successful reconciliation changed the preferred value.
The patch also removes the old code for processing SP/NN Change options, since new code to process these is mostly there already; related references have been commented out.
The code for processing Change options follows in the next patch.
--- net/dccp/feat.c | 230 ++++++++++++-------------------------------------------- 1 file changed, 50 insertions(+), 180 deletions(-)
net/dccp/feat.c +50 -180
@@ -655,200 +655,68 @@ static int dccp_feat_update(struct sockreturn 0 ; } -static int dccp_feat_reconcile (struct sock *sk,struct dccp_opt_pend *opt, -u8 *rpref,u8 rlen) +/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */ +static int dccp_feat_preflist_match (u8 *servlist,u8 slen,u8 *clilist,u8 clen) { -struct dccp_sock *dp =dccp_sk (sk); -u8 *spref, slen, *res =NULL ; -int i, j, rc, agree =1 ; - -BUG_ON (rpref =NULL ); - -/* check if we are the black sheep */ -if (dp->dccps_role =DCCP_ROLE_CLIENT ) { - spref = rpref; - slen = rlen; - rpref = opt->dccpop_val; - rlen = opt->dccpop_len; - }else { - spref = opt->dccpop_val; - slen = opt->dccpop_len; - } -/* -* Now we have server preference list in spref and client preference in -* rpref -*/ -BUG_ON (spref =NULL ); -BUG_ON (rpref =NULL ); - -/* FIXME sanity check vals */ - -/* Are values in any order? XXX Lame "algorithm" here */ -for (i =0 ; i < slen; i++) { -for (j =0 ; j < rlen; j++) { -if (spref[i] = rpref[j]) { - res = &spref[i]; -break ; - } - } -if (res) -break ; - } - -/* we didn't agree on anything */ -if (res =NULL ) { -/* confirm previous value */ -switch (opt->dccpop_feat) { -case DCCPF_CCID : -/* XXX did i get this right? =P */ -if (opt->dccpop_type =DCCPO_CHANGE_L ) - res = &dccp_msk (sk)->dccpms_tx_ccid; -else - res = &dccp_msk (sk)->dccpms_rx_ccid; -break ; - -default : -DCCP_BUG ("Fell through, feat=%d" , opt->dccpop_feat); -/* XXX implement res */ -return -EFAULT ; - } +u8 c, s; -dccp_pr_debug ("Don't agree... reconfirming %d\n" , *res); - agree =0 ;/* this is used for mandatory options... */ - } - -/* need to put result and our preference list */ - rlen =1 + opt->dccpop_len; - rpref =kmalloc (rlen,GFP_ATOMIC ); -if (rpref =NULL ) -return -ENOMEM ; - - *rpref = *res; -memcpy (&rpref[1 ], opt->dccpop_val, opt->dccpop_len); - -/* put it in the "confirm queue" */ -if (opt->dccpop_sc =NULL ) { - opt->dccpop_sc =kmalloc (sizeof (*opt->dccpop_sc),GFP_ATOMIC ); -if (opt->dccpop_sc =NULL ) { -kfree (rpref); -return -ENOMEM ; - } - }else { -/* recycle the confirm slot */ -BUG_ON (opt->dccpop_sc->dccpoc_val =NULL ); -kfree (opt->dccpop_sc->dccpoc_val); -dccp_pr_debug ("recycling confirm slot\n" ); - } -memset (opt->dccpop_sc,0 ,sizeof (*opt->dccpop_sc)); - - opt->dccpop_sc->dccpoc_val = rpref; - opt->dccpop_sc->dccpoc_len = rlen; - -/* update the option on our side [we are about to send the confirm] */ - rc =dccp_feat_update (sk, opt->dccpop_type, opt->dccpop_feat, *res); -if (rc) { -kfree (opt->dccpop_sc->dccpoc_val); -kfree (opt->dccpop_sc); - opt->dccpop_sc =NULL ; -return rc; - } - -dccp_pr_debug ("Will confirm %d\n" , *rpref); - -/* say we want to change to X but we just got a confirm X, suppress our -* change -*/ -if (!opt->dccpop_conf) { -if (*opt->dccpop_val = *res) - opt->dccpop_conf =1 ; -dccp_pr_debug ("won't ask for change of same feature\n" ); - } - -return agree ?0 :DCCP_FEAT_SP_NOAGREE ;/* used for mandatory opts */ +for (s =0 ; s < slen; s++) +for (c =0 ; c < clen; c++) +if (servlist[s] = clilist[c]) +return servlist[s]; +return -1 ; } -static int dccp_feat_sp (struct sock *sk,u8 type,u8 feature,u8 *val,u8 len) +/* Reorder array so that the preferred value comes first. Returns > 0 on success. */ +static u8 dccp_feat_prefer (u8 preferred_value,u8 *array,u8 array_len) { -struct dccp_minisock *dmsk =dccp_msk (sk); -struct dccp_opt_pend *opt; -int rc =1 ; -u8 t; - -/* -* We received a CHANGE. We gotta match it against our own preference -* list. If we got a CHANGE_R it means it's a change for us, so we need -* to compare our CHANGE_L list. -*/ -if (type =DCCPO_CHANGE_L ) - t =DCCPO_CHANGE_R ; -else - t =DCCPO_CHANGE_L ; +u8 i, does_occur =0 ; -/* find our preference list for this feature */ -list_for_each_entry (opt, &dmsk->dccpms_pending, dccpop_node) { -if (opt->dccpop_type != t || opt->dccpop_feat != feature) -continue ; - -/* find the winner from the two preference lists */ - rc =dccp_feat_reconcile (sk, opt, val, len); -break ; +if (array !=NULL ) { +for (i =0 ; i < array_len; i++) +if (array[i] = preferred_value) { + array[i] = array[0 ]; + does_occur++; + } +if (does_occur) + array[0 ] = preferred_value; } - -/* We didn't deal with the change. This can happen if we have no -* preference list for the feature. In fact, it just shouldn't -* happen---if we understand a feature, we should have a preference list -* with at least the default value. -*/ -BUG_ON (rc =1 ); - -return rc; +return does_occur; } -static int dccp_feat_nn (struct sock *sk,u8 type,u8 feature,u8 *val,u8 len) +/** +* dccp_feat_reconcile - Reconcile SP preference lists +* @fval: SP list to reconcile into +* @arr: received SP preference list +* @len: length of @arr in bytes +* @is_server: whether this side is the server (and @fv is the server's list) +* @reorder: whether to reorder the list in @fv after reconciling with @arr +* When successful, > 0 is returned and the reconciled list is in @fval. +* A value of 0 means that negotiation failed (no shared entry). +*/ +static int dccp_feat_reconcile (dccp_feat_val *fv,u8 *arr,u8 len, +bool is_server,bool reorder) { -struct dccp_opt_pend *opt; -struct dccp_minisock *dmsk =dccp_msk (sk); -u8 *copy;int rc; -/* NN features must be Change L (sec. 6.3.2) */ -if (type !=DCCPO_CHANGE_L ) { -dccp_pr_debug ("received %s for NN feature %d\n" , -dccp_feat_typename (type), feature); -return -EFAULT ; - } - -/* XXX sanity check opt val */ - -/* copy option so we can confirm it */ - opt =kzalloc (sizeof (*opt),GFP_ATOMIC ); -if (opt =NULL ) -return -ENOMEM ; - - copy =kmemdup (val, len,GFP_ATOMIC ); -if (copy =NULL ) { -kfree (opt); -return -ENOMEM ; - } +BUG_TRAP (fv->sp.vec !=NULL && arr !=NULL ); +if (!fv->sp.vec || !arr) +return 0 ; - opt->dccpop_type =DCCPO_CONFIRM_R ;/* NN can only confirm R */ - opt->dccpop_feat = feature; - opt->dccpop_val = copy; - opt->dccpop_len = len; +if (is_server) + rc =dccp_feat_preflist_match (fv->sp.vec, fv->sp.len, arr, len); +else + rc =dccp_feat_preflist_match (arr, len, fv->sp.vec, fv->sp.len); -/* change feature */ - rc =dccp_feat_update (sk, type, feature, *val); -if (rc) { -kfree (opt->dccpop_val); -kfree (opt); +if (!reorder)return rc; - } - -dccp_feat_debug (type, feature, *copy); - -list_add_tail (&opt->dccpop_node, &dmsk->dccpms_conf); +if (rc <0 ) +return 0 ; -return 0 ; +/* +* Reorder list: used for activating features and in dccp_insert_fn_opt. +*/ +return dccp_feat_prefer (rc, fv->sp.vec, fv->sp.len); } static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
@@ -925,12 +793,14 @@ int dccp_feat_change_recv(struct sock *sswitch (feature) {/* deal with SP features */ case DCCPF_CCID : - rc =dccp_feat_sp (sk, type, feature, val, len); +/* XXX Obsoleted by next patch +rc = dccp_feat_sp(sk, type, feature, val, len); */ break ;/* deal with NN features */ case DCCPF_ACK_RATIO : - rc =dccp_feat_nn (sk, type, feature, val, len); +/* XXX Obsoleted by next patch +rc = dccp_feat_nn(sk, type, feature, val, len); */ break ;/* XXX implement other features */
Quoted 7 lines · Gerrit Renker
[DCCP]: Preference list reconciliation
This provides two functions to
* reconcile preference lists (with appropriate return codes) and
* reorder the preference list if successful reconciliation changed the preferred value.
Quoted 6 lines
The patch also removes the old code for processing SP/NN Change options, since new code to process these is mostly there already; related references have been commented out.
The code for processing Change options follows in the next patch.Signed-off-by Gerrit Renker <[email protected]>