📄 xfrm_state.c
字号:
* timeout of our timer function * 2. if x->replay_maxage has elapsed since last update, * and there were changes * * The state structure must be locked! */ switch (event) { case XFRM_REPLAY_UPDATE: if (x->replay_maxdiff && (x->replay.seq - x->preplay.seq < x->replay_maxdiff) && (x->replay.oseq - x->preplay.oseq < x->replay_maxdiff)) { if (x->xflags & XFRM_TIME_DEFER) event = XFRM_REPLAY_TIMEOUT; else return; } break; case XFRM_REPLAY_TIMEOUT: if ((x->replay.seq == x->preplay.seq) && (x->replay.bitmap == x->preplay.bitmap) && (x->replay.oseq == x->preplay.oseq)) { x->xflags |= XFRM_TIME_DEFER; return; } break; } memcpy(&x->preplay, &x->replay, sizeof(struct xfrm_replay_state)); c.event = XFRM_MSG_NEWAE; c.data.aevent = event; km_state_notify(x, &c); if (x->replay_maxage && !mod_timer(&x->rtimer, jiffies + x->replay_maxage)) x->xflags &= ~XFRM_TIME_DEFER;}static void xfrm_replay_timer_handler(unsigned long data){ struct xfrm_state *x = (struct xfrm_state*)data; spin_lock(&x->lock); if (x->km.state == XFRM_STATE_VALID) { if (xfrm_aevent_is_on()) xfrm_replay_notify(x, XFRM_REPLAY_TIMEOUT); else x->xflags |= XFRM_TIME_DEFER; } spin_unlock(&x->lock);}int xfrm_replay_check(struct xfrm_state *x, __be32 net_seq){ u32 diff; u32 seq = ntohl(net_seq); if (unlikely(seq == 0)) return -EINVAL; if (likely(seq > x->replay.seq)) return 0; diff = x->replay.seq - seq; if (diff >= min_t(unsigned int, x->props.replay_window, sizeof(x->replay.bitmap) * 8)) { x->stats.replay_window++; return -EINVAL; } if (x->replay.bitmap & (1U << diff)) { x->stats.replay++; return -EINVAL; } return 0;}EXPORT_SYMBOL(xfrm_replay_check);void xfrm_replay_advance(struct xfrm_state *x, __be32 net_seq){ u32 diff; u32 seq = ntohl(net_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); } if (xfrm_aevent_is_on()) xfrm_replay_notify(x, XFRM_REPLAY_UPDATE);}EXPORT_SYMBOL(xfrm_replay_advance);static struct list_head xfrm_km_list = LIST_HEAD_INIT(xfrm_km_list);static DEFINE_RWLOCK(xfrm_km_lock);void km_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c){ 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(xp, dir, c); read_unlock(&xfrm_km_lock);}void km_state_notify(struct xfrm_state *x, struct km_event *c){ struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) if (km->notify) km->notify(x, c); read_unlock(&xfrm_km_lock);}EXPORT_SYMBOL(km_policy_notify);EXPORT_SYMBOL(km_state_notify);void km_state_expired(struct xfrm_state *x, int hard, u32 pid){ struct km_event c; c.data.hard = hard; c.pid = pid; c.event = XFRM_MSG_EXPIRE; km_state_notify(x, &c); if (hard) wake_up(&km_waitq);}EXPORT_SYMBOL(km_state_expired);/* * We send to all registered managers regardless of failure * We are happy with one success*/int km_query(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *pol){ int err = -EINVAL, acqret; struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { acqret = km->acquire(x, t, pol, XFRM_POLICY_OUT); if (!acqret) err = acqret; } read_unlock(&xfrm_km_lock); return err;}EXPORT_SYMBOL(km_query);int km_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 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;}EXPORT_SYMBOL(km_new_mapping);void km_policy_expired(struct xfrm_policy *pol, int dir, int hard, u32 pid){ struct km_event c; c.data.hard = hard; c.pid = pid; c.event = XFRM_MSG_POLEXPIRE; km_policy_notify(pol, dir, &c); if (hard) wake_up(&km_waitq);}EXPORT_SYMBOL(km_policy_expired);#ifdef CONFIG_XFRM_MIGRATEint km_migrate(struct xfrm_selector *sel, u8 dir, u8 type, struct xfrm_migrate *m, int num_migrate){ int err = -EINVAL; int ret; struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { if (km->migrate) { ret = km->migrate(sel, dir, type, m, num_migrate); if (!ret) err = ret; } } read_unlock(&xfrm_km_lock); return err;}EXPORT_SYMBOL(km_migrate);#endifint km_report(u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr){ int err = -EINVAL; int ret; struct xfrm_mgr *km; read_lock(&xfrm_km_lock); list_for_each_entry(km, &xfrm_km_list, list) { if (km->report) { ret = km->report(proto, sel, addr); if (!ret) err = ret; } } read_unlock(&xfrm_km_lock); return err;}EXPORT_SYMBOL(km_report);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, 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;}EXPORT_SYMBOL(xfrm_user_policy);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;}EXPORT_SYMBOL(xfrm_register_km);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;}EXPORT_SYMBOL(xfrm_unregister_km);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_bh(&xfrm_state_afinfo_lock); if (unlikely(xfrm_state_afinfo[afinfo->family] != NULL)) err = -ENOBUFS; else xfrm_state_afinfo[afinfo->family] = afinfo; write_unlock_bh(&xfrm_state_afinfo_lock); return err;}EXPORT_SYMBOL(xfrm_state_register_afinfo);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_bh(&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; } write_unlock_bh(&xfrm_state_afinfo_lock); return err;}EXPORT_SYMBOL(xfrm_state_unregister_afinfo);static struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family){ struct xfrm_state_afinfo *afinfo; if (unlikely(family >= NPROTO)) return NULL; read_lock(&xfrm_state_afinfo_lock); afinfo = xfrm_state_afinfo[family]; if (unlikely(!afinfo)) read_unlock(&xfrm_state_afinfo_lock); return afinfo;}static void xfrm_state_put_afinfo(struct xfrm_state_afinfo *afinfo){ read_unlock(&xfrm_state_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; }}EXPORT_SYMBOL(xfrm_state_delete_tunnel);int xfrm_state_mtu(struct xfrm_state *x, int mtu){ int res; spin_lock_bh(&x->lock); if (x->km.state == XFRM_STATE_VALID && x->type && x->type->get_mtu) res = x->type->get_mtu(x, mtu); else res = mtu - x->props.header_len; spin_unlock_bh(&x->lock); return res;}int xfrm_init_state(struct xfrm_state *x){ struct xfrm_state_afinfo *afinfo; int family = x->props.family; int err; err = -EAFNOSUPPORT; afinfo = xfrm_state_get_afinfo(family); if (!afinfo) goto error; err = 0; if (afinfo->init_flags) err = afinfo->init_flags(x); xfrm_state_put_afinfo(afinfo); if (err) goto error; err = -EPROTONOSUPPORT; x->inner_mode = xfrm_get_mode(x->props.mode, x->sel.family); if (x->inner_mode == NULL) goto error; if (!(x->inner_mode->flags & XFRM_MODE_FLAG_TUNNEL) && family != x->sel.family) goto error; x->type = xfrm_get_type(x->id.proto, family); if (x->type == NULL) goto error; err = x->type->init_state(x); if (err) goto error; x->outer_mode = xfrm_get_mode(x->props.mode, family); if (x->outer_mode == NULL) goto error; x->km.state = XFRM_STATE_VALID;error: return err;}EXPORT_SYMBOL(xfrm_init_state);void __init xfrm_state_init(void){ unsigned int sz; sz = sizeof(struct hlist_head) * 8; xfrm_state_bydst = xfrm_hash_alloc(sz); xfrm_state_bysrc = xfrm_hash_alloc(sz); xfrm_state_byspi = xfrm_hash_alloc(sz); if (!xfrm_state_bydst || !xfrm_state_bysrc || !xfrm_state_byspi) panic("XFRM: Cannot allocate bydst/bysrc/byspi hashes."); xfrm_state_hmask = ((sz / sizeof(struct hlist_head)) - 1); INIT_WORK(&xfrm_state_gc_work, xfrm_state_gc_task);}#ifdef CONFIG_AUDITSYSCALLstatic inline void xfrm_audit_common_stateinfo(struct xfrm_state *x, struct audit_buffer *audit_buf){ if (x->security) audit_log_format(audit_buf, " sec_alg=%u sec_doi=%u sec_obj=%s", x->security->ctx_alg, x->security->ctx_doi, x->security->ctx_str); switch(x->props.family) { case AF_INET: audit_log_format(audit_buf, " src=%u.%u.%u.%u dst=%u.%u.%u.%u", NIPQUAD(x->props.saddr.a4), NIPQUAD(x->id.daddr.a4)); break; case AF_INET6: { struct in6_addr saddr6, daddr6; memcpy(&saddr6, x->props.saddr.a6, sizeof(struct in6_addr)); memcpy(&daddr6, x->id.daddr.a6, sizeof(struct in6_addr)); audit_log_format(audit_buf, " src=" NIP6_FMT " dst=" NIP6_FMT, NIP6(saddr6), NIP6(daddr6)); } break; }}voidxfrm_audit_state_add(struct xfrm_state *x, int result, u32 auid, u32 sid){ struct audit_buffer *audit_buf; u32 spi; extern int audit_enabled; if (audit_enabled == 0) return; audit_buf = xfrm_audit_start(auid, sid); if (audit_buf == NULL) return; audit_log_format(audit_buf, " op=SAD-add res=%u",result); xfrm_audit_common_stateinfo(x, audit_buf); spi = ntohl(x->id.spi); audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); audit_log_end(audit_buf);}EXPORT_SYMBOL_GPL(xfrm_audit_state_add);voidxfrm_audit_state_delete(struct xfrm_state *x, int result, u32 auid, u32 sid){ struct audit_buffer *audit_buf; u32 spi; extern int audit_enabled; if (audit_enabled == 0) return; audit_buf = xfrm_audit_start(auid, sid); if (audit_buf == NULL) return; audit_log_format(audit_buf, " op=SAD-delete res=%u",result); xfrm_audit_common_stateinfo(x, audit_buf); spi = ntohl(x->id.spi); audit_log_format(audit_buf, " spi=%u(0x%x)", spi, spi); audit_log_end(audit_buf);}EXPORT_SYMBOL_GPL(xfrm_audit_state_delete);#endif /* CONFIG_AUDITSYSCALL */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -