📄 xfrm_state.c
字号:
} err = -EINVAL; spin_lock_bh(&x1->lock); if (likely(x1->km.state == XFRM_STATE_VALID)) { if (x->encap && x1->encap) memcpy(x1->encap, x->encap, sizeof(*x1->encap)); memcpy(&x1->lft, &x->lft, sizeof(x1->lft)); x1->km.dying = 0; if (!mod_timer(&x1->timer, jiffies + HZ)) xfrm_state_hold(x1); if (x1->curlft.use_time) xfrm_state_check_expire(x1); err = 0; } spin_unlock_bh(&x1->lock); xfrm_state_put(x1); return err;}int xfrm_state_check_expire(struct xfrm_state *x){ if (!x->curlft.use_time) x->curlft.use_time = (unsigned long)xtime.tv_sec; if (x->km.state != XFRM_STATE_VALID) return -EINVAL; if (x->curlft.bytes >= x->lft.hard_byte_limit || x->curlft.packets >= x->lft.hard_packet_limit) { km_state_expired(x, 1); if (!mod_timer(&x->timer, jiffies + XFRM_ACQ_EXPIRES*HZ)) xfrm_state_hold(x); return -EINVAL; } if (!x->km.dying && (x->curlft.bytes >= x->lft.soft_byte_limit || x->curlft.packets >= x->lft.soft_packet_limit)) km_state_expired(x, 0); return 0;}int xfrm_state_check_space(struct xfrm_state *x, struct sk_buff *skb){ int nhead = x->props.header_len + LL_RESERVED_SPACE(skb->dst->dev) - skb_headroom(skb); if (nhead > 0) return pskb_expand_head(skb, nhead, 0, GFP_ATOMIC); /* Check tail too... */ return 0;}int xfrm_state_check(struct xfrm_state *x, struct sk_buff *skb){ int err = xfrm_state_check_expire(x); if (err < 0) goto err; err = xfrm_state_check_space(x, skb);err: return err;}struct xfrm_state *xfrm_state_lookup(xfrm_address_t *daddr, u32 spi, u8 proto, unsigned short family){ struct xfrm_state *x; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return NULL; spin_lock_bh(&xfrm_state_lock); x = afinfo->state_lookup(daddr, spi, proto); spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return x;}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){ struct xfrm_state *x; struct xfrm_state_afinfo *afinfo = xfrm_state_get_afinfo(family); if (!afinfo) return NULL; spin_lock_bh(&xfrm_state_lock); x = afinfo->find_acq(mode, reqid, proto, daddr, saddr, create); spin_unlock_bh(&xfrm_state_lock); xfrm_state_put_afinfo(afinfo); return x;}/* Silly enough, but I'm lazy to build resolution list */static struct xfrm_state *__xfrm_find_acq_byseq(u32 seq){ int i; struct xfrm_state *x; for (i = 0; i < XFRM_DST_HSIZE; i++) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) { if (x->km.seq == seq) { xfrm_state_hold(x); return x; } } } return NULL;}struct xfrm_state *xfrm_find_acq_byseq(u32 seq){ struct xfrm_state *x; spin_lock_bh(&xfrm_state_lock); x = __xfrm_find_acq_byseq(seq); spin_unlock_bh(&xfrm_state_lock); return x;} u32 xfrm_get_acqseq(void){ u32 res; static u32 acqseq; static spinlock_t acqseq_lock = SPIN_LOCK_UNLOCKED; spin_lock_bh(&acqseq_lock); res = (++acqseq ? : ++acqseq); spin_unlock_bh(&acqseq_lock); return res;}voidxfrm_alloc_spi(struct xfrm_state *x, u32 minspi, u32 maxspi){ u32 h; struct xfrm_state *x0; if (x->id.spi) return; if (minspi == maxspi) { x0 = xfrm_state_lookup(&x->id.daddr, minspi, x->id.proto, x->props.family); if (x0) { xfrm_state_put(x0); return; } x->id.spi = minspi; } else { u32 spi = 0; minspi = ntohl(minspi); maxspi = ntohl(maxspi); for (h=0; h<maxspi-minspi+1; h++) { spi = minspi + net_random()%(maxspi-minspi+1); x0 = xfrm_state_lookup(&x->id.daddr, htonl(spi), x->id.proto, x->props.family); if (x0 == NULL) { x->id.spi = htonl(spi); break; } xfrm_state_put(x0); } } if (x->id.spi) { spin_lock_bh(&xfrm_state_lock); h = xfrm_spi_hash(&x->id.daddr, x->id.spi, x->id.proto, x->props.family); list_add(&x->byspi, xfrm_state_byspi+h); xfrm_state_hold(x); spin_unlock_bh(&xfrm_state_lock); wake_up(&km_waitq); }}int xfrm_state_walk(u8 proto, int (*func)(struct xfrm_state *, int, void*), void *data){ int i; struct xfrm_state *x; int count = 0; int err = 0; spin_lock_bh(&xfrm_state_lock); for (i = 0; i < XFRM_DST_HSIZE; i++) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) { if (proto == IPSEC_PROTO_ANY || x->id.proto == proto) count++; } } if (count == 0) { err = -ENOENT; goto out; } for (i = 0; i < XFRM_DST_HSIZE; i++) { list_for_each_entry(x, xfrm_state_bydst+i, bydst) { if (proto != IPSEC_PROTO_ANY && x->id.proto != proto) continue; err = func(x, --count, data); if (err) goto out; } }out: spin_unlock_bh(&xfrm_state_lock); return err;}int xfrm_replay_check(struct xfrm_state *x, u32 seq){ u32 diff; seq = ntohl(seq); if (unlikely(seq == 0)) return -EINVAL; if (likely(seq > x->replay.seq)) return 0; diff = x->replay.seq - seq; if (diff >= x->props.replay_window) { x->stats.replay_window++; return -EINVAL; } if (x->replay.bitmap & (1U << diff)) { x->stats.replay++; return -EINVAL; } return 0;}void xfrm_replay_advance(struct xfrm_state *x, u32 seq){ u32 diff; seq = ntohl(seq); if (seq > x->replay.seq) { diff = seq - x->replay.seq; if (diff < x->props.replay_window) x->replay.bitmap = ((x->replay.bitmap) << diff) | 1; else x->replay.bitmap = 1; x->replay.seq = seq; } else { diff = x->replay.seq - seq; x->replay.bitmap |= (1U << diff); }}int xfrm_check_selectors(struct xfrm_state **x, int n, struct flowi *fl){ int i; for (i=0; i<n; i++) { int match; match = xfrm_selector_match(&x[i]->sel, fl, x[i]->props.family); if (!match) return -EINVAL; } return 0;}static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);static rwlock_t xfrm_km_lock = RW_LOCK_UNLOCKED;void km_state_expired(struct xfrm_state *x, int hard){ struct xfrm_mgr *km; if (hard) x->km.state = XFRM_STATE_EXPIRED; else x->km.dying = 1; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) km->notify(x, hard); read_unlock(&xfrm_km_lock); if (hard) wake_up(&km_waitq);}int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol){ int err = -EINVAL; struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { err = km->acquire(x, t, pol, XFRM_POLICY_OUT); if (!err) break; } read_unlock(&xfrm_km_lock); return err;}int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, u16 sport){ int err = -EINVAL; struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { if (km->new_mapping) err = km->new_mapping(x, ipaddr, sport); if (!err) break; } read_unlock(&xfrm_km_lock); return err;}void km_policy_expired(struct xfrm_policy *pol, int dir, int hard){ struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) if (km->notify_policy) km->notify_policy(pol, dir, hard); read_unlock(&xfrm_km_lock); if (hard) wake_up(&km_waitq);}int xfrm_user_policy(struct sock *sk, int optname, u8 __user *optval, int optlen){ int err; u8 *data; struct xfrm_mgr *km; struct xfrm_policy *pol = NULL; if (optlen <= 0 || optlen > PAGE_SIZE) return -EMSGSIZE; data = kmalloc(optlen, GFP_KERNEL); if (!data) return -ENOMEM; err = -EFAULT; if (copy_from_user(data, optval, optlen)) goto out; err = -EINVAL; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { pol = km->compile_policy(sk->sk_family, optname, data, optlen, &err); if (err >= 0) break; } read_unlock(&xfrm_km_lock); if (err >= 0) { xfrm_sk_policy_insert(sk, err, pol); xfrm_pol_put(pol); err = 0; }out: kfree(data); return err;}int xfrm_register_km(struct xfrm_mgr *km){ write_lock_bh(&xfrm_km_lock); list_add_tail(&km->list, &xfrm_km_list); write_unlock_bh(&xfrm_km_lock); return 0;}int xfrm_unregister_km(struct xfrm_mgr *km){ write_lock_bh(&xfrm_km_lock); list_del(&km->list); write_unlock_bh(&xfrm_km_lock); return 0;}int xfrm_state_register_afinfo(struct xfrm_state_afinfo *afinfo){ int err = 0; if (unlikely(afinfo == NULL)) return -EINVAL; if (unlikely(afinfo->family >= NPROTO)) return -EAFNOSUPPORT; write_lock(&xfrm_state_afinfo_lock); if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) err = -ENOBUFS; else { afinfo->state_bydst = xfrm_state_bydst; afinfo->state_byspi = xfrm_state_byspi; xfrm_state_afinfo[afinfo->family] = afinfo; } write_unlock(&xfrm_state_afinfo_lock); return err;}int xfrm_state_unregister_afinfo(struct xfrm_state_afinfo *afinfo){ int err = 0; if (unlikely(afinfo == NULL)) return -EINVAL; if (unlikely(afinfo->family >= NPROTO)) return -EAFNOSUPPORT; write_lock(&xfrm_state_afinfo_lock); if (likely(xfrm_state_afinfo[afinfo->family] != NULL)) { if (unlikely(xfrm_state_afinfo[afinfo->family] != afinfo)) err = -EINVAL; else { xfrm_state_afinfo[afinfo->family] = NULL; afinfo->state_byspi = NULL; afinfo->state_bydst = NULL; } } write_unlock(&xfrm_state_afinfo_lock); return err;}struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned short family){ struct xfrm_state_afinfo *afinfo; if (unlikely(family >= NPROTO)) return NULL; read_lock(&xfrm_state_afinfo_lock); afinfo = xfrm_state_afinfo[family]; if (likely(afinfo != NULL)) read_lock(&afinfo->lock); read_unlock(&xfrm_state_afinfo_lock); return afinfo;}void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo){ if (unlikely(afinfo == NULL)) return; read_unlock(&afinfo->lock);}/* Temporarily located here until net/xfrm/xfrm_tunnel.c is created */void xfrm_state_delete_tunnel(struct xfrm_state *x){ if (x->tunnel) { struct xfrm_state *t = x->tunnel; if (atomic_read(&t->tunnel_users) == 2) xfrm_state_delete(t); atomic_dec(&t->tunnel_users); xfrm_state_put(t); x->tunnel = NULL; }}void __init xfrm_state_init(void){ int i; for (i=0; i<XFRM_DST_HSIZE; i++) { INIT_LIST_HEAD(&xfrm_state_bydst[i]); INIT_LIST_HEAD(&xfrm_state_byspi[i]); } INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task, NULL);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -