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) |