aboutsummaryrefslogtreecommitdiffstats
path: root/net/xfrm/xfrm_policy.c
diff options
context:
space:
mode:
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
-rw-r--r--net/xfrm/xfrm_policy.c141
1 files changed, 117 insertions, 24 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index b469c8b5461..b8936926c24 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)