aboutsummaryrefslogtreecommitdiffstats
path: root/net/dccp
diff options
context:
space:
mode:
authorGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:30:19 -0400
committerGerrit Renker <gerrit@erg.abdn.ac.uk>2008-09-04 01:45:30 -0400
commit23479cbfd30402c7d9fa413cc467983061073557 (patch)
treeb2b9e3fa10acdaf177424172d4ea4d86f7b00edd /net/dccp
parentc49b22729f3da7479c4e6c572d53fdd40201d0bd (diff)
dccp: Clean up old feature-negotiation infrastructure
The code removed by this patch is no longer referenced or used, the added lines update documentation and copyrights. Signed-off-by: Gerrit Renker <gerrit@erg.abdn.ac.uk> Acked-by: Ian McDonald <ian.mcdonald@jandi.co.nz>
Diffstat (limited to 'net/dccp')
-rw-r--r--net/dccp/feat.c505
-rw-r--r--net/dccp/feat.h12
2 files changed, 12 insertions, 505 deletions
diff --git a/net/dccp/feat.c b/net/dccp/feat.c
index f78bd357b5b1..6c82dea409d9 100644
--- a/net/dccp/feat.c
+++ b/net/dccp/feat.c
@@ -1,8 +1,13 @@
1/* 1/*
2 * net/dccp/feat.c 2 * net/dccp/feat.c
3 * 3 *
4 * An implementation of the DCCP protocol 4 * Feature negotiation for the DCCP protocol (RFC 4340, section 6)
5 * Andrea Bittau <a.bittau@cs.ucl.ac.uk> 5 *
6 * Copyright (c) 2008 The University of Aberdeen, Scotland, UK
7 * Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
8 * Rewrote from scratch, some bits from earlier code by
9 * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
10 *
6 * 11 *
7 * ASSUMPTIONS 12 * ASSUMPTIONS
8 * ----------- 13 * -----------
@@ -17,14 +22,10 @@
17 * as published by the Free Software Foundation; either version 22 * as published by the Free Software Foundation; either version
18 * 2 of the License, or (at your option) any later version. 23 * 2 of the License, or (at your option) any later version.
19 */ 24 */
20
21#include <linux/module.h> 25#include <linux/module.h>
22
23#include "ccid.h" 26#include "ccid.h"
24#include "feat.h" 27#include "feat.h"
25 28
26#define DCCP_FEAT_SP_NOAGREE (-123)
27
28/* 29/*
29 * Feature activation handlers. 30 * Feature activation handlers.
30 * 31 *
@@ -805,51 +806,6 @@ int dccp_feat_server_ccid_dependencies(struct dccp_request_sock *dreq)
805 return 0; 806 return 0;
806} 807}
807 808
808static int dccp_feat_update_ccid(struct sock *sk, u8 type, u8 new_ccid_nr)
809{
810 struct dccp_sock *dp = dccp_sk(sk);
811 struct dccp_minisock *dmsk = dccp_msk(sk);
812 /* figure out if we are changing our CCID or the peer's */
813 const int rx = type == DCCPO_CHANGE_R;
814 const u8 ccid_nr = rx ? dmsk->dccpms_rx_ccid : dmsk->dccpms_tx_ccid;
815 struct ccid *new_ccid;
816
817 /* Check if nothing is being changed. */
818 if (ccid_nr == new_ccid_nr)
819 return 0;
820
821 new_ccid = ccid_new(new_ccid_nr, sk, rx, GFP_ATOMIC);
822 if (new_ccid == NULL)
823 return -ENOMEM;
824
825 if (rx) {
826 ccid_hc_rx_delete(dp->dccps_hc_rx_ccid, sk);
827 dp->dccps_hc_rx_ccid = new_ccid;
828 dmsk->dccpms_rx_ccid = new_ccid_nr;
829 } else {
830 ccid_hc_tx_delete(dp->dccps_hc_tx_ccid, sk);
831 dp->dccps_hc_tx_ccid = new_ccid;
832 dmsk->dccpms_tx_ccid = new_ccid_nr;
833 }
834
835 return 0;
836}
837
838static int dccp_feat_update(struct sock *sk, u8 type, u8 feat, u8 val)
839{
840 dccp_feat_debug(type, feat, val);
841
842 switch (feat) {
843 case DCCPF_CCID:
844 return dccp_feat_update_ccid(sk, type, val);
845 default:
846 dccp_pr_debug("UNIMPLEMENTED: %s(%d, ...)\n",
847 dccp_feat_typename(type), feat);
848 break;
849 }
850 return 0;
851}
852
853/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */ 809/* Select the first entry in @servlist that also occurs in @clilist (6.3.1) */
854static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen) 810static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen)
855{ 811{
@@ -919,453 +875,6 @@ static int dccp_feat_reconcile(dccp_feat_val *fv, u8 *arr, u8 len,
919 return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len); 875 return dccp_feat_prefer(rc, fv->sp.vec, fv->sp.len);
920} 876}
921 877
922#ifdef __this_is_the_old_framework_and_will_be_removed_later_in_a_subsequent_patch
923static int dccp_feat_reconcile(struct sock *sk, struct dccp_opt_pend *opt,
924 u8 *rpref, u8 rlen)
925{
926 struct dccp_sock *dp = dccp_sk(sk);
927 u8 *spref, slen, *res = NULL;
928 int i, j, rc, agree = 1;
929
930 BUG_ON(rpref == NULL);
931
932 /* check if we are the black sheep */
933 if (dp->dccps_role == DCCP_ROLE_CLIENT) {
934 spref = rpref;
935 slen = rlen;
936 rpref = opt->dccpop_val;
937 rlen = opt->dccpop_len;
938 } else {
939 spref = opt->dccpop_val;
940 slen = opt->dccpop_len;
941 }
942 /*
943 * Now we have server preference list in spref and client preference in
944 * rpref
945 */
946 BUG_ON(spref == NULL);
947 BUG_ON(rpref == NULL);
948
949 /* FIXME sanity check vals */
950
951 /* Are values in any order? XXX Lame "algorithm" here */
952 for (i = 0; i < slen; i++) {
953 for (j = 0; j < rlen; j++) {
954 if (spref[i] == rpref[j]) {
955 res = &spref[i];
956 break;
957 }
958 }
959 if (res)
960 break;
961 }
962
963 /* we didn't agree on anything */
964 if (res == NULL) {
965 /* confirm previous value */
966 switch (opt->dccpop_feat) {
967 case DCCPF_CCID:
968 /* XXX did i get this right? =P */
969 if (opt->dccpop_type == DCCPO_CHANGE_L)
970 res = &dccp_msk(sk)->dccpms_tx_ccid;
971 else
972 res = &dccp_msk(sk)->dccpms_rx_ccid;
973 break;
974
975 default:
976 DCCP_BUG("Fell through, feat=%d", opt->dccpop_feat);
977 /* XXX implement res */
978 return -EFAULT;
979 }
980
981 dccp_pr_debug("Don't agree... reconfirming %d\n", *res);
982 agree = 0; /* this is used for mandatory options... */
983 }
984
985 /* need to put result and our preference list */
986 rlen = 1 + opt->dccpop_len;
987 rpref = kmalloc(rlen, GFP_ATOMIC);
988 if (rpref == NULL)
989 return -ENOMEM;
990
991 *rpref = *res;
992 memcpy(&rpref[1], opt->dccpop_val, opt->dccpop_len);
993
994 /* put it in the "confirm queue" */
995 if (opt->dccpop_sc == NULL) {
996 opt->dccpop_sc = kmalloc(sizeof(*opt->dccpop_sc), GFP_ATOMIC);
997 if (opt->dccpop_sc == NULL) {
998 kfree(rpref);
999 return -ENOMEM;
1000 }
1001 } else {
1002 /* recycle the confirm slot */
1003 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
1004 kfree(opt->dccpop_sc->dccpoc_val);
1005 dccp_pr_debug("recycling confirm slot\n");
1006 }
1007 memset(opt->dccpop_sc, 0, sizeof(*opt->dccpop_sc));
1008
1009 opt->dccpop_sc->dccpoc_val = rpref;
1010 opt->dccpop_sc->dccpoc_len = rlen;
1011
1012 /* update the option on our side [we are about to send the confirm] */
1013 rc = dccp_feat_update(sk, opt->dccpop_type, opt->dccpop_feat, *res);
1014 if (rc) {
1015 kfree(opt->dccpop_sc->dccpoc_val);
1016 kfree(opt->dccpop_sc);
1017 opt->dccpop_sc = NULL;
1018 return rc;
1019 }
1020
1021 dccp_pr_debug("Will confirm %d\n", *rpref);
1022
1023 /* say we want to change to X but we just got a confirm X, suppress our
1024 * change
1025 */
1026 if (!opt->dccpop_conf) {
1027 if (*opt->dccpop_val == *res)
1028 opt->dccpop_conf = 1;
1029 dccp_pr_debug("won't ask for change of same feature\n");
1030 }
1031
1032 return agree ? 0 : DCCP_FEAT_SP_NOAGREE; /* used for mandatory opts */
1033}
1034
1035static int dccp_feat_sp(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1036{
1037 struct dccp_minisock *dmsk = dccp_msk(sk);
1038 struct dccp_opt_pend *opt;
1039 int rc = 1;
1040 u8 t;
1041
1042 /*
1043 * We received a CHANGE. We gotta match it against our own preference
1044 * list. If we got a CHANGE_R it means it's a change for us, so we need
1045 * to compare our CHANGE_L list.
1046 */
1047 if (type == DCCPO_CHANGE_L)
1048 t = DCCPO_CHANGE_R;
1049 else
1050 t = DCCPO_CHANGE_L;
1051
1052 /* find our preference list for this feature */
1053 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
1054 if (opt->dccpop_type != t || opt->dccpop_feat != feature)
1055 continue;
1056
1057 /* find the winner from the two preference lists */
1058 rc = dccp_feat_reconcile(sk, opt, val, len);
1059 break;
1060 }
1061
1062 /* We didn't deal with the change. This can happen if we have no
1063 * preference list for the feature. In fact, it just shouldn't
1064 * happen---if we understand a feature, we should have a preference list
1065 * with at least the default value.
1066 */
1067 BUG_ON(rc == 1);
1068
1069 return rc;
1070}
1071
1072static int dccp_feat_nn(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1073{
1074 struct dccp_opt_pend *opt;
1075 struct dccp_minisock *dmsk = dccp_msk(sk);
1076 u8 *copy;
1077 int rc;
1078
1079 /* NN features must be Change L (sec. 6.3.2) */
1080 if (type != DCCPO_CHANGE_L) {
1081 dccp_pr_debug("received %s for NN feature %d\n",
1082 dccp_feat_typename(type), feature);
1083 return -EFAULT;
1084 }
1085
1086 /* XXX sanity check opt val */
1087
1088 /* copy option so we can confirm it */
1089 opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
1090 if (opt == NULL)
1091 return -ENOMEM;
1092
1093 copy = kmemdup(val, len, GFP_ATOMIC);
1094 if (copy == NULL) {
1095 kfree(opt);
1096 return -ENOMEM;
1097 }
1098
1099 opt->dccpop_type = DCCPO_CONFIRM_R; /* NN can only confirm R */
1100 opt->dccpop_feat = feature;
1101 opt->dccpop_val = copy;
1102 opt->dccpop_len = len;
1103
1104 /* change feature */
1105 rc = dccp_feat_update(sk, type, feature, *val);
1106 if (rc) {
1107 kfree(opt->dccpop_val);
1108 kfree(opt);
1109 return rc;
1110 }
1111
1112 dccp_feat_debug(type, feature, *copy);
1113
1114 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
1115
1116 return 0;
1117}
1118
1119static void dccp_feat_empty_confirm(struct dccp_minisock *dmsk,
1120 u8 type, u8 feature)
1121{
1122 /* XXX check if other confirms for that are queued and recycle slot */
1123 struct dccp_opt_pend *opt = kzalloc(sizeof(*opt), GFP_ATOMIC);
1124
1125 if (opt == NULL) {
1126 /* XXX what do we do? Ignoring should be fine. It's a change
1127 * after all =P
1128 */
1129 return;
1130 }
1131
1132 switch (type) {
1133 case DCCPO_CHANGE_L:
1134 opt->dccpop_type = DCCPO_CONFIRM_R;
1135 break;
1136 case DCCPO_CHANGE_R:
1137 opt->dccpop_type = DCCPO_CONFIRM_L;
1138 break;
1139 default:
1140 DCCP_WARN("invalid type %d\n", type);
1141 kfree(opt);
1142 return;
1143 }
1144 opt->dccpop_feat = feature;
1145 opt->dccpop_val = NULL;
1146 opt->dccpop_len = 0;
1147
1148 /* change feature */
1149 dccp_pr_debug("Empty %s(%d)\n", dccp_feat_typename(type), feature);
1150
1151 list_add_tail(&opt->dccpop_node, &dmsk->dccpms_conf);
1152}
1153
1154static void dccp_feat_flush_confirm(struct sock *sk)
1155{
1156 struct dccp_minisock *dmsk = dccp_msk(sk);
1157 /* Check if there is anything to confirm in the first place */
1158 int yes = !list_empty(&dmsk->dccpms_conf);
1159
1160 if (!yes) {
1161 struct dccp_opt_pend *opt;
1162
1163 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
1164 if (opt->dccpop_conf) {
1165 yes = 1;
1166 break;
1167 }
1168 }
1169 }
1170
1171 if (!yes)
1172 return;
1173
1174 /* OK there is something to confirm... */
1175 /* XXX check if packet is in flight? Send delayed ack?? */
1176 if (sk->sk_state == DCCP_OPEN)
1177 dccp_send_ack(sk);
1178}
1179
1180int dccp_feat_change_recv(struct sock *sk, u8 type, u8 feature, u8 *val, u8 len)
1181{
1182 int rc;
1183
1184 /* Ignore Change requests other than during connection setup */
1185 if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
1186 return 0;
1187 dccp_feat_debug(type, feature, *val);
1188
1189 /* figure out if it's SP or NN feature */
1190 switch (feature) {
1191 /* deal with SP features */
1192 case DCCPF_CCID:
1193 /* XXX Obsoleted by next patch
1194 rc = dccp_feat_sp(sk, type, feature, val, len); */
1195 break;
1196
1197 /* deal with NN features */
1198 case DCCPF_ACK_RATIO:
1199 /* XXX Obsoleted by next patch
1200 rc = dccp_feat_nn(sk, type, feature, val, len); */
1201 break;
1202
1203 /* XXX implement other features */
1204 default:
1205 dccp_pr_debug("UNIMPLEMENTED: not handling %s(%d, ...)\n",
1206 dccp_feat_typename(type), feature);
1207 rc = -EFAULT;
1208 break;
1209 }
1210
1211 /* check if there were problems changing features */
1212 if (rc) {
1213 /* If we don't agree on SP, we sent a confirm for old value.
1214 * However we propagate rc to caller in case option was
1215 * mandatory
1216 */
1217 if (rc != DCCP_FEAT_SP_NOAGREE)
1218 dccp_feat_empty_confirm(dccp_msk(sk), type, feature);
1219 }
1220
1221 /* generate the confirm [if required] */
1222 dccp_feat_flush_confirm(sk);
1223
1224 return rc;
1225}
1226
1227EXPORT_SYMBOL_GPL(dccp_feat_change_recv);
1228
1229int dccp_feat_confirm_recv(struct sock *sk, u8 type, u8 feature,
1230 u8 *val, u8 len)
1231{
1232 u8 t;
1233 struct dccp_opt_pend *opt;
1234 struct dccp_minisock *dmsk = dccp_msk(sk);
1235 int found = 0;
1236 int all_confirmed = 1;
1237
1238 /* Ignore Confirm options other than during connection setup */
1239 if (sk->sk_state != DCCP_LISTEN && sk->sk_state != DCCP_REQUESTING)
1240 return 0;
1241 dccp_feat_debug(type, feature, *val);
1242
1243 /* locate our change request */
1244 switch (type) {
1245 case DCCPO_CONFIRM_L: t = DCCPO_CHANGE_R; break;
1246 case DCCPO_CONFIRM_R: t = DCCPO_CHANGE_L; break;
1247 default: DCCP_WARN("invalid type %d\n", type);
1248 return 1;
1249
1250 }
1251 /* XXX sanity check feature value */
1252
1253 list_for_each_entry(opt, &dmsk->dccpms_pending, dccpop_node) {
1254 if (!opt->dccpop_conf && opt->dccpop_type == t &&
1255 opt->dccpop_feat == feature) {
1256 found = 1;
1257 dccp_pr_debug("feature %d found\n", opt->dccpop_feat);
1258
1259 /* XXX do sanity check */
1260
1261 opt->dccpop_conf = 1;
1262
1263 /* We got a confirmation---change the option */
1264 dccp_feat_update(sk, opt->dccpop_type,
1265 opt->dccpop_feat, *val);
1266
1267 /* XXX check the return value of dccp_feat_update */
1268 break;
1269 }
1270
1271 if (!opt->dccpop_conf)
1272 all_confirmed = 0;
1273 }
1274
1275 if (!found)
1276 dccp_pr_debug("%s(%d, ...) never requested\n",
1277 dccp_feat_typename(type), feature);
1278 return 0;
1279}
1280
1281EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv);
1282#endif /* (later) */
1283
1284void dccp_feat_clean(struct dccp_minisock *dmsk)
1285{
1286 struct dccp_opt_pend *opt, *next;
1287
1288 list_for_each_entry_safe(opt, next, &dmsk->dccpms_pending,
1289 dccpop_node) {
1290 BUG_ON(opt->dccpop_val == NULL);
1291 kfree(opt->dccpop_val);
1292
1293 if (opt->dccpop_sc != NULL) {
1294 BUG_ON(opt->dccpop_sc->dccpoc_val == NULL);
1295 kfree(opt->dccpop_sc->dccpoc_val);
1296 kfree(opt->dccpop_sc);
1297 }
1298
1299 kfree(opt);
1300 }
1301 INIT_LIST_HEAD(&dmsk->dccpms_pending);
1302
1303 list_for_each_entry_safe(opt, next, &dmsk->dccpms_conf, dccpop_node) {
1304 BUG_ON(opt == NULL);
1305 if (opt->dccpop_val != NULL)
1306 kfree(opt->dccpop_val);
1307 kfree(opt);
1308 }
1309 INIT_LIST_HEAD(&dmsk->dccpms_conf);
1310}
1311
1312EXPORT_SYMBOL_GPL(dccp_feat_clean);
1313
1314/* this is to be called only when a listening sock creates its child. It is
1315 * assumed by the function---the confirm is not duplicated, but rather it is
1316 * "passed on".
1317 */
1318int dccp_feat_clone(struct sock *oldsk, struct sock *newsk)
1319{
1320 struct dccp_minisock *olddmsk = dccp_msk(oldsk);
1321 struct dccp_minisock *newdmsk = dccp_msk(newsk);
1322 struct dccp_opt_pend *opt;
1323 int rc = 0;
1324
1325 INIT_LIST_HEAD(&newdmsk->dccpms_pending);
1326 INIT_LIST_HEAD(&newdmsk->dccpms_conf);
1327
1328 list_for_each_entry(opt, &olddmsk->dccpms_pending, dccpop_node) {
1329 struct dccp_opt_pend *newopt;
1330 /* copy the value of the option */
1331 u8 *val = kmemdup(opt->dccpop_val, opt->dccpop_len, GFP_ATOMIC);
1332
1333 if (val == NULL)
1334 goto out_clean;
1335
1336 newopt = kmemdup(opt, sizeof(*newopt), GFP_ATOMIC);
1337 if (newopt == NULL) {
1338 kfree(val);
1339 goto out_clean;
1340 }
1341
1342 /* insert the option */
1343 newopt->dccpop_val = val;
1344 list_add_tail(&newopt->dccpop_node, &newdmsk->dccpms_pending);
1345
1346 /* XXX what happens with backlogs and multiple connections at
1347 * once...
1348 */
1349 /* the master socket no longer needs to worry about confirms */
1350 opt->dccpop_sc = NULL; /* it's not a memleak---new socket has it */
1351
1352 /* reset state for a new socket */
1353 opt->dccpop_conf = 0;
1354 }
1355
1356 /* XXX not doing anything about the conf queue */
1357
1358out:
1359 return rc;
1360
1361out_clean:
1362 dccp_feat_clean(newdmsk);
1363 rc = -ENOMEM;
1364 goto out;
1365}
1366
1367EXPORT_SYMBOL_GPL(dccp_feat_clone);
1368
1369/** 878/**
1370 * dccp_feat_change_recv - Process incoming ChangeL/R options 879 * dccp_feat_change_recv - Process incoming ChangeL/R options
1371 * @fn: feature-negotiation list to update 880 * @fn: feature-negotiation list to update
diff --git a/net/dccp/feat.h b/net/dccp/feat.h
index 618bed935b33..177e9c39ea9f 100644
--- a/net/dccp/feat.h
+++ b/net/dccp/feat.h
@@ -3,14 +3,14 @@
3/* 3/*
4 * net/dccp/feat.h 4 * net/dccp/feat.h
5 * 5 *
6 * An implementation of the DCCP protocol 6 * Feature negotiation for the DCCP protocol (RFC 4340, section 6)
7 * Copyright (c) 2008 Gerrit Renker <gerrit@erg.abdn.ac.uk>
7 * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk> 8 * Copyright (c) 2005 Andrea Bittau <a.bittau@cs.ucl.ac.uk>
8 * 9 *
9 * This program is free software; you can redistribute it and/or modify it 10 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public License version 2 as 11 * under the terms of the GNU General Public License version 2 as
11 * published by the Free Software Foundation. 12 * published by the Free Software Foundation.
12 */ 13 */
13
14#include <linux/types.h> 14#include <linux/types.h>
15#include "dccp.h" 15#include "dccp.h"
16 16
@@ -117,8 +117,6 @@ extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); 117extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
118extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, 118extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
119 u8 mand, u8 opt, u8 feat, u8 *val, u8 len); 119 u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
120extern void dccp_feat_clean(struct dccp_minisock *dmsk);
121extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk);
122extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); 120extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
123extern int dccp_feat_init(struct sock *sk); 121extern int dccp_feat_init(struct sock *sk);
124 122