[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.
Signed-off-by: Gerrit Renker [EMAIL PROTECTED]
---
net/dccp/feat.c | 230
1 file changed, 50 insertions(+), 180 deletions(-)
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -655,200 +655,68 @@ static int dccp_feat_update(struct sock
return 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