diff options
Diffstat (limited to 'net/xfrm/xfrm_policy.c')
| -rw-r--r-- | net/xfrm/xfrm_policy.c | 83 |
1 files changed, 83 insertions, 0 deletions
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c index 44b64a593c01..b8936926c24b 100644 --- a/net/xfrm/xfrm_policy.c +++ b/net/xfrm/xfrm_policy.c | |||
| @@ -138,6 +138,89 @@ void xfrm_put_type(struct xfrm_type *type) | |||
| 138 | module_put(type->owner); | 138 | module_put(type->owner); |
| 139 | } | 139 | } |
| 140 | 140 | ||
| 141 | int 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 | } | ||
| 164 | EXPORT_SYMBOL(xfrm_register_mode); | ||
| 165 | |||
| 166 | int 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 | } | ||
| 189 | EXPORT_SYMBOL(xfrm_unregister_mode); | ||
| 190 | |||
| 191 | struct 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 | |||
| 200 | retry: | ||
| 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 | |||
| 219 | void xfrm_put_mode(struct xfrm_mode *mode) | ||
| 220 | { | ||
| 221 | module_put(mode->owner); | ||
| 222 | } | ||
| 223 | |||
| 141 | static inline unsigned long make_jiffies(long secs) | 224 | static inline unsigned long make_jiffies(long secs) |
| 142 | { | 225 | { |
| 143 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) | 226 | if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ) |
