aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm')
-rw-r--r--net/xfrm/xfrm_policy.c141
-rw-r--r--net/xfrm/xfrm_state.c15
-rw-r--r--net/xfrm/xfrm_user.c19
3 files changed, 138 insertions, 37 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b469c8b54613..b8936926c24b 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -46,45 +46,43 @@ static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
46 46
47static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); 47static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
48static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); 48static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
49static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
50static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
49 51
50int xfrm_register_type(struct xfrm_type *type, unsigned short family) 52int xfrm_register_type(struct xfrm_type *type, unsigned short family)
51{ 53{
52 struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); 54 struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
53 struct xfrm_type_map *typemap; 55 struct xfrm_type **typemap;
54 int err = 0; 56 int err = 0;
55 57
56 if (unlikely(afinfo == NULL)) 58 if (unlikely(afinfo == NULL))
57 return -EAFNOSUPPORT; 59 return -EAFNOSUPPORT;
58 typemap = afinfo->type_map; 60 typemap = afinfo->type_map;
59 61
60 write_lock_bh(&typemap->lock); 62 if (likely(typemap[type->proto] == NULL))
61 if (likely(typemap->map[type->proto] == NULL)) 63 typemap[type->proto] = type;
62 typemap->map[type->proto] = type;
63 else 64 else
64 err = -EEXIST; 65 err = -EEXIST;
65 write_unlock_bh(&typemap->lock); 66 xfrm_policy_unlock_afinfo(afinfo);
66 xfrm_policy_put_afinfo(afinfo);
67 return err; 67 return err;
68} 68}
69EXPORT_SYMBOL(xfrm_register_type); 69EXPORT_SYMBOL(xfrm_register_type);
70 70
71int xfrm_unregister_type(struct xfrm_type *type, unsigned short family) 71int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
72{ 72{
73 struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family); 73 struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
74 struct xfrm_type_map *typemap; 74 struct xfrm_type **typemap;
75 int err = 0; 75 int err = 0;
76 76
77 if (unlikely(afinfo == NULL)) 77 if (unlikely(afinfo == NULL))
78 return -EAFNOSUPPORT; 78 return -EAFNOSUPPORT;
79 typemap = afinfo->type_map; 79 typemap = afinfo->type_map;
80 80
81 write_lock_bh(&typemap->lock); 81 if (unlikely(typemap[type->proto] != type))
82 if (unlikely(typemap->map[type->proto] != type))
83 err = -ENOENT; 82 err = -ENOENT;
84 else 83 else
85 typemap->map[type->proto] = NULL; 84 typemap[type->proto] = NULL;
86 write_unlock_bh(&typemap->lock); 85 xfrm_policy_unlock_afinfo(afinfo);
87 xfrm_policy_put_afinfo(afinfo);
88 return err; 86 return err;
89} 87}
90EXPORT_SYMBOL(xfrm_unregister_type); 88EXPORT_SYMBOL(xfrm_unregister_type);
@@ -92,7 +90,7 @@ EXPORT_SYMBOL(xfrm_unregister_type);
92struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family) 90struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
93{ 91{
94 struct xfrm_policy_afinfo *afinfo; 92 struct xfrm_policy_afinfo *afinfo;
95 struct xfrm_type_map *typemap; 93 struct xfrm_type **typemap;
96 struct xfrm_type *type; 94 struct xfrm_type *type;
97 int modload_attempted = 0; 95 int modload_attempted = 0;
98 96
@@ -102,11 +100,9 @@ retry:
102 return NULL; 100 return NULL;
103 typemap = afinfo->type_map; 101 typemap = afinfo->type_map;
104 102
105 read_lock(&typemap->lock); 103 type = typemap[proto];
106 type = typemap->map[proto];
107 if (unlikely(type && !try_module_get(type->owner))) 104 if (unlikely(type && !try_module_get(type->owner)))
108 type = NULL; 105 type = NULL;
109 read_unlock(&typemap->lock);
110 if (!type && !modload_attempted) { 106 if (!type && !modload_attempted) {
111 xfrm_policy_put_afinfo(afinfo); 107 xfrm_policy_put_afinfo(afinfo);
112 request_module("xfrm-type-%d-%d", 108 request_module("xfrm-type-%d-%d",
@@ -142,6 +138,89 @@ void xfrm_put_type(struct xfrm_type *type)
142 module_put(type->owner); 138 module_put(type->owner);
143} 139}
144 140
141int xfrm_register_mode(struct xfrm_mode *mode, int family)
142{
143 struct xfrm_policy_afinfo *afinfo;
144 struct xfrm_mode **modemap;
145 int err;
146
147 if (unlikely(mode->encap >= XFRM_MODE_MAX))
148 return -EINVAL;
149
150 afinfo = xfrm_policy_lock_afinfo(family);
151 if (unlikely(afinfo == NULL))
152 return -EAFNOSUPPORT;
153
154 err = -EEXIST;
155 modemap = afinfo->mode_map;
156 if (likely(modemap[mode->encap] == NULL)) {
157 modemap[mode->encap] = mode;
158 err = 0;
159 }
160
161 xfrm_policy_unlock_afinfo(afinfo);
162 return err;
163}
164EXPORT_SYMBOL(xfrm_register_mode);
165
166int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
167{
168 struct xfrm_policy_afinfo *afinfo;
169 struct xfrm_mode **modemap;
170 int err;
171
172 if (unlikely(mode->encap >= XFRM_MODE_MAX))
173 return -EINVAL;
174
175 afinfo = xfrm_policy_lock_afinfo(family);
176 if (unlikely(afinfo == NULL))
177 return -EAFNOSUPPORT;
178
179 err = -ENOENT;
180 modemap = afinfo->mode_map;
181 if (likely(modemap[mode->encap] == mode)) {
182 modemap[mode->encap] = NULL;
183 err = 0;
184 }
185
186 xfrm_policy_unlock_afinfo(afinfo);
187 return err;
188}
189EXPORT_SYMBOL(xfrm_unregister_mode);
190
191struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
192{
193 struct xfrm_policy_afinfo *afinfo;
194 struct xfrm_mode *mode;
195 int modload_attempted = 0;
196
197 if (unlikely(encap >= XFRM_MODE_MAX))
198 return NULL;
199
200retry:
201 afinfo = xfrm_policy_get_afinfo(family);
202 if (unlikely(afinfo == NULL))
203 return NULL;
204
205 mode = afinfo->mode_map[encap];
206 if (unlikely(mode && !try_module_get(mode->owner)))
207 mode = NULL;
208 if (!mode && !modload_attempted) {
209 xfrm_policy_put_afinfo(afinfo);
210 request_module("xfrm-mode-%d-%d", family, encap);
211 modload_attempted = 1;
212 goto retry;
213 }
214
215 xfrm_policy_put_afinfo(afinfo);
216 return mode;
217}
218
219void xfrm_put_mode(struct xfrm_mode *mode)
220{
221 module_put(mode->owner);
222}
223
145static inline unsigned long make_jiffies(long secs) 224static inline unsigned long make_jiffies(long secs)
146{ 225{
147 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) 226 if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
@@ -1306,17 +1385,31 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
1306 return NULL; 1385 return NULL;
1307 read_lock(&xfrm_policy_afinfo_lock); 1386 read_lock(&xfrm_policy_afinfo_lock);
1308 afinfo = xfrm_policy_afinfo[family]; 1387 afinfo = xfrm_policy_afinfo[family];
1309 if (likely(afinfo != NULL)) 1388 if (unlikely(!afinfo))
1310 read_lock(&afinfo->lock); 1389 read_unlock(&xfrm_policy_afinfo_lock);
1311 read_unlock(&xfrm_policy_afinfo_lock);
1312 return afinfo; 1390 return afinfo;
1313} 1391}
1314 1392
1315static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo) 1393static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
1316{ 1394{
1317 if (unlikely(afinfo == NULL)) 1395 read_unlock(&xfrm_policy_afinfo_lock);
1318 return; 1396}
1319 read_unlock(&afinfo->lock); 1397
1398static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family)
1399{
1400 struct xfrm_policy_afinfo *afinfo;
1401 if (unlikely(family >= NPROTO))
1402 return NULL;
1403 write_lock_bh(&xfrm_policy_afinfo_lock);
1404 afinfo = xfrm_policy_afinfo[family];
1405 if (unlikely(!afinfo))
1406 write_unlock_bh(&xfrm_policy_afinfo_lock);
1407 return afinfo;
1408}
1409
1410static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
1411{
1412 write_unlock_bh(&xfrm_policy_afinfo_lock);
1320} 1413}
1321 1414
1322static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr) 1415static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index 93a2f36ad3db..17b29ec3c417 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -77,6 +77,8 @@ static void xfrm_state_gc_destroy(struct xfrm_state *x)
77 kfree(x->ealg); 77 kfree(x->ealg);
78 kfree(x->calg); 78 kfree(x->calg);
79 kfree(x->encap); 79 kfree(x->encap);
80 if (x->mode)
81 xfrm_put_mode(x->mode);
80 if (x->type) { 82 if (x->type) {
81 x->type->destructor(x); 83 x->type->destructor(x);
82 xfrm_put_type(x->type); 84 xfrm_put_type(x->type);
@@ -1103,17 +1105,14 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family)
1103 return NULL; 1105 return NULL;
1104 read_lock(&xfrm_state_afinfo_lock); 1106 read_lock(&xfrm_state_afinfo_lock);
1105 afinfo = xfrm_state_afinfo[family]; 1107 afinfo = xfrm_state_afinfo[family];
1106 if (likely(afinfo != NULL)) 1108 if (unlikely(!afinfo))
1107 read_lock(&afinfo->lock); 1109 read_unlock(&xfrm_state_afinfo_lock);
1108 read_unlock(&xfrm_state_afinfo_lock);
1109 return afinfo; 1110 return afinfo;
1110} 1111}
1111 1112
1112static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) 1113static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo)
1113{ 1114{
1114 if (unlikely(afinfo == NULL)) 1115 read_unlock(&xfrm_state_afinfo_lock);
1115 return;
1116 read_unlock(&afinfo->lock);
1117} 1116}
1118 1117
1119/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ 1118/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */
@@ -1196,6 +1195,10 @@ int xfrm_init_state(struct xfrm_state *x)
1196 if (err) 1195 if (err)
1197 goto error; 1196 goto error;
1198 1197
1198 x->mode = xfrm_get_mode(x->props.mode, family);
1199 if (x->mode == NULL)
1200 goto error;
1201
1199 x->km.state = XFRM_STATE_VALID; 1202 x->km.state = XFRM_STATE_VALID;
1200 1203
1201error: 1204error:
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c
index 81d1005830f4..c21dc26141ea 100644
--- a/net/xfrm/xfrm_user.c
+++ b/net/xfrm/xfrm_user.c
@@ -427,23 +427,25 @@ static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfrma)
427 if (x == NULL) 427 if (x == NULL)
428 return -ESRCH; 428 return -ESRCH;
429 429
430 if ((err = security_xfrm_state_delete(x)) != 0)
431 goto out;
432
430 if (xfrm_state_kern(x)) { 433 if (xfrm_state_kern(x)) {
431 xfrm_state_put(x); 434 err = -EPERM;
432 return -EPERM; 435 goto out;
433 } 436 }
434 437
435 err = xfrm_state_delete(x); 438 err = xfrm_state_delete(x);
436 if (err < 0) { 439 if (err < 0)
437 xfrm_state_put(x); 440 goto out;
438 return err;
439 }
440 441
441 c.seq = nlh->nlmsg_seq; 442 c.seq = nlh->nlmsg_seq;
442 c.pid = nlh->nlmsg_pid; 443 c.pid = nlh->nlmsg_pid;
443 c.event = nlh->nlmsg_type; 444 c.event = nlh->nlmsg_type;
444 km_state_notify(x, &c); 445 km_state_notify(x, &c);
445 xfrm_state_put(x);
446 446
447out:
448 xfrm_state_put(x);
447 return err; 449 return err;
448} 450}
449 451
@@ -1055,6 +1057,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
1055 MSG_DONTWAIT); 1057 MSG_DONTWAIT);
1056 } 1058 }
1057 } else { 1059 } else {
1060 if ((err = security_xfrm_policy_delete(xp)) != 0)
1061 goto out;
1058 c.data.byid = p->index; 1062 c.data.byid = p->index;
1059 c.event = nlh->nlmsg_type; 1063 c.event = nlh->nlmsg_type;
1060 c.seq = nlh->nlmsg_seq; 1064 c.seq = nlh->nlmsg_seq;
@@ -1064,6 +1068,7 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, void **xfr
1064 1068
1065 xfrm_pol_put(xp); 1069 xfrm_pol_put(xp);
1066 1070
1071out:
1067 return err; 1072 return err;
1068} 1073}
1069 1074