X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=include%2Fnet%2Fxfrm.h;h=afa508d92c93fdf6b3a4a96946a223c440514750;hb=43bc926fffd92024b46cafaf7350d669ba9ca884;hp=aaf74999a1f3ff5dcd2d046c50f103812661f1d1;hpb=9bf4aaab3e101692164d49b7ca357651eb691cb6;p=linux-2.6.git diff --git a/include/net/xfrm.h b/include/net/xfrm.h index aaf74999a..afa508d92 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -1,14 +1,17 @@ #ifndef _NET_XFRM_H #define _NET_XFRM_H +#include +#include #include #include #include #include -#include +#include #include #include #include +#include #include #include @@ -18,7 +21,11 @@ #define XFRM_ALIGN8(len) (((len) + 7) & ~7) -extern struct semaphore xfrm_cfg_sem; +extern struct sock *xfrm_nl; +extern u32 sysctl_xfrm_aevent_etime; +extern u32 sysctl_xfrm_aevent_rseqth; + +extern struct mutex xfrm_cfg_mutex; /* Organization of SPD aka "XFRM rules" ------------------------------------ @@ -133,6 +140,21 @@ struct xfrm_state /* State for replay detection */ struct xfrm_replay_state replay; + /* Replay detection state at the time we sent the last notification */ + struct xfrm_replay_state preplay; + + /* internal flag that only holds state for delayed aevent at the + * moment + */ + u32 xflags; + + /* Replay detection notification settings */ + u32 replay_maxage; + u32 replay_maxdiff; + + /* Replay detection notification timer */ + struct timer_list rtimer; + /* Statistics */ struct xfrm_stats stats; @@ -143,11 +165,17 @@ struct xfrm_state * transformer. */ struct xfrm_type *type; + /* Security context */ + struct xfrm_sec_ctx *security; + /* Private data of this transformer, format is opaque, * interpreted by xfrm_type methods. */ void *data; }; +/* xflags - make enum if more show up */ +#define XFRM_TIME_DEFER 1 + enum { XFRM_STATE_VOID, XFRM_STATE_ACQ, @@ -157,6 +185,21 @@ enum { XFRM_STATE_DEAD }; +/* callback structure passed from either netlink or pfkey */ +struct km_event +{ + union { + u32 hard; + u32 proto; + u32 byid; + u32 aevent; + } data; + + u32 seq; + u32 pid; + u32 event; +}; + struct xfrm_type; struct xfrm_dst; struct xfrm_policy_afinfo { @@ -178,17 +221,21 @@ struct xfrm_policy_afinfo { extern int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo); extern int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo); -extern struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family); -extern void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo); - +extern void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c); +extern void km_state_notify(struct xfrm_state *x, struct km_event *c); #define XFRM_ACQ_EXPIRES 30 struct xfrm_tmpl; +extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol); +extern void km_state_expired(struct xfrm_state *x, int hard, u32 pid); +extern int __xfrm_state_delete(struct xfrm_state *x); + struct xfrm_state_afinfo { unsigned short family; rwlock_t lock; struct list_head *state_bydst; struct list_head *state_byspi; + int (*init_flags)(struct xfrm_state *x); void (*init_tempsel)(struct xfrm_state *x, struct flowi *fl, struct xfrm_tmpl *tmpl, xfrm_address_t *daddr, xfrm_address_t *saddr); @@ -200,23 +247,19 @@ struct xfrm_state_afinfo { extern int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo); extern int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo); -extern struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family); -extern void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo); extern void xfrm_state_delete_tunnel(struct xfrm_state *x); -struct xfrm_decap_state; struct xfrm_type { char *description; struct module *owner; __u8 proto; - int (*init_state)(struct xfrm_state *x, void *args); + int (*init_state)(struct xfrm_state *x); void (*destructor)(struct xfrm_state *); - int (*input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); - int (*post_input)(struct xfrm_state *, struct xfrm_decap_state *, struct sk_buff *skb); - int (*output)(struct sk_buff **pskb); + int (*input)(struct xfrm_state *, struct sk_buff *skb); + int (*output)(struct xfrm_state *, struct sk_buff *pskb); /* Estimate maximal size of result of transformation of a dgram */ u32 (*get_max_size)(struct xfrm_state *, int size); }; @@ -284,67 +327,41 @@ struct xfrm_policy __u8 flags; __u8 dead; __u8 xfrm_nr; + struct xfrm_sec_ctx *security; struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; }; -#define XFRM_KM_TIMEOUT 30 +#define XFRM_KM_TIMEOUT 30 +/* which seqno */ +#define XFRM_REPLAY_SEQ 1 +#define XFRM_REPLAY_OSEQ 2 +#define XFRM_REPLAY_SEQ_MASK 3 +/* what happened */ +#define XFRM_REPLAY_UPDATE XFRM_AE_CR +#define XFRM_REPLAY_TIMEOUT XFRM_AE_CE + +/* default aevent timeout in units of 100ms */ +#define XFRM_AE_ETIME 10 +/* Async Event timer multiplier */ +#define XFRM_AE_ETH_M 10 +/* default seq threshold size */ +#define XFRM_AE_SEQT_SIZE 2 struct xfrm_mgr { struct list_head list; char *id; - int (*notify)(struct xfrm_state *x, int event); + int (*notify)(struct xfrm_state *x, struct km_event *c); int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp, int dir); struct xfrm_policy *(*compile_policy)(u16 family, int opt, u8 *data, int len, int *dir); int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); - int (*notify_policy)(struct xfrm_policy *x, int dir, int event); + int (*notify_policy)(struct xfrm_policy *x, int dir, struct km_event *c); }; extern int xfrm_register_km(struct xfrm_mgr *km); extern int xfrm_unregister_km(struct xfrm_mgr *km); -#define XFRM_FLOWCACHE_HASH_SIZE 1024 - -static inline u32 __flow_hash4(struct flowi *fl) -{ - u32 hash = fl->fl4_src ^ fl->fl_ip_sport; - - hash = ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4); - - hash ^= fl->fl4_dst ^ fl->fl_ip_dport; - hash ^= (hash >> 10); - hash ^= (hash >> 20); - return hash & (XFRM_FLOWCACHE_HASH_SIZE-1); -} - -static inline u32 __flow_hash6(struct flowi *fl) -{ - u32 hash = fl->fl6_src.s6_addr32[2] ^ - fl->fl6_src.s6_addr32[3] ^ - fl->fl_ip_sport; - - hash = ((hash & 0xF0F0F0F0) >> 4) | ((hash & 0x0F0F0F0F) << 4); - - hash ^= fl->fl6_dst.s6_addr32[2] ^ - fl->fl6_dst.s6_addr32[3] ^ - fl->fl_ip_dport; - hash ^= (hash >> 10); - hash ^= (hash >> 20); - return hash & (XFRM_FLOWCACHE_HASH_SIZE-1); -} - -static inline u32 flow_hash(struct flowi *fl, unsigned short family) -{ - switch (family) { - case AF_INET: - return __flow_hash4(fl); - case AF_INET6: - return __flow_hash6(fl); - } - return 0; /*XXX*/ -} - extern struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2]; static inline void xfrm_pol_hold(struct xfrm_policy *policy) @@ -425,6 +442,11 @@ unsigned xfrm_spi_hash(xfrm_address_t *addr, u32 spi, u8 proto, unsigned short f extern void __xfrm_state_destroy(struct xfrm_state *); +static inline void __xfrm_state_put(struct xfrm_state *x) +{ + atomic_dec(&x->refcnt); +} + static inline void xfrm_state_put(struct xfrm_state *x) { if (atomic_dec_and_test(&x->refcnt)) @@ -462,13 +484,53 @@ static __inline__ int addr_match(void *token1, void *token2, int prefixlen) return 1; } +static __inline__ +u16 xfrm_flowi_sport(struct flowi *fl) +{ + u16 port; + switch(fl->proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + port = fl->fl_ip_sport; + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + port = htons(fl->fl_icmp_type); + break; + default: + port = 0; /*XXX*/ + } + return port; +} + +static __inline__ +u16 xfrm_flowi_dport(struct flowi *fl) +{ + u16 port; + switch(fl->proto) { + case IPPROTO_TCP: + case IPPROTO_UDP: + case IPPROTO_SCTP: + port = fl->fl_ip_dport; + break; + case IPPROTO_ICMP: + case IPPROTO_ICMPV6: + port = htons(fl->fl_icmp_code); + break; + default: + port = 0; /*XXX*/ + } + return port; +} + static inline int __xfrm4_selector_match(struct xfrm_selector *sel, struct flowi *fl) { return addr_match(&fl->fl4_dst, &sel->daddr, sel->prefixlen_d) && addr_match(&fl->fl4_src, &sel->saddr, sel->prefixlen_s) && - !((fl->fl_ip_dport^sel->dport)&sel->dport_mask) && - !((fl->fl_ip_sport^sel->sport)&sel->sport_mask) && + !((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) && + !((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) && (fl->proto == sel->proto || !sel->proto) && (fl->oif == sel->ifindex || !sel->ifindex); } @@ -478,8 +540,8 @@ __xfrm6_selector_match(struct xfrm_selector *sel, struct flowi *fl) { return addr_match(&fl->fl6_dst, &sel->daddr, sel->prefixlen_d) && addr_match(&fl->fl6_src, &sel->saddr, sel->prefixlen_s) && - !((fl->fl_ip_dport^sel->dport)&sel->dport_mask) && - !((fl->fl_ip_sport^sel->sport)&sel->sport_mask) && + !((xfrm_flowi_dport(fl) ^ sel->dport) & sel->dport_mask) && + !((xfrm_flowi_sport(fl) ^ sel->sport) & sel->sport_mask) && (fl->proto == sel->proto || !sel->proto) && (fl->oif == sel->ifindex || !sel->ifindex); } @@ -497,6 +559,25 @@ xfrm_selector_match(struct xfrm_selector *sel, struct flowi *fl, return 0; } +#ifdef CONFIG_SECURITY_NETWORK_XFRM +/* If neither has a context --> match + * Otherwise, both must have a context and the sids, doi, alg must match + */ +static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) +{ + return ((!s1 && !s2) || + (s1 && s2 && + (s1->ctx_sid == s2->ctx_sid) && + (s1->ctx_doi == s2->ctx_doi) && + (s1->ctx_alg == s2->ctx_alg))); +} +#else +static inline int xfrm_sec_ctx_match(struct xfrm_sec_ctx *s1, struct xfrm_sec_ctx *s2) +{ + return 1; +} +#endif + /* A struct encoding bundle of transformations to apply to some set of flow. * * dst->child points to the next element of bundle. @@ -516,27 +597,27 @@ struct xfrm_dst struct rtable rt; struct rt6_info rt6; } u; + struct dst_entry *route; + u32 route_mtu_cached; + u32 child_mtu_cached; + u32 route_cookie; + u32 path_cookie; }; -/* Decapsulation state, used by the input to store data during - * decapsulation procedure, to be used later (during the policy - * check - */ -struct xfrm_decap_state { - char decap_data[20]; - __u16 decap_type; -}; - -struct sec_decap_state { - struct xfrm_state *xvec; - struct xfrm_decap_state decap; -}; +static inline void xfrm_dst_destroy(struct xfrm_dst *xdst) +{ + dst_release(xdst->route); + if (likely(xdst->u.dst.xfrm)) + xfrm_state_put(xdst->u.dst.xfrm); +} + +extern void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev); struct sec_path { atomic_t refcnt; int len; - struct sec_decap_state x[XFRM_MAX_DEPTH]; + struct xfrm_state *xvec[XFRM_MAX_DEPTH]; }; static inline struct sec_path * @@ -602,7 +683,7 @@ static inline int xfrm_policy_check(struct sock *sk, int dir, struct sk_buff *sk if (sk && sk->sk_policy[XFRM_POLICY_IN]) return __xfrm_policy_check(sk, dir, skb, family); - return !xfrm_policy_list[dir] || + return (!xfrm_policy_list[dir] && !skb->sp) || (skb->dst->flags & DST_NOPOLICY) || __xfrm_policy_check(sk, dir, skb, family); } @@ -617,7 +698,7 @@ static inline int xfrm6_policy_check(struct sock *sk, int dir, struct sk_buff *s return xfrm_policy_check(sk, dir, skb, AF_INET6); } - +extern int xfrm_decode_session(struct sk_buff *skb, struct flowi *fl, unsigned short family); extern int __xfrm_route_forward(struct sk_buff *skb, unsigned short family); static inline int xfrm_route_forward(struct sk_buff *skb, unsigned short family) @@ -646,7 +727,7 @@ static inline int xfrm_sk_clone_policy(struct sock *sk) return 0; } -extern void xfrm_policy_delete(struct xfrm_policy *pol, int dir); +extern int xfrm_policy_delete(struct xfrm_policy *pol, int dir); static inline void xfrm_sk_free_policy(struct sock *sk) { @@ -776,27 +857,29 @@ struct xfrm_algo_desc { /* XFRM tunnel handlers. */ struct xfrm_tunnel { int (*handler)(struct sk_buff *skb); - void (*err_handler)(struct sk_buff *skb, void *info); + int (*err_handler)(struct sk_buff *skb, __u32 info); + + struct xfrm_tunnel *next; + int priority; }; struct xfrm6_tunnel { - int (*handler)(struct sk_buff **pskb, unsigned int *nhoffp); - void (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, - int type, int code, int offset, __u32 info); + int (*handler)(struct sk_buff *skb); + int (*err_handler)(struct sk_buff *skb, struct inet6_skb_parm *opt, + int type, int code, int offset, __u32 info); + + struct xfrm6_tunnel *next; + int priority; }; extern void xfrm_init(void); extern void xfrm4_init(void); -extern void xfrm4_fini(void); extern void xfrm6_init(void); extern void xfrm6_fini(void); extern void xfrm_state_init(void); extern void xfrm4_state_init(void); -extern void xfrm4_state_fini(void); extern void xfrm6_state_init(void); extern void xfrm6_state_fini(void); -extern void xfrm6_tunnel_init(void); -extern void xfrm6_tunnel_fini(void); extern int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *); extern struct xfrm_state *xfrm_state_alloc(void); @@ -808,26 +891,28 @@ extern int xfrm_state_check_expire(struct xfrm_state *x); extern void xfrm_state_insert(struct xfrm_state *x); extern int xfrm_state_add(struct xfrm_state *x); extern int xfrm_state_update(struct xfrm_state *x); -extern int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb); extern struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family); extern struct xfrm_state *xfrm_find_acq_byseq(u32 seq); -extern void xfrm_state_delete(struct xfrm_state *x); +extern int xfrm_state_delete(struct xfrm_state *x); extern void xfrm_state_flush(u8 proto); extern int xfrm_replay_check(struct xfrm_state *x, u32 seq); extern void xfrm_replay_advance(struct xfrm_state *x, u32 seq); -extern int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl); +extern void xfrm_replay_notify(struct xfrm_state *x, int event); extern int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb); +extern int xfrm_state_mtu(struct xfrm_state *x, int mtu); +extern int xfrm_init_state(struct xfrm_state *x); extern int xfrm4_rcv(struct sk_buff *skb); -extern int xfrm4_output(struct sk_buff **pskb); +extern int xfrm4_output(struct sk_buff *skb); extern int xfrm4_tunnel_register(struct xfrm_tunnel *handler); extern int xfrm4_tunnel_deregister(struct xfrm_tunnel *handler); -extern int xfrm6_rcv(struct sk_buff **pskb, unsigned int *nhoffp); +extern int xfrm6_rcv_spi(struct sk_buff *skb, u32 spi); +extern int xfrm6_rcv(struct sk_buff **pskb); extern int xfrm6_tunnel_register(struct xfrm6_tunnel *handler); extern int xfrm6_tunnel_deregister(struct xfrm6_tunnel *handler); extern u32 xfrm6_tunnel_alloc_spi(xfrm_address_t *saddr); extern void xfrm6_tunnel_free_spi(xfrm_address_t *saddr); extern u32 xfrm6_tunnel_spi_lookup(xfrm_address_t *saddr); -extern int xfrm6_output(struct sk_buff **pskb); +extern int xfrm6_output(struct sk_buff *skb); #ifdef CONFIG_XFRM extern int xfrm4_rcv_encap(struct sk_buff *skb, __u16 encap_type); @@ -851,14 +936,11 @@ static inline int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, unsig } #endif -void xfrm_policy_init(void); -void xfrm4_policy_init(void); -void xfrm6_policy_init(void); -struct xfrm_policy *xfrm_policy_alloc(int gfp); +struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp); extern int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*), void *); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); -struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel, - int delete); +struct xfrm_policy *xfrm_policy_bysel_ctx(int dir, struct xfrm_selector *sel, + struct xfrm_sec_ctx *ctx, int delete); struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete); void xfrm_policy_flush(void); u32 xfrm_get_acqseq(void); @@ -867,16 +949,15 @@ struct xfrm_state * xfrm_find_acq(u8 mode, u32 reqid, u8 proto, xfrm_address_t *daddr, xfrm_address_t *saddr, int create, unsigned short family); extern void xfrm_policy_flush(void); -extern void xfrm_policy_kill(struct xfrm_policy *); extern int xfrm_sk_policy_insert(struct sock *sk, int dir, struct xfrm_policy *pol); -extern struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl); extern int xfrm_flush_bundles(void); +extern void xfrm_flush_all_bundles(void); +extern int xfrm_bundle_ok(struct xfrm_dst *xdst, struct flowi *fl, int family); +extern void xfrm_init_pmtu(struct dst_entry *dst); extern wait_queue_head_t km_waitq; -extern void km_state_expired(struct xfrm_state *x, int hard); -extern int km_query(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *pol); extern int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport); -extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard); +extern void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid); extern void xfrm_input_init(void); extern int xfrm_parse_spi(struct sk_buff *skb, u8 nexthdr, u32 *spi, u32 *seq); @@ -886,13 +967,12 @@ extern int xfrm_count_auth_supported(void); extern int xfrm_count_enc_supported(void); extern struct xfrm_algo_desc *xfrm_aalg_get_byidx(unsigned int idx); extern struct xfrm_algo_desc *xfrm_ealg_get_byidx(unsigned int idx); -extern struct xfrm_algo_desc *xfrm_calg_get_byidx(unsigned int idx); extern struct xfrm_algo_desc *xfrm_aalg_get_byid(int alg_id); extern struct xfrm_algo_desc *xfrm_ealg_get_byid(int alg_id); extern struct xfrm_algo_desc *xfrm_calg_get_byid(int alg_id); -extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name); -extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name); -extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name); +extern struct xfrm_algo_desc *xfrm_aalg_get_byname(char *name, int probe); +extern struct xfrm_algo_desc *xfrm_ealg_get_byname(char *name, int probe); +extern struct xfrm_algo_desc *xfrm_calg_get_byname(char *name, int probe); struct crypto_tfm; typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsigned int); @@ -900,4 +980,42 @@ typedef void (icv_update_fn_t)(struct crypto_tfm *, struct scatterlist *, unsign extern void skb_icv_walk(const struct sk_buff *skb, struct crypto_tfm *tfm, int offset, int len, icv_update_fn_t icv_update); +static inline int xfrm_addr_cmp(xfrm_address_t *a, xfrm_address_t *b, + int family) +{ + switch (family) { + default: + case AF_INET: + return a->a4 - b->a4; + case AF_INET6: + return ipv6_addr_cmp((struct in6_addr *)a, + (struct in6_addr *)b); + } +} + +static inline int xfrm_policy_id2dir(u32 index) +{ + return index & 7; +} + +static inline int xfrm_aevent_is_on(void) +{ + struct sock *nlsk; + int ret = 0; + + rcu_read_lock(); + nlsk = rcu_dereference(xfrm_nl); + if (nlsk) + ret = netlink_has_listeners(nlsk, XFRMNLGRP_AEVENTS); + rcu_read_unlock(); + return ret; +} + +static inline void xfrm_aevent_doreplay(struct xfrm_state *x) +{ + if (xfrm_aevent_is_on()) + xfrm_replay_notify(x, XFRM_REPLAY_UPDATE); +} + + #endif /* _NET_XFRM_H */