diff options
Diffstat (limited to 'net/xfrm/xfrm_state.c')
-rw-r--r-- | net/xfrm/xfrm_state.c | 165 |
1 files changed, 78 insertions, 87 deletions
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c index 3459692092ec..ae01bdbcb294 100644 --- a/net/xfrm/xfrm_state.c +++ b/net/xfrm/xfrm_state.c | |||
@@ -158,8 +158,8 @@ out_unlock: | |||
158 | mutex_unlock(&hash_resize_mutex); | 158 | mutex_unlock(&hash_resize_mutex); |
159 | } | 159 | } |
160 | 160 | ||
161 | static DEFINE_RWLOCK(xfrm_state_afinfo_lock); | 161 | static DEFINE_SPINLOCK(xfrm_state_afinfo_lock); |
162 | static struct xfrm_state_afinfo *xfrm_state_afinfo[NPROTO]; | 162 | static struct xfrm_state_afinfo __rcu *xfrm_state_afinfo[NPROTO]; |
163 | 163 | ||
164 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); | 164 | static DEFINE_SPINLOCK(xfrm_state_gc_lock); |
165 | 165 | ||
@@ -168,58 +168,45 @@ int __xfrm_state_delete(struct xfrm_state *x); | |||
168 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); | 168 | int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); |
169 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); | 169 | void km_state_expired(struct xfrm_state *x, int hard, u32 portid); |
170 | 170 | ||
171 | static struct xfrm_state_afinfo *xfrm_state_lock_afinfo(unsigned int family) | 171 | static DEFINE_SPINLOCK(xfrm_type_lock); |
172 | { | ||
173 | struct xfrm_state_afinfo *afinfo; | ||
174 | if (unlikely(family >= NPROTO)) | ||
175 | return NULL; | ||
176 | write_lock_bh(&xfrm_state_afinfo_lock); | ||
177 | afinfo = xfrm_state_afinfo[family]; | ||
178 | if (unlikely(!afinfo)) | ||
179 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
180 | return afinfo; | ||
181 | } | ||
182 | |||
183 | static void xfrm_state_unlock_afinfo(struct xfrm_state_afinfo *afinfo) | ||
184 | __releases(xfrm_state_afinfo_lock) | ||
185 | { | ||
186 | write_unlock_bh(&xfrm_state_afinfo_lock); | ||
187 | } | ||
188 | |||
189 | int xfrm_register_type(const struct xfrm_type *type, unsigned short family) | 172 | int xfrm_register_type(const struct xfrm_type *type, unsigned short family) |
190 | { | 173 | { |
191 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | 174 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
192 | const struct xfrm_type **typemap; | 175 | const struct xfrm_type **typemap; |
193 | int err = 0; | 176 | int err = 0; |
194 | 177 | ||
195 | if (unlikely(afinfo == NULL)) | 178 | if (unlikely(afinfo == NULL)) |
196 | return -EAFNOSUPPORT; | 179 | return -EAFNOSUPPORT; |
197 | typemap = afinfo->type_map; | 180 | typemap = afinfo->type_map; |
181 | spin_lock_bh(&xfrm_type_lock); | ||
198 | 182 | ||
199 | if (likely(typemap[type->proto] == NULL)) | 183 | if (likely(typemap[type->proto] == NULL)) |
200 | typemap[type->proto] = type; | 184 | typemap[type->proto] = type; |
201 | else | 185 | else |
202 | err = -EEXIST; | 186 | err = -EEXIST; |
203 | xfrm_state_unlock_afinfo(afinfo); | 187 | spin_unlock_bh(&xfrm_type_lock); |
188 | xfrm_state_put_afinfo(afinfo); | ||
204 | return err; | 189 | return err; |
205 | } | 190 | } |
206 | EXPORT_SYMBOL(xfrm_register_type); | 191 | EXPORT_SYMBOL(xfrm_register_type); |
207 | 192 | ||
208 | int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) | 193 | int xfrm_unregister_type(const struct xfrm_type *type, unsigned short family) |
209 | { | 194 | { |
210 | struct xfrm_state_afinfo *afinfo = xfrm_state_lock_afinfo(family); | 195 | struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); |
211 | const struct xfrm_type **typemap; | 196 | const struct xfrm_type **typemap; |
212 | int err = 0; | 197 | int err = 0; |
213 | 198 | ||
214 | if (unlikely(afinfo == NULL)) | 199 | if (unlikely(afinfo == NULL)) |
215 | return -EAFNOSUPPORT; | 200 | return -EAFNOSUPPORT; |
216 | typemap = afinfo->type_map; | 201 | typemap = afinfo->type_map; |
202 | spin_lock_bh(&xfrm_type_lock); | ||
217 | 203 | ||
218 | if (unlikely(typemap[type->proto] != type)) | 204 | if (unlikely(typemap[type->proto] != type)) |
219 | err = -ENOENT; | 205 | err = -ENOENT; |
220 | else | 206 | else |
221 | typemap[type->proto] = NULL; | 207 | typemap[type->proto] = NULL; |
222 | xfrm_state_unlock_afinfo(afinfo); | 208 | spin_unlock_bh(&xfrm_type_lock); |
209 | xfrm_state_put_afinfo(afinfo); | ||
223 | return err; | 210 | return err; |
224 | } | 211 | } |
225 | EXPORT_SYMBOL(xfrm_unregister_type); | 212 | EXPORT_SYMBOL(xfrm_unregister_type); |
@@ -256,6 +243,7 @@ static void xfrm_put_type(const struct xfrm_type *type) | |||
256 | module_put(type->owner); | 243 | module_put(type->owner); |
257 | } | 244 | } |
258 | 245 | ||
246 | static DEFINE_SPINLOCK(xfrm_mode_lock); | ||
259 | int xfrm_register_mode(struct xfrm_mode *mode, int family) | 247 | int xfrm_register_mode(struct xfrm_mode *mode, int family) |
260 | { | 248 | { |
261 | struct xfrm_state_afinfo *afinfo; | 249 | struct xfrm_state_afinfo *afinfo; |
@@ -265,12 +253,13 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family) | |||
265 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 253 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) |
266 | return -EINVAL; | 254 | return -EINVAL; |
267 | 255 | ||
268 | afinfo = xfrm_state_lock_afinfo(family); | 256 | afinfo = xfrm_state_get_afinfo(family); |
269 | if (unlikely(afinfo == NULL)) | 257 | if (unlikely(afinfo == NULL)) |
270 | return -EAFNOSUPPORT; | 258 | return -EAFNOSUPPORT; |
271 | 259 | ||
272 | err = -EEXIST; | 260 | err = -EEXIST; |
273 | modemap = afinfo->mode_map; | 261 | modemap = afinfo->mode_map; |
262 | spin_lock_bh(&xfrm_mode_lock); | ||
274 | if (modemap[mode->encap]) | 263 | if (modemap[mode->encap]) |
275 | goto out; | 264 | goto out; |
276 | 265 | ||
@@ -283,7 +272,8 @@ int xfrm_register_mode(struct xfrm_mode *mode, int family) | |||
283 | err = 0; | 272 | err = 0; |
284 | 273 | ||
285 | out: | 274 | out: |
286 | xfrm_state_unlock_afinfo(afinfo); | 275 | spin_unlock_bh(&xfrm_mode_lock); |
276 | xfrm_state_put_afinfo(afinfo); | ||
287 | return err; | 277 | return err; |
288 | } | 278 | } |
289 | EXPORT_SYMBOL(xfrm_register_mode); | 279 | EXPORT_SYMBOL(xfrm_register_mode); |
@@ -297,19 +287,21 @@ int xfrm_unregister_mode(struct xfrm_mode *mode, int family) | |||
297 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) | 287 | if (unlikely(mode->encap >= XFRM_MODE_MAX)) |
298 | return -EINVAL; | 288 | return -EINVAL; |
299 | 289 | ||
300 | afinfo = xfrm_state_lock_afinfo(family); | 290 | afinfo = xfrm_state_get_afinfo(family); |
301 | if (unlikely(afinfo == NULL)) | 291 | if (unlikely(afinfo == NULL)) |
302 | return -EAFNOSUPPORT; | 292 | return -EAFNOSUPPORT; |
303 | 293 | ||
304 | err = -ENOENT; | 294 | err = -ENOENT; |
305 | modemap = afinfo->mode_map; | 295 | modemap = afinfo->mode_map; |
296 | spin_lock_bh(&xfrm_mode_lock); | ||
306 | if (likely(modemap[mode->encap] == mode)) { | 297 | if (likely(modemap[mode->encap] == mode)) { |
307 | modemap[mode->encap] = NULL; | 298 | modemap[mode->encap] = NULL; |
308 | module_put(mode->afinfo->owner); | 299 | module_put(mode->afinfo->owner); |
309 | err = 0; | 300 | err = 0; |
310 | } | 301 | } |
311 | 302 | ||
312 | xfrm_state_unlock_afinfo(afinfo); | 303 | spin_unlock_bh(&xfrm_mode_lock); |
304 | xfrm_state_put_afinfo(afinfo); | ||
313 | return err; | 305 | return err; |
314 | } | 306 | } |
315 | EXPORT_SYMBOL(xfrm_unregister_mode); | 307 | EXPORT_SYMBOL(xfrm_unregister_mode); |
@@ -699,7 +691,7 @@ static struct xfrm_state *__xfrm_state_lookup(struct net *net, u32 mark, | |||
699 | if (x->props.family != family || | 691 | if (x->props.family != family || |
700 | x->id.spi != spi || | 692 | x->id.spi != spi || |
701 | x->id.proto != proto || | 693 | x->id.proto != proto || |
702 | xfrm_addr_cmp(&x->id.daddr, daddr, family)) | 694 | !xfrm_addr_equal(&x->id.daddr, daddr, family)) |
703 | continue; | 695 | continue; |
704 | 696 | ||
705 | if ((mark & x->mark.m) != x->mark.v) | 697 | if ((mark & x->mark.m) != x->mark.v) |
@@ -723,8 +715,8 @@ static struct xfrm_state *__xfrm_state_lookup_byaddr(struct net *net, u32 mark, | |||
723 | hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) { | 715 | hlist_for_each_entry(x, entry, net->xfrm.state_bysrc+h, bysrc) { |
724 | if (x->props.family != family || | 716 | if (x->props.family != family || |
725 | x->id.proto != proto || | 717 | x->id.proto != proto || |
726 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 718 | !xfrm_addr_equal(&x->id.daddr, daddr, family) || |
727 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 719 | !xfrm_addr_equal(&x->props.saddr, saddr, family)) |
728 | continue; | 720 | continue; |
729 | 721 | ||
730 | if ((mark & x->mark.m) != x->mark.v) | 722 | if ((mark & x->mark.m) != x->mark.v) |
@@ -989,8 +981,8 @@ static void __xfrm_state_bump_genids(struct xfrm_state *xnew) | |||
989 | if (x->props.family == family && | 981 | if (x->props.family == family && |
990 | x->props.reqid == reqid && | 982 | x->props.reqid == reqid && |
991 | (mark & x->mark.m) == x->mark.v && | 983 | (mark & x->mark.m) == x->mark.v && |
992 | !xfrm_addr_cmp(&x->id.daddr, &xnew->id.daddr, family) && | 984 | xfrm_addr_equal(&x->id.daddr, &xnew->id.daddr, family) && |
993 | !xfrm_addr_cmp(&x->props.saddr, &xnew->props.saddr, family)) | 985 | xfrm_addr_equal(&x->props.saddr, &xnew->props.saddr, family)) |
994 | x->genid++; | 986 | x->genid++; |
995 | } | 987 | } |
996 | } | 988 | } |
@@ -1024,8 +1016,8 @@ static struct xfrm_state *__find_acq_core(struct net *net, struct xfrm_mark *m, | |||
1024 | x->id.spi != 0 || | 1016 | x->id.spi != 0 || |
1025 | x->id.proto != proto || | 1017 | x->id.proto != proto || |
1026 | (mark & x->mark.m) != x->mark.v || | 1018 | (mark & x->mark.m) != x->mark.v || |
1027 | xfrm_addr_cmp(&x->id.daddr, daddr, family) || | 1019 | !xfrm_addr_equal(&x->id.daddr, daddr, family) || |
1028 | xfrm_addr_cmp(&x->props.saddr, saddr, family)) | 1020 | !xfrm_addr_equal(&x->props.saddr, saddr, family)) |
1029 | continue; | 1021 | continue; |
1030 | 1022 | ||
1031 | xfrm_state_hold(x); | 1023 | xfrm_state_hold(x); |
@@ -1108,7 +1100,7 @@ int xfrm_state_add(struct xfrm_state *x) | |||
1108 | if (use_spi && x->km.seq) { | 1100 | if (use_spi && x->km.seq) { |
1109 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); | 1101 | x1 = __xfrm_find_acq_byseq(net, mark, x->km.seq); |
1110 | if (x1 && ((x1->id.proto != x->id.proto) || | 1102 | if (x1 && ((x1->id.proto != x->id.proto) || |
1111 | xfrm_addr_cmp(&x1->id.daddr, &x->id.daddr, family))) { | 1103 | !xfrm_addr_equal(&x1->id.daddr, &x->id.daddr, family))) { |
1112 | to_put = x1; | 1104 | to_put = x1; |
1113 | x1 = NULL; | 1105 | x1 = NULL; |
1114 | } | 1106 | } |
@@ -1234,10 +1226,10 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | |||
1234 | continue; | 1226 | continue; |
1235 | if (m->reqid && x->props.reqid != m->reqid) | 1227 | if (m->reqid && x->props.reqid != m->reqid) |
1236 | continue; | 1228 | continue; |
1237 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | 1229 | if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, |
1238 | m->old_family) || | 1230 | m->old_family) || |
1239 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | 1231 | !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, |
1240 | m->old_family)) | 1232 | m->old_family)) |
1241 | continue; | 1233 | continue; |
1242 | xfrm_state_hold(x); | 1234 | xfrm_state_hold(x); |
1243 | return x; | 1235 | return x; |
@@ -1249,10 +1241,10 @@ struct xfrm_state * xfrm_migrate_state_find(struct xfrm_migrate *m) | |||
1249 | if (x->props.mode != m->mode || | 1241 | if (x->props.mode != m->mode || |
1250 | x->id.proto != m->proto) | 1242 | x->id.proto != m->proto) |
1251 | continue; | 1243 | continue; |
1252 | if (xfrm_addr_cmp(&x->id.daddr, &m->old_daddr, | 1244 | if (!xfrm_addr_equal(&x->id.daddr, &m->old_daddr, |
1253 | m->old_family) || | 1245 | m->old_family) || |
1254 | xfrm_addr_cmp(&x->props.saddr, &m->old_saddr, | 1246 | !xfrm_addr_equal(&x->props.saddr, &m->old_saddr, |
1255 | m->old_family)) | 1247 | m->old_family)) |
1256 | continue; | 1248 | continue; |
1257 | xfrm_state_hold(x); | 1249 | xfrm_state_hold(x); |
1258 | return x; | 1250 | return x; |
@@ -1277,7 +1269,7 @@ struct xfrm_state * xfrm_state_migrate(struct xfrm_state *x, | |||
1277 | memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); | 1269 | memcpy(&xc->props.saddr, &m->new_saddr, sizeof(xc->props.saddr)); |
1278 | 1270 | ||
1279 | /* add state */ | 1271 | /* add state */ |
1280 | if (!xfrm_addr_cmp(&x->id.daddr, &m->new_daddr, m->new_family)) { | 1272 | if (xfrm_addr_equal(&x->id.daddr, &m->new_daddr, m->new_family)) { |
1281 | /* a care is needed when the destination address of the | 1273 | /* a care is needed when the destination address of the |
1282 | state is to be updated as it is a part of triplet */ | 1274 | state is to be updated as it is a part of triplet */ |
1283 | xfrm_state_insert(xc); | 1275 | xfrm_state_insert(xc); |
@@ -1370,9 +1362,6 @@ int xfrm_state_check_expire(struct xfrm_state *x) | |||
1370 | if (!x->curlft.use_time) | 1362 | if (!x->curlft.use_time) |
1371 | x->curlft.use_time = get_seconds(); | 1363 | x->curlft.use_time = get_seconds(); |
1372 | 1364 | ||
1373 | if (x->km.state != XFRM_STATE_VALID) | ||
1374 | return -EINVAL; | ||
1375 | |||
1376 | if (x->curlft.bytes >= x->lft.hard_byte_limit || | 1365 | if (x->curlft.bytes >= x->lft.hard_byte_limit || |
1377 | x->curlft.packets >= x->lft.hard_packet_limit) { | 1366 | x->curlft.packets >= x->lft.hard_packet_limit) { |
1378 | x->km.state = XFRM_STATE_EXPIRED; | 1367 | x->km.state = XFRM_STATE_EXPIRED; |
@@ -1648,27 +1637,26 @@ static void xfrm_replay_timer_handler(unsigned long data) | |||
1648 | } | 1637 | } |
1649 | 1638 | ||
1650 | static LIST_HEAD(xfrm_km_list); | 1639 | static LIST_HEAD(xfrm_km_list); |
1651 | static DEFINE_RWLOCK(xfrm_km_lock); | ||
1652 | 1640 | ||
1653 | void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) | 1641 | void km_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) |
1654 | { | 1642 | { |
1655 | struct xfrm_mgr *km; | 1643 | struct xfrm_mgr *km; |
1656 | 1644 | ||
1657 | read_lock(&xfrm_km_lock); | 1645 | rcu_read_lock(); |
1658 | list_for_each_entry(km, &xfrm_km_list, list) | 1646 | list_for_each_entry_rcu(km, &xfrm_km_list, list) |
1659 | if (km->notify_policy) | 1647 | if (km->notify_policy) |
1660 | km->notify_policy(xp, dir, c); | 1648 | km->notify_policy(xp, dir, c); |
1661 | read_unlock(&xfrm_km_lock); | 1649 | rcu_read_unlock(); |
1662 | } | 1650 | } |
1663 | 1651 | ||
1664 | void km_state_notify(struct xfrm_state *x, const struct km_event *c) | 1652 | void km_state_notify(struct xfrm_state *x, const struct km_event *c) |
1665 | { | 1653 | { |
1666 | struct xfrm_mgr *km; | 1654 | struct xfrm_mgr *km; |
1667 | read_lock(&xfrm_km_lock); | 1655 | rcu_read_lock(); |
1668 | list_for_each_entry(km, &xfrm_km_list, list) | 1656 | list_for_each_entry_rcu(km, &xfrm_km_list, list) |
1669 | if (km->notify) | 1657 | if (km->notify) |
1670 | km->notify(x, c); | 1658 | km->notify(x, c); |
1671 | read_unlock(&xfrm_km_lock); | 1659 | rcu_read_unlock(); |
1672 | } | 1660 | } |
1673 | 1661 | ||
1674 | EXPORT_SYMBOL(km_policy_notify); | 1662 | EXPORT_SYMBOL(km_policy_notify); |
@@ -1698,13 +1686,13 @@ int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol) | |||
1698 | int err = -EINVAL, acqret; | 1686 | int err = -EINVAL, acqret; |
1699 | struct xfrm_mgr *km; | 1687 | struct xfrm_mgr *km; |
1700 | 1688 | ||
1701 | read_lock(&xfrm_km_lock); | 1689 | rcu_read_lock(); |
1702 | list_for_each_entry(km, &xfrm_km_list, list) { | 1690 | list_for_each_entry_rcu(km, &xfrm_km_list, list) { |
1703 | acqret = km->acquire(x, t, pol); | 1691 | acqret = km->acquire(x, t, pol); |
1704 | if (!acqret) | 1692 | if (!acqret) |
1705 | err = acqret; | 1693 | err = acqret; |
1706 | } | 1694 | } |
1707 | read_unlock(&xfrm_km_lock); | 1695 | rcu_read_unlock(); |
1708 | return err; | 1696 | return err; |
1709 | } | 1697 | } |
1710 | EXPORT_SYMBOL(km_query); | 1698 | EXPORT_SYMBOL(km_query); |
@@ -1714,14 +1702,14 @@ int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) | |||
1714 | int err = -EINVAL; | 1702 | int err = -EINVAL; |
1715 | struct xfrm_mgr *km; | 1703 | struct xfrm_mgr *km; |
1716 | 1704 | ||
1717 | read_lock(&xfrm_km_lock); | 1705 | rcu_read_lock(); |
1718 | list_for_each_entry(km, &xfrm_km_list, list) { | 1706 | list_for_each_entry_rcu(km, &xfrm_km_list, list) { |
1719 | if (km->new_mapping) | 1707 | if (km->new_mapping) |
1720 | err = km->new_mapping(x, ipaddr, sport); | 1708 | err = km->new_mapping(x, ipaddr, sport); |
1721 | if (!err) | 1709 | if (!err) |
1722 | break; | 1710 | break; |
1723 | } | 1711 | } |
1724 | read_unlock(&xfrm_km_lock); | 1712 | rcu_read_unlock(); |
1725 | return err; | 1713 | return err; |
1726 | } | 1714 | } |
1727 | EXPORT_SYMBOL(km_new_mapping); | 1715 | EXPORT_SYMBOL(km_new_mapping); |
@@ -1750,15 +1738,15 @@ int km_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, | |||
1750 | int ret; | 1738 | int ret; |
1751 | struct xfrm_mgr *km; | 1739 | struct xfrm_mgr *km; |
1752 | 1740 | ||
1753 | read_lock(&xfrm_km_lock); | 1741 | rcu_read_lock(); |
1754 | list_for_each_entry(km, &xfrm_km_list, list) { | 1742 | list_for_each_entry_rcu(km, &xfrm_km_list, list) { |
1755 | if (km->migrate) { | 1743 | if (km->migrate) { |
1756 | ret = km->migrate(sel, dir, type, m, num_migrate, k); | 1744 | ret = km->migrate(sel, dir, type, m, num_migrate, k); |
1757 | if (!ret) | 1745 | if (!ret) |
1758 | err = ret; | 1746 | err = ret; |
1759 | } | 1747 | } |
1760 | } | 1748 | } |
1761 | read_unlock(&xfrm_km_lock); | 1749 | rcu_read_unlock(); |
1762 | return err; | 1750 | return err; |
1763 | } | 1751 | } |
1764 | EXPORT_SYMBOL(km_migrate); | 1752 | EXPORT_SYMBOL(km_migrate); |
@@ -1770,15 +1758,15 @@ int km_report(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address | |||
1770 | int ret; | 1758 | int ret; |
1771 | struct xfrm_mgr *km; | 1759 | struct xfrm_mgr *km; |
1772 | 1760 | ||
1773 | read_lock(&xfrm_km_lock); | 1761 | rcu_read_lock(); |
1774 | list_for_each_entry(km, &xfrm_km_list, list) { | 1762 | list_for_each_entry_rcu(km, &xfrm_km_list, list) { |
1775 | if (km->report) { | 1763 | if (km->report) { |
1776 | ret = km->report(net, proto, sel, addr); | 1764 | ret = km->report(net, proto, sel, addr); |
1777 | if (!ret) | 1765 | if (!ret) |
1778 | err = ret; | 1766 | err = ret; |
1779 | } | 1767 | } |
1780 | } | 1768 | } |
1781 | read_unlock(&xfrm_km_lock); | 1769 | rcu_read_unlock(); |
1782 | return err; | 1770 | return err; |
1783 | } | 1771 | } |
1784 | EXPORT_SYMBOL(km_report); | 1772 | EXPORT_SYMBOL(km_report); |
@@ -1802,14 +1790,14 @@ int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen | |||
1802 | goto out; | 1790 | goto out; |
1803 | 1791 | ||
1804 | err = -EINVAL; | 1792 | err = -EINVAL; |
1805 | read_lock(&xfrm_km_lock); | 1793 | rcu_read_lock(); |
1806 | list_for_each_entry(km, &xfrm_km_list, list) { | 1794 | list_for_each_entry_rcu(km, &xfrm_km_list, list) { |
1807 | pol = km->compile_policy(sk, optname, data, | 1795 | pol = km->compile_policy(sk, optname, data, |
1808 | optlen, &err); | 1796 | optlen, &err); |
1809 | if (err >= 0) | 1797 | if (err >= 0) |
1810 | break; | 1798 | break; |
1811 | } | 1799 | } |
1812 | read_unlock(&xfrm_km_lock); | 1800 | rcu_read_unlock(); |
1813 | 1801 | ||
1814 | if (err >= 0) { | 1802 | if (err >= 0) { |
1815 | xfrm_sk_policy_insert(sk, err, pol); | 1803 | xfrm_sk_policy_insert(sk, err, pol); |
@@ -1823,20 +1811,23 @@ out: | |||
1823 | } | 1811 | } |
1824 | EXPORT_SYMBOL(xfrm_user_policy); | 1812 | EXPORT_SYMBOL(xfrm_user_policy); |
1825 | 1813 | ||
1814 | static DEFINE_SPINLOCK(xfrm_km_lock); | ||
1815 | |||
1826 | int xfrm_register_km(struct xfrm_mgr *km) | 1816 | int xfrm_register_km(struct xfrm_mgr *km) |
1827 | { | 1817 | { |
1828 | write_lock_bh(&xfrm_km_lock); | 1818 | spin_lock_bh(&xfrm_km_lock); |
1829 | list_add_tail(&km->list, &xfrm_km_list); | 1819 | list_add_tail_rcu(&km->list, &xfrm_km_list); |
1830 | write_unlock_bh(&xfrm_km_lock); | 1820 | spin_unlock_bh(&xfrm_km_lock); |
1831 | return 0; | 1821 | return 0; |
1832 | } | 1822 | } |
1833 | EXPORT_SYMBOL(xfrm_register_km); | 1823 | EXPORT_SYMBOL(xfrm_register_km); |
1834 | 1824 | ||
1835 | int xfrm_unregister_km(struct xfrm_mgr *km) | 1825 | int xfrm_unregister_km(struct xfrm_mgr *km) |
1836 | { | 1826 | { |
1837 | write_lock_bh(&xfrm_km_lock); | 1827 | spin_lock_bh(&xfrm_km_lock); |
1838 | list_del(&km->list); | 1828 | list_del_rcu(&km->list); |
1839 | write_unlock_bh(&xfrm_km_lock); | 1829 | spin_unlock_bh(&xfrm_km_lock); |
1830 | synchronize_rcu(); | ||
1840 | return 0; | 1831 | return 0; |
1841 | } | 1832 | } |
1842 | EXPORT_SYMBOL(xfrm_unregister_km); | 1833 | EXPORT_SYMBOL(xfrm_unregister_km); |
@@ -1848,12 +1839,12 @@ int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1848 | return -EINVAL; | 1839 | return -EINVAL; |
1849 | if (unlikely(afinfo->family >= NPROTO)) | 1840 | if (unlikely(afinfo->family >= NPROTO)) |
1850 | return -EAFNOSUPPORT; | 1841 | return -EAFNOSUPPORT; |
1851 | write_lock_bh(&xfrm_state_afinfo_lock); | 1842 | spin_lock_bh(&xfrm_state_afinfo_lock); |
1852 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) | 1843 | if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) |
1853 | err = -ENOBUFS; | 1844 | err = -ENOBUFS; |
1854 | else | 1845 | else |
1855 | xfrm_state_afinfo[afinfo->family] = afinfo; | 1846 | rcu_assign_pointer(xfrm_state_afinfo[afinfo->family], afinfo); |
1856 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1847 | spin_unlock_bh(&xfrm_state_afinfo_lock); |
1857 | return err; | 1848 | return err; |
1858 | } | 1849 | } |
1859 | EXPORT_SYMBOL(xfrm_state_register_afinfo); | 1850 | EXPORT_SYMBOL(xfrm_state_register_afinfo); |
@@ -1865,14 +1856,15 @@ int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo) | |||
1865 | return -EINVAL; | 1856 | return -EINVAL; |
1866 | if (unlikely(afinfo->family >= NPROTO)) | 1857 | if (unlikely(afinfo->family >= NPROTO)) |
1867 | return -EAFNOSUPPORT; | 1858 | return -EAFNOSUPPORT; |
1868 | write_lock_bh(&xfrm_state_afinfo_lock); | 1859 | spin_lock_bh(&xfrm_state_afinfo_lock); |
1869 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { | 1860 | if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { |
1870 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) | 1861 | if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) |
1871 | err = -EINVAL; | 1862 | err = -EINVAL; |
1872 | else | 1863 | else |
1873 | xfrm_state_afinfo[afinfo->family] = NULL; | 1864 | RCU_INIT_POINTER(xfrm_state_afinfo[afinfo->family], NULL); |
1874 | } | 1865 | } |
1875 | write_unlock_bh(&xfrm_state_afinfo_lock); | 1866 | spin_unlock_bh(&xfrm_state_afinfo_lock); |
1867 | synchronize_rcu(); | ||
1876 | return err; | 1868 | return err; |
1877 | } | 1869 | } |
1878 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); | 1870 | EXPORT_SYMBOL(xfrm_state_unregister_afinfo); |
@@ -1882,17 +1874,16 @@ static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family) | |||
1882 | struct xfrm_state_afinfo *afinfo; | 1874 | struct xfrm_state_afinfo *afinfo; |
1883 | if (unlikely(family >= NPROTO)) | 1875 | if (unlikely(family >= NPROTO)) |
1884 | return NULL; | 1876 | return NULL; |
1885 | read_lock(&xfrm_state_afinfo_lock); | 1877 | rcu_read_lock(); |
1886 | afinfo = xfrm_state_afinfo[family]; | 1878 | afinfo = rcu_dereference(xfrm_state_afinfo[family]); |
1887 | if (unlikely(!afinfo)) | 1879 | if (unlikely(!afinfo)) |
1888 | read_unlock(&xfrm_state_afinfo_lock); | 1880 | rcu_read_unlock(); |
1889 | return afinfo; | 1881 | return afinfo; |
1890 | } | 1882 | } |
1891 | 1883 | ||
1892 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) | 1884 | static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo) |
1893 | __releases(xfrm_state_afinfo_lock) | ||
1894 | { | 1885 | { |
1895 | read_unlock(&xfrm_state_afinfo_lock); | 1886 | rcu_read_unlock(); |
1896 | } | 1887 | } |
1897 | 1888 | ||
1898 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ | 1889 | /* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */ |