diff options
author | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:30:19 -0400 |
---|---|---|
committer | Gerrit Renker <gerrit@erg.abdn.ac.uk> | 2008-09-04 01:45:30 -0400 |
commit | 23479cbfd30402c7d9fa413cc467983061073557 (patch) | |
tree | b2b9e3fa10acdaf177424172d4ea4d86f7b00edd | |
parent | c49b22729f3da7479c4e6c572d53fdd40201d0bd (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>
-rw-r--r-- | net/dccp/feat.c | 505 | ||||
-rw-r--r-- | net/dccp/feat.h | 12 |
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 | ||
808 | static 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 | |||
838 | static 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) */ |
854 | static int dccp_feat_preflist_match(u8 *servlist, u8 slen, u8 *clilist, u8 clen) | 810 | static 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 | ||
923 | static 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 | |||
1035 | static 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 | |||
1072 | static 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 | |||
1119 | static 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 | |||
1154 | static 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 | |||
1180 | int 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 | |||
1227 | EXPORT_SYMBOL_GPL(dccp_feat_change_recv); | ||
1228 | |||
1229 | int 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 | |||
1281 | EXPORT_SYMBOL_GPL(dccp_feat_confirm_recv); | ||
1282 | #endif /* (later) */ | ||
1283 | |||
1284 | void 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 | |||
1312 | EXPORT_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 | */ | ||
1318 | int 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 | |||
1358 | out: | ||
1359 | return rc; | ||
1360 | |||
1361 | out_clean: | ||
1362 | dccp_feat_clean(newdmsk); | ||
1363 | rc = -ENOMEM; | ||
1364 | goto out; | ||
1365 | } | ||
1366 | |||
1367 | EXPORT_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, | |||
117 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); | 117 | extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val); |
118 | extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *, | 118 | extern 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); |
120 | extern void dccp_feat_clean(struct dccp_minisock *dmsk); | ||
121 | extern int dccp_feat_clone(struct sock *oldsk, struct sock *newsk); | ||
122 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); | 120 | extern int dccp_feat_clone_list(struct list_head const *, struct list_head *); |
123 | extern int dccp_feat_init(struct sock *sk); | 121 | extern int dccp_feat_init(struct sock *sk); |
124 | 122 | ||