IPSEC Linux kernel implementation (3) --- reserved

2010-11-15  来源:本站原创  分类:CPP  人气:188 

Copyleft this document owned by yfydz all, the use of GPL, free to copy, reprint, reproduced keep the documents for completeness, for any commercial purposes is strictly prohibited.
MSN: [email protected]
Source: http://yfydz.cublog.cn

5. Security Policy (xfrm_policy) treatment

Functions described in this section are net / xfrm / xfrm_policy.c defined.

5.1 Distribution Strategy

Strategy distribution function for the xfrm_policy_alloc (), the function is pfkey_spdadd () function call

struct xfrm_policy * xfrm_policy_alloc (gfp_t gfp)
{
struct xfrm_policy * policy;

/ / Allocate struct xfrm_policy structure of space and clear
policy = kzalloc (sizeof (struct xfrm_policy), gfp);

if (policy) {
/ / Initialize the link node
INIT_HLIST_NODE (& policy-> bydst);
INIT_HLIST_NODE (& policy-> byidx);
/ / Initialize locking
rwlock_init (& policy-> lock);
/ / Reference count is initialized to a strategy
atomic_set (& policy-> refcnt, 1);
/ / Initialize timer
init_timer (& policy-> timer);
policy-> timer.data = (unsigned long) policy;
policy-> timer.function = xfrm_policy_timer;
}
return policy;
}
EXPORT_SYMBOL (xfrm_policy_alloc);

Timer function:

static void xfrm_policy_timer (unsigned long data)
{
struct xfrm_policy * xp = (struct xfrm_policy *) data;
unsigned long now = (unsigned long) xtime.tv_sec;
long next = LONG_MAX;
int warn = 0;
int dir;
/ / Lock
read_lock (& xp-> lock);
/ / If the policy is already dead, exit
if (xp-> dead)
goto out;

/ / Index number based on the policy strategy of processing the data to determine the direction, look after the index number 3
dir = xfrm_policy_id2dir (xp-> index);

/ / If expired some time also forced to increase
if (xp-> lft.hard_add_expires_seconds) {
/ / Calculate the force to increase the timeout
long tmo = xp-> lft.hard_add_expires_seconds +
xp-> curlft.add_time - now;
/ / Can not increase the timeout, the maturity
if (tmo <= 0)
goto expired;
if (tmo <next)
next = tmo;
}
/ / Even if the force due to the increased use of time
if (xp-> lft.hard_use_expires_seconds) {
/ / Calculate the increased use of mandatory time
long tmo = xp-> lft.hard_use_expires_seconds +
(Xp-> curlft.use_time?: Xp-> curlft.add_time) - now;
/ / Can not increase the timeout, the maturity
if (tmo <= 0)
goto expired;
if (tmo <next)
next = tmo;
}
/ / If still soft due to the increase in some time
if (xp-> lft.soft_add_expires_seconds) {
/ / Calculate the increase in the time of soft
long tmo = xp-> lft.soft_add_expires_seconds +
xp-> curlft.add_time - now;
/ / Soft increase the timeout is less than 0, set the alarm flag and timeout is set to XFRM_KM_TIMEOUT, this and other different
if (tmo <= 0) {
warn = 1;
tmo = XFRM_KM_TIMEOUT;
}
if (tmo <next)
next = tmo;
}
/ / If the still soft due to the increased use of time
if (xp-> lft.soft_use_expires_seconds) {
/ / Calculate the increased use of flexible time
long tmo = xp-> lft.soft_use_expires_seconds +
(Xp-> curlft.use_time?: Xp-> curlft.add_time) - now;
/ / Soft increase the timeout is less than 0, set the alarm flag and timeout is set to XFRM_KM_TIMEOUT, this and other different
if (tmo <= 0) {
warn = 1;
tmo = XFRM_KM_TIMEOUT;
}
if (tmo <next)
next = tmo;
}
/ / Need the police, call the maturity of the callback
if (warn)
km_policy_expired (xp, dir, 0, 0);
/ / If the timeout value is valid update, modify the timer times out, increase the use of counting strategies
if (next! = LONG_MAX & &
! Mod_timer (& xp-> timer, jiffies + make_jiffies (next)))
xfrm_pol_hold (xp);

out:
read_unlock (& xp-> lock);
xfrm_pol_put (xp);
return;

expired:
read_unlock (& xp-> lock);
/ / If it does expire, delete strategy
if (! xfrm_policy_delete (xp, dir))
/ / 1 that is hard expired
km_policy_expired (xp, dir, 1, 0);
xfrm_pol_put (xp);
}

5.2 Strategy into

Strategy into the function xfrm_policy_insert (), the function is pfkey_spdadd () function call, pay attention to strategy list is sorted by priority order list size, so when inserted into strategic priority to be inserted compared to the appropriate location.

int xfrm_policy_insert (int dir, struct xfrm_policy * policy, int excl)
{
struct xfrm_policy * pol;
struct xfrm_policy * delpol;
struct hlist_head * chain;
struct hlist_node * entry, * newpos, * last;
struct dst_entry * gc_list;

write_lock_bh (& xfrm_policy_lock);
/ / Find the specific hash list
chain = policy_hash_bysel (& policy-> selector, policy-> family, dir);
delpol = NULL;
newpos = NULL;
last = NULL;
/ / Traverse the list, the list is based on the value of the priority strategies to sort the list, requiring new strategies based on size of the priority
/ / The new strategy into the appropriate location
hlist_for_each_entry (pol, entry, chain, bydst) {
/ / Delpol to empty
if (! delpol & &
/ / Strategy type comparison
pol-> type == policy-> type & &
/ / Select, relatively
! Selector_cmp (& pol-> selector, & policy-> selector) & &
/ / Security context of the comparison
xfrm_sec_ctx_match (pol-> security, policy-> security)) {
/ / The new strategy and a strategy for matching existing
if (excl) {
/ / Add operation if it is exclusive, the strategy to be inserted in the database already exists error
write_unlock_bh (& xfrm_policy_lock);
return-EEXIST;
}
/ / Save the strategic position to be deleted
delpol = pol;
/ / To update the policy priority of the priority value is greater than the original value, re-insertion loop to find a suitable location
/ / Because the value of the priority list is sorted, not chaos
/ / Now delpol has non-empty, the previous strategy was not possible to meet the search criteria
if (policy-> priority> pol-> priority)
continue;
} Else if (policy-> priority> = pol-> priority) {
/ / If the new priority is not less than the current priority, to save the current node and continue to find the appropriate insertion location
last = & pol-> bydst;
continue;
}
/ / Here is the priority of the new strategy based on the insertion site to determine
if (! newpos)
newpos = & pol-> bydst;
/ / If you have found a strategy to remove the interrupt
if (delpol)
break;
last = & pol-> bydst;
}
if (! newpos)
newpos = last;
/ / Insert the policy into the list at the destination address specified location HASH
if (newpos)
hlist_add_after (newpos, & policy-> bydst);
else
hlist_add_head (& policy-> bydst, chain);
/ / Increase reference count strategy
xfrm_pol_hold (policy);
/ / Increase the strategic direction 1
xfrm_policy_count [dir] + +;
atomic_inc (& flow_cache_genid);
/ / If there is the same old strategy, the destination address from the index HASH HASH and remove the two tables
if (delpol) {
hlist_del (& delpol-> bydst);
hlist_del (& delpol-> byidx);
xfrm_policy_count [dir] -;
}
/ / Get the index number of strategies, into the index list HASH
policy-> index = delpol? delpol-> index: xfrm_gen_index (policy-> type, dir);
hlist_add_head (& policy-> byidx, xfrm_policy_byidx + idx_hash (policy-> index));
/ / Insert the real time strategy
policy-> curlft.add_time = (unsigned long) xtime.tv_sec;
policy-> curlft.use_time = 0;
if (! mod_timer (& policy-> timer, jiffies + HZ))
xfrm_pol_hold (policy);
write_unlock_bh (& xfrm_policy_lock);

/ / Release the old strategy
if (delpol)
xfrm_policy_kill (delpol);
else if (xfrm_bydst_should_resize (dir, NULL))
schedule_work (& xfrm_hash_work);

/ / The following strategy for the release of all the current routing cache
read_lock_bh (& xfrm_policy_lock);
gc_list = NULL;
entry = & policy-> bydst;
/ / Iterate through the list, the list established to collect garbage route cache
hlist_for_each_entry_continue (policy, entry, bydst) {
struct dst_entry * dst;

write_lock (& policy-> lock);
/ / List header routing strategy
dst = policy-> bundles;
if (dst) {
/ / Directly to the policy routing list added to the list in front of garbage
struct dst_entry * tail = dst;
while (tail-> next)
tail = tail-> next;
tail-> next = gc_list;
gc_list = dst;
/ / The current strategy of routing is empty
policy-> bundles = NULL;
}
write_unlock (& policy-> lock);
}
read_unlock_bh (& xfrm_policy_lock);
/ / Release the garbage route cahce
while (gc_list) {
struct dst_entry * dst = gc_list;

gc_list = dst-> next;
dst_free (dst);
}

return 0;
}
EXPORT_SYMBOL (xfrm_policy_insert);

5.3 Remove all the security policies of a type

This function is pfkey_spdflush () function call, etc.

void xfrm_policy_flush (u8 type)
{
int dir;

write_lock_bh (& xfrm_policy_lock);
for (dir = 0; dir <XFRM_POLICY_MAX; dir + +) {
struct xfrm_policy * pol;
struct hlist_node * entry;
int i, killed;

killed = 0;
again1:
/ / Iterate through the list inexact HASH
hlist_for_each_entry (pol, entry,
& Xfrm_policy_inexact [dir], bydst) {
/ / Determine the type of
if (pol-> type! = type)
continue;
/ / The strategy off the list from the bydst
hlist_del (& pol-> bydst);
/ / The strategy off the list from the byidt
hlist_del (& pol-> byidx);
write_unlock_bh (& xfrm_policy_lock);
/ / Set the policy state dead, and added to the system's strategy for waste treatment to delete the list scheduling
xfrm_policy_kill (pol);
killed + +;

write_lock_bh (& xfrm_policy_lock);
goto again1;
}
/ / Iterate through the list of all the purpose of HASH
for (i = xfrm_policy_bydst [dir]. hmask; i> = 0; i -) {
again2:
/ / Iterate through the list by the destination address HASH
hlist_for_each_entry (pol, entry,
xfrm_policy_bydst [dir]. table + i,
bydst) {
if (pol-> type! = type)
continue;
/ / Disconnect the node from the list
hlist_del (& pol-> bydst);
hlist_del (& pol-> byidx);
write_unlock_bh (& xfrm_policy_lock);
/ / Release nodes
xfrm_policy_kill (pol);
killed + +;

write_lock_bh (& xfrm_policy_lock);
goto again2;
}
}

xfrm_policy_count [dir] -= killed;
}
atomic_inc (& flow_cache_genid);
write_unlock_bh (& xfrm_policy_lock);
}
EXPORT_SYMBOL (xfrm_policy_flush);

/ * Rule must be locked. Release descentant resources, announce
* Entry dead. The rule must be unlinked from lists to the moment.
* /
/ / Policy list released into the garbage
static void xfrm_policy_kill (struct xfrm_policy * policy)
{
int dead;

write_lock_bh (& policy-> lock);
/ / Keep the old DEAD logo
dead = policy-> dead;
/ / Set flag policy DEAD
policy-> dead = 1;
write_unlock_bh (& policy-> lock);

/ / Why not judge DEAD before it?
if (unlikely (dead)) {
WARN_ON (1);
return;
}

spin_lock (& xfrm_policy_gc_lock);
/ / Node in the strategy disconnect from the current list, spam list insertion strategy
hlist_add_head (& policy-> bydst, & xfrm_policy_gc_list);
spin_unlock (& xfrm_policy_gc_lock);
/ / Scheduling strategy for garbage work structure
schedule_work (& xfrm_policy_gc_work);
}

5.4 Search Strategy

5.4.1 Strategies to find and delete

Select the child and under the security context of search strategy, you can find strategies and deleted, pfkey_spddelete () function call

struct xfrm_policy * xfrm_policy_bysel_ctx (u8 type, int dir,
struct xfrm_selector * sel,
struct xfrm_sec_ctx * ctx, int delete)
{
struct xfrm_policy * pol, * ret;
struct hlist_head * chain;
struct hlist_node * entry;

write_lock_bh (& xfrm_policy_lock);
/ / Positioning HASH table
chain = policy_hash_bysel (sel, sel-> family, dir);
ret = NULL;
/ / Traverse the list
hlist_for_each_entry (pol, entry, chain, bydst) {
/ / According to the type and context selector to match
if (pol-> type == type & &
! Selector_cmp (sel, & pol-> selector) & &
xfrm_sec_ctx_match (ctx, pol-> security)) {
xfrm_pol_hold (pol);
if (delete) {
/ / If the strategy to delete the node from the destination address list and index HASH HASH off the list
hlist_del (& pol-> bydst);
hlist_del (& pol-> byidx);
xfrm_policy_count [dir] -;
}
ret = pol;
break;
}
}
write_unlock_bh (& xfrm_policy_lock);

if (ret & & delete) {
/ / Increase genid
atomic_inc (& flow_cache_genid);
/ / Set the policy state dead, and added to the system's strategy for waste treatment to delete the list scheduling
xfrm_policy_kill (ret);
}
return ret;
}
EXPORT_SYMBOL (xfrm_policy_bysel_ctx);

5.4.2 find and remove by index

struct xfrm_policy * xfrm_policy_byid (u8 type, int dir, u32 id, int delete)
{
struct xfrm_policy * pol, * ret;
struct hlist_head * chain;
struct hlist_node * entry;

write_lock_bh (& xfrm_policy_lock);
/ / List under the positioning index
chain = xfrm_policy_byidx + idx_hash (id);
ret = NULL;
/ / Traverse the list
hlist_for_each_entry (pol, entry, chain, byidx) {
/ / Strategy and index numbers are the same type of
if (pol-> type == type & & pol-> index == id) {
xfrm_pol_hold (pol);
/ / If you want to delete the policy node removed from the list
if (delete) {
hlist_del (& pol-> bydst);
hlist_del (& pol-> byidx);
xfrm_policy_count [dir] -;
}
ret = pol;
break;
}
}
write_unlock_bh (& xfrm_policy_lock);

if (ret & & delete) {
/ / Increase genid
atomic_inc (& flow_cache_genid);
/ / Set the policy state dead, and added to the system's strategy for waste treatment to delete the list scheduling
xfrm_policy_kill (ret);
}
return ret;
}
EXPORT_SYMBOL (xfrm_policy_byid);

5.4.3 Search strategy according to the routing

/ / Parameter fl is related to the structure of the routing, commonly used in the route lookup in the
/ / Note that the return value is an integer, 0 successful, non-0 failed, to find the strategy to be passed through parameter objp
static int xfrm_policy_lookup (struct flowi * fl, u16 family, u8 dir,
void ** objp, atomic_t ** obj_refp)
{
struct xfrm_policy * pol;
int err = 0;

# Ifdef CONFIG_XFRM_SUB_POLICY
/ / Find sub-strategies, are Linux extensions themselves, non-standard features
pol = xfrm_policy_lookup_bytype (XFRM_POLICY_TYPE_SUB, fl, family, dir);
if (IS_ERR (pol)) {
err = PTR_ERR (pol);
pol = NULL;
}
if (pol | | err)
goto end;
# Endif
/ / Find the type of strategy MAIN
pol = xfrm_policy_lookup_bytype (XFRM_POLICY_TYPE_MAIN, fl, family, dir);
if (IS_ERR (pol)) {
err = PTR_ERR (pol);
pol = NULL;
}
# Ifdef CONFIG_XFRM_SUB_POLICY
end:
# Endif
/ / Will find the return policy is assigned to objp
if ((* objp = (void *) pol)! = NULL)
* Obj_refp = & pol-> refcnt;
return err;
}

/ / By type of search strategy
static struct xfrm_policy * xfrm_policy_lookup_bytype (u8 type, struct flowi * fl,
u16 family, u8 dir)
{
int err;
struct xfrm_policy * pol, * ret;
xfrm_address_t * daddr, * saddr;
struct hlist_node * entry;
struct hlist_head * chain;
u32 priority = ~ 0U;

/ / By the current structure of the destination and source address
daddr = xfrm_flowi_daddr (fl, family);
saddr = xfrm_flowi_saddr (fl, family);
if (unlikely (! daddr | |! saddr))
return NULL;

read_lock_bh (& xfrm_policy_lock);
/ / List under the address information to find HASH
chain = policy_hash_direct (daddr, saddr, family, dir);
ret = NULL;
/ / Loop HASH list
hlist_for_each_entry (pol, entry, chain, bydst) {
/ / Check the current structure, type and protocol family match strategy, returns 0 matches
err = xfrm_policy_match (pol, fl, type, family, dir);
if (err) {
if (err ==-ESRCH)
continue;
else {
ret = ERR_PTR (err);
goto fail;
}
} Else {
/ / Backup to find the strategy and priority
ret = pol;
priority = ret-> priority;
break;
}
}
/ / Then find the list in the inexact strategy, if also find the strategy and priority of smaller,
/ / Will be a new strategy to find alternative strategies to find the front
chain = & xfrm_policy_inexact [dir];
/ / Loop HASH list
hlist_for_each_entry (pol, entry, chain, bydst) {
/ / Check the current structure, type and protocol family match strategy, returns 0 matches
err = xfrm_policy_match (pol, fl, type, family, dir);
if (err) {
if (err ==-ESRCH)
continue;
else {
ret = ERR_PTR (err);
goto fail;
}
} Else if (pol-> priority <priority) {
/ / If the priority of the new strategy to find smaller, to find a strategy to replace the original
ret = pol;
break;
}
}
if (ret)
xfrm_pol_hold (ret);
fail:
read_unlock_bh (& xfrm_policy_lock);

return ret;
}

/ / Check xfrm and flow parameters matching strategy is
/ / Returns 0 for successful match
static int xfrm_policy_match (struct xfrm_policy * pol, struct flowi * fl,
u8 type, u16 family, int dir)
{
/ / Selector
struct xfrm_selector * sel = & pol-> selector;
int match, ret =-ESRCH;
/ / Protocol family and type of inspection policy match
if (pol-> family! = family | |
pol-> type! = type)
return ret;
/ / Check whether the selector matches, return non-0 value indicates a successful match
match = xfrm_selector_match (sel, fl, family);
if (match)
/ / This security function can not be considered, as a function can return 0
ret = security_xfrm_policy_lookup (pol, fl-> secid, dir);

return ret;
}

/ / Selector matches, respectively, compared IPV4 and IPV6 protocol suite
static inline int
xfrm_selector_match (struct xfrm_selector * sel, struct flowi * fl,
unsigned short family)
{
switch (family) {
case AF_INET:
return __xfrm4_selector_match (sel, fl);
case AF_INET6:
return __xfrm6_selector_match (sel, fl);
}
return 0;
}

/ / IPV4 protocol family of choice, relatively
static inline int
__xfrm4_selector_match (struct xfrm_selector * sel, struct flowi * fl)
{
/ / Compare the destination address V4, V4 source address, destination port, source port, protocol, network card index
return addr_match (& fl-> fl4_dst, & sel-> daddr, sel-> prefixlen_d) & &
addr_match (& fl-> fl4_src, & sel-> saddr, sel-> prefixlen_s) & &
! ((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);
}

/ / IPV6 protocol family of choice, relatively
static inline int
__xfrm6_selector_match (struct xfrm_selector * sel, struct flowi * fl)
{
/ / Compare the destination address V6, V6 source address, destination port, source port, protocol, network card index
return addr_match (& fl-> fl6_dst, & sel-> daddr, sel-> prefixlen_d) & &
addr_match (& fl-> fl6_src, & sel-> saddr, sel-> prefixlen_s) & &
! ((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);
}

5.4.4 the corresponding strategy to find and sock

static struct xfrm_policy * xfrm_sk_policy_lookup (struct sock * sk, int dir, struct flowi * fl)
{
struct xfrm_policy * pol;

read_lock_bh (& xfrm_policy_lock);
/ / Sock structure is used to point to the way data are sk_policy security policy
if ((pol = sk-> sk_policy [dir])! = NULL) {
/ / Check whether the policy choices and the flow of sub-structure matching
int match = xfrm_selector_match (& pol-> selector, fl,
sk-> sk_family);
int err = 0;
/ / If match, then return to the policy as a result of
if (match) {
/ / This security function can be regarded as an empty function returns 0
err = security_xfrm_policy_lookup (pol, fl-> secid,
policy_to_flow_dir (dir));
if (! err)
xfrm_pol_hold (pol);
else if (err ==-ESRCH)
pol = NULL;
else
pol = ERR_PTR (err);
} Else
pol = NULL;
}
read_unlock_bh (& xfrm_policy_lock);
return pol;
}

5.5 traversal strategy

This function is pfkey_spddump () function call, etc.

/ / Func function is used to specify the search strategy to traverse
/ / Actual traverse all the strategies of two
int xfrm_policy_walk (u8 type, int (* func) (struct xfrm_policy *, int, int, void *),
void * data)
{
struct xfrm_policy * pol;
struct hlist_node * entry;
int dir, count, error;

read_lock_bh (& xfrm_policy_lock);
count = 0;
/ / First Statistics found the total number of types of strategies, the direction is two-way
for (dir = 0; dir <2 * XFRM_POLICY_MAX; dir + +) {
struct hlist_head * table = xfrm_policy_bydst [dir]. table;
int i;
/ / Inexact HASH table
hlist_for_each_entry (pol, entry,
& Xfrm_policy_inexact [dir], bydst) {
if (pol-> type == type)
count + +;
}
/ / Iterate through the list by address HASH
for (i = xfrm_policy_bydst [dir]. hmask; i> = 0; i -) {
/ / Traverse the list
hlist_for_each_entry (pol, entry, table + i, bydst) {
if (pol-> type == type)
count + +;
}
}
}

if (count == 0) {
error =-ENOENT;
goto out;
}
/ / HASH table to re-iterate, the current count value as the SA's serial number, serial number before the user space is decreasing
for (dir = 0; dir <2 * XFRM_POLICY_MAX; dir + +) {
struct hlist_head * table = xfrm_policy_bydst [dir]. table;
int i;
/ / Iterate through the list inexact
hlist_for_each_entry (pol, entry,
& Xfrm_policy_inexact [dir], bydst) {
if (pol-> type! = type)
continue;
/ / Types of policies that meet the func function call
error = func (pol, dir% XFRM_POLICY_MAX, - count, data);
if (error)
goto out;
}
/ / Iterate through the list by address HASH
for (i = xfrm_policy_bydst [dir]. hmask; i> = 0; i -) {
hlist_for_each_entry (pol, entry, table + i, bydst) {
if (pol-> type! = type)
continue;
/ / Types of policies that meet the func function call, when the count is reduced to 0 that the last strategy
error = func (pol, dir% XFRM_POLICY_MAX, - count, data);
if (error)
goto out;
}
}
}
error = 0;
out:
read_unlock_bh (& xfrm_policy_lock);
return error;
}
EXPORT_SYMBOL (xfrm_policy_walk);

5.5 Strategy check

__xfrm_policy_check function is a more important function that is xfrm_policy_check () call, and be xfrm4_policy_check () and xfrm6_policy_check () call, and these two functions at the network layer at the input and call forwarding.

Package to return to the ordinary legal, on the IPSEC packet inspection policy is legitimate, whether the direction and routing match

/ / Returns 1 for valid, 0 invalid, the function returns 0 for the data packets are usually discarded
int __xfrm_policy_check (struct sock * sk, int dir, struct sk_buff * skb,
unsigned short family)
{
struct xfrm_policy * pol;
struct xfrm_policy * pols [XFRM_POLICY_TYPE_MAX];
int npols = 0;
int xfrm_nr;
int pi;
struct flowi fl;
/ / Convert the policy direction of flow direction, in fact, is the same as the value
u8 fl_dir = policy_to_flow_dir (dir);
int xerr_idx = -1;

/ / Call the protocol suite decode_session () function, it is _decode_session4 IPV4
/ / Address of the skb in the fill port and other information in the flow structure fl
if (xfrm_decode_session (skb, & fl, family) <0)
return 0;
/ / If the kernel supports NETFILTER, NAT will fill in the information function call ip_nat_decode_session
/ / Otherwise it is empty function
nf_nat_decode_session (skb, & fl, family);

/ * First, check used SA against their selectors. * /
if (skb-> sp) {
/ / Decrypt the package is carried out after the IPSEC packets
int i;

for (i = skb-> sp-> len-1; i> = 0; i -) {
/ / Get the packet of information related to SA
struct xfrm_state * x = skb-> sp-> xvec [i];
/ / Check the SA selector and flow parameters (routing) match, the result is 0 for no match, do not match, then return
if (! xfrm_selector_match (& x-> sel, & fl, family))
return 0;
}
}

pol = NULL;
/ / If the sock structure and strategic
if (sk & & sk-> sk_policy [dir]) {
/ / Check whether the strategies and flow structure matching, matching words return policy
pol = xfrm_sk_policy_lookup (sk, dir, & fl);
if (IS_ERR (pol))
return 0;
}

/ / Find the routing information, if not to create a route, xfrm_policy_lookup () function as a parameter to the
/ / Flow_cache_lookup () function, search and security policy corresponding to the route
if (! pol)
pol = flow_cache_lookup (& fl, family, fl_dir,
xfrm_policy_lookup);
/ / Find the process error, return 0
if (IS_ERR (pol))
return 0;

/ / Strategy does not exist
if (! pol) {
/ / If the package is a package and secure IPSEC SA is not the path of the transmission mode,
/ / Forwarded, the packet has been no need to re-package package;
/ / Input, is their basic package IPSEC communications package and meaningless
if (skb-> sp & & secpath_has_nontransport (skb-> sp, 0, & xerr_idx)) {
/ / Reject the safe path, returns 0 failure
xfrm_secpath_reject (xerr_idx, skb, & fl);
return 0;
}
/ / General packet processing, security policy does not exist, return 1
return 1;
}

/ / Find a safe strategy, according to the strategy of the IPSEC packet processing
/ / Update the current strategy of using time
pol-> curlft.use_time = (unsigned long) xtime.tv_sec;

pols [0] = pol;
npols + +;
# Ifdef CONFIG_XFRM_SUB_POLICY
/ / If you define the limits of sub-strategies, then find the sub-strategy, which is not defined in the standard IPSEC can not consider
if (pols [0] -> type! = XFRM_POLICY_TYPE_MAIN) {
pols [1] = xfrm_policy_lookup_bytype (XFRM_POLICY_TYPE_MAIN,
& Fl, family,
XFRM_POLICY_IN);
if (pols [1]) {
if (IS_ERR (pols [1]))
return 0;
pols [1] -> curlft.use_time = (unsigned long) xtime.tv_sec;
npols + +;
}
}
# Endif

/ / Policy action is allows
if (pol-> action == XFRM_POLICY_ALLOW) {
struct sec_path * sp;
/ / First forged a safe path
static struct sec_path dummy;
struct xfrm_tmpl * tp [XFRM_MAX_DEPTH];
struct xfrm_tmpl * stp [XFRM_MAX_DEPTH];
struct xfrm_tmpl ** tpp = tp;
int ti = 0;
int i, k;

/ / If the data packet is no safe path, the path pointer is initialized to the safety of the path forged
if ((sp = skb-> sp) == NULL)
sp = &dummy;

/ / Iterate through an array of strategies, including the main strategy and sub-strategies (core sub-strategies to support it), in general, to a strategy
for (pi = 0; pi <npols; pi + +) {
/ / If there are other non-security policy allows, give up
if (pols [pi]! = pol & &
pols [pi] -> action! = XFRM_POLICY_ALLOW)
goto reject;
/ / If the policy level too much, give up
if (ti + pols [pi] -> xfrm_nr> = XFRM_MAX_DEPTH)
goto reject_error;
/ / Backup strategy in xfrm vector template, ti is the number of
for (i = 0; i <pols [pi] -> xfrm_nr; i + +)
tpp [ti + +] = & pols [pi] -> xfrm_vec [i];
}
/ / Number of policies
xfrm_nr = ti;
if (npols> 1) {
/ / If more than one strategy to sort, but when used in the kernel support subsystem, or simply return an error
/ / But the error can be ignored
xfrm_tmpl_sort (stp, tpp, xfrm_nr, family);
tpp = stp;
}

/ * For each tunnel xfrm, find the first matching tmpl.
* For each tmpl before that, find corresponding xfrm.
* Order is _important_. Later we will implement
* Some barriers, but at the moment barriers
* Are implied between each two transformations.
* /
/ / Traverse checking policy template is OK
for (i = xfrm_nr-1, k = 0; i> = 0; i -) {
/ / Note that k is both input and output values is, k is initialized to 0
/ / Return value is greater than or equal to 0 that the legal strategies available
k = xfrm_policy_ok (tpp [i], sp, k, family);
if (k <0) {
if (k <-1)
/ * "-2 - Errored_index" returned * /
xerr_idx = - (2 + k);
goto reject;
}
}
/ / There is a strategy of non-transmission mode, give up
if (secpath_has_nontransport (sp, k, & xerr_idx))
goto reject;

xfrm_pols_put (pols, npols);
return 1;
}
/ / Give up, do not pass inspection return 0
reject:
xfrm_secpath_reject (xerr_idx, skb, & fl);
reject_error:
xfrm_pols_put (pols, npols);
return 0;
}
EXPORT_SYMBOL (__xfrm_policy_check);

/ *
* 0 or more than 0 is returned when validation is succeeded (either bypass
* Because of optional transport mode, or next index of the mathced secpath
* State with the template.
* -1 Is returned when no matching template is found.
* Otherwise "-2 - errored_index" is returned.
* /
static inline int
xfrm_policy_ok (struct xfrm_tmpl * tmpl, struct sec_path * sp, int start,
unsigned short family)
{
int idx = start;

if (tmpl-> optional) {
/ / If the transfer mode, a direct return
if (tmpl-> mode == XFRM_MODE_TRANSPORT)
return start;
} Else
start = -1;
for (; idx <sp-> len; idx + +) {
/ / Sp-> xvec is xfrm state
/ / If the security path and template matching, returns the index position
if (xfrm_state_ok (tmpl, sp-> xvec [idx], family))
return + + idx;
/ / If security is not the path of the SA transmission mode, return error
if (sp-> xvec [idx] -> props.mode! = XFRM_MODE_TRANSPORT) {
if (start == -1)
start =-2-idx;
break;
}
}
return start;
}

5.6 Security Policy Routing Lookup

xfrm_lookup function is a very important function, according to security policy for routing data packets necklace constructed table, the routing table reflects a necklace for IPSEC packet processing multi-level packages, each package one to add a routing entry.
Route lookup function This function is ip_route_output_flow () call is forwarded or sent for the packet.

/ * Main function: finds / creates a bundle for given flow.
*
* At the moment we eat a raw IP route. Mostly to speed up lookups
* On interfaces with disabled IPsec.
* /
/ / Return 0 over, negative for failure
int xfrm_lookup (struct dst_entry ** dst_p, struct flowi * fl,
struct sock * sk, int flags)
{
struct xfrm_policy * policy;
struct xfrm_policy * pols [XFRM_POLICY_TYPE_MAX];
int npols;
int pol_dead;
int xfrm_nr;
int pi;
struct xfrm_state * xfrm [XFRM_MAX_DEPTH];
struct dst_entry * dst, * dst_orig = * dst_p;
int nx = 0;
int err;
u32 genid;
u16 family;
u8 dir = policy_to_flow_dir (XFRM_POLICY_OUT);

restart:
/ / Initialize the clear operation
genid = atomic_read (& flow_cache_genid);
policy = NULL;
for (pi = 0; pi <ARRAY_SIZE (pols); pi + +)
pols [pi] = NULL;
npols = 0;
pol_dead = 0;
xfrm_nr = 0;

if (sk & & sk-> sk_policy [1]) {
/ / If the security policy defined sock, sock-related strategies to find the
/ / A security policy can socket setsockopt () to set, socket option
/ / IP_IPSEC_POLICY or IP_XFRM_POLICY (net/ipv4/ip_sockglue.c)
policy = xfrm_sk_policy_lookup (sk, XFRM_POLICY_OUT, fl);
if (IS_ERR (policy))
return PTR_ERR (policy);
}

if (! policy) {
/ / Did not find its own defined security policy sock
/ * To accelerate a bit ... * /
/ / If the initial set of non-IPSEC route sign or not to issue the direction of security policy, a direct return
if ((dst_orig-> flags & DST_NOXFRM) | |
! Xfrm_policy_count [XFRM_POLICY_OUT])
return 0;

/ / Find the routing information, if not to create a route, xfrm_policy_lookup () function as a parameter to the
/ / Flow_cache_lookup () function, search and security policy corresponding to the route
policy = flow_cache_lookup (fl, dst_orig-> ops-> family,
dir, xfrm_policy_lookup);
if (IS_ERR (policy))
return PTR_ERR (policy);
}
/ / No return policy, then, is the general packet routing entries General
if (! policy)
return 0;

/ / The following is the case of a security strategy to establish a secure route to the package list
/ / Initial routing protocol suite
family = dst_orig-> ops-> family;
/ / Recent use of time security policy
policy-> curlft.use_time = (unsigned long) xtime.tv_sec;
/ / Will find an array of strategies as the first strategy
pols [0] = policy;
npols + +;
xfrm_nr + = pols [0] -> xfrm_nr;

/ / According to the results of policy actions related to treatment, only two cases: occlusion or by
switch (policy-> action) {
case XFRM_POLICY_BLOCK:
/ / Block the packet, return error
/ * Prohibit the flow * /
err =-EPERM;
goto error;

case XFRM_POLICY_ALLOW:
/ / Allow the packet to pass, so we must deal with the IPSEC packets
# Ifndef CONFIG_XFRM_SUB_POLICY
/ / Ignore pairs policy actions
if (policy-> xfrm_nr == 0) {
/ * Flow passes not transformed. * /
xfrm_pol_put (policy);
return 0;
}
# Endif

/ * Try to find matching bundle.
*
* LATER: help from flow cache. It is optional, this
* Is required only for output policy.
* /
/ / Look for existing secure routing, bundle can be interpreted as described in the safe handling of secure routing, data packets to go that route
/ / Is some sort of security package, and the general routing entries as secure routing is also used cached
dst = xfrm_find_bundle (fl, policy, family);
if (IS_ERR (dst)) {
err = PTR_ERR (dst);
goto error;
}
/ / If you find a safe route to exit the switch
if (dst)
break;

# Ifdef CONFIG_XFRM_SUB_POLICY
/ / Pair policy actions, because it is non-standard IPSEC, ignored
if (pols [0] -> type! = XFRM_POLICY_TYPE_MAIN) {
pols [1] = xfrm_policy_lookup_bytype (XFRM_POLICY_TYPE_MAIN,
fl, family,
XFRM_POLICY_OUT);
if (pols [1]) {
if (IS_ERR (pols [1])) {
err = PTR_ERR (pols [1]);
goto error;
}
if (pols [1] -> action == XFRM_POLICY_BLOCK) {
err =-EPERM;
goto error;
}
npols + +;
xfrm_nr + = pols [1] -> xfrm_nr;
}
}

/ *
* Because neither flowi nor bundle information knows about
* Transformation template size. On more than one policy usage
* We can realize whether all of them is bypass or not after
* They are searched. See above not-transformed bypass
* Is surrounded by non-sub policy configuration, too.
* /
if (xfrm_nr == 0) {
/ * Flow passes not transformed. * /
xfrm_pols_put (pols, npols);
return 0;
}

# Endif
/ / Did not find a safe route, ready to construct a new route entry
/ / Use strategies, flow-related parameters such as structure SA (xfrm_state) stored in the xfrm in, nx is the number of SA
nx = xfrm_tmpl_resolve (pols, npols, fl, xfrm, family);

if (unlikely (nx <0)) {
/ / Nx <0 for failure, did not find SA
/ / But if it is-EAGAIN, said the space has to notify the user to consult the new IKE SA, and
/ / Currently only generates the type of xfrm_state ACQUIRE
err = nx;
if (err ==-EAGAIN & & flags) {
/ / Process enters the blocked state
DECLARE_WAITQUEUE (wait, current);

add_wait_queue (& km_waitq, & wait);
set_current_state (TASK_INTERRUPTIBLE);
schedule ();
set_current_state (TASK_RUNNING);
remove_wait_queue (& km_waitq, & wait);
/ / Block lift, re-parsing SA
nx = xfrm_tmpl_resolve (pols, npols, fl, xfrm, family);

if (nx ==-EAGAIN & & signal_pending (current)) {
err =-ERESTART;
goto error;
}
if (nx ==-EAGAIN | |
genid! = atomic_read (& flow_cache_genid)) {
xfrm_pols_put (pols, npols);
goto restart;
}
err = nx;
}
if (err <0)
goto error;
}
if (nx == 0) {
/ / Nx == 0 IPSEC does not require that data is processed, the return
/ * Flow passes not transformed. * /
xfrm_pols_put (pols, npols);
return 0;
}
/ / Save the initial route
dst = dst_orig;
/ / Create a new secure routing, return 0 on success, failure to return a negative number
/ / Dst saved successfully secure routing entries return, each SA treatment corresponds to a secure routing, secure routing them through
/ / Routing entries in the child links as a list, so you can transform a row of data packets, such as the first compression,
/ / Re-ESP package, and then AH packaging.
/ / Routing tables necklace family structure and related agreements, follow-up article in the implementation of the specific protocol suite described in detail when
/ / Construct the routing entries of the specific structure of the situation
err = xfrm_bundle_create (policy, xfrm, nx, fl, & dst, family);

if (unlikely (err)) {
/ / If it fails to obtain the SA just released
int i;
for (i = 0; i <nx; i + +)
xfrm_state_put (xfrm [i]);
goto error;
}
/ / Check the status of all policy dead
for (pi = 0; pi <npols; pi + +) {
read_lock_bh (& pols [pi] -> lock);
pol_dead | = pols [pi] -> dead;
read_unlock_bh (& pols [pi] -> lock);
}

write_lock_bh (& policy-> lock);
/ / If there are dead or acquisition strategy is to secure routing entry in question, the release of secure routing
if (unlikely (pol_dead | | stale_bundle (dst))) {
/ * Wow! While we worked on resolving, this
* Policy has gone. Retry. It is not paranoia,
* We just cannot enlist new bundle to dead object.
* We can't enlist stable bundles either.
* /
write_unlock_bh (& policy-> lock);
if (dst)
dst_free (dst);

err =-EHOSTUNREACH;
goto error;
}
/ / The safe route to the routing strategy necklace header, the list is NULL at the end of the one-way linked list
/ / However, under normal circumstances there should be only one element
dst-> next = policy-> bundles;
policy-> bundles = dst;
dst_hold (dst);
write_unlock_bh (& policy-> lock);
}
/ / As the security list
* Dst_p = dst;
dst_release (dst_orig);
xfrm_pols_put (pols, npols);
return 0;

error:
dst_release (dst_orig);
xfrm_pols_put (pols, npols);
* Dst_p = NULL;
return err;
}
EXPORT_SYMBOL (xfrm_lookup);

The following are xfrm_lookup bundle used in the operation of the two functions: to find and create, the use of the address parameter, and it is family-related agreements, and therefore the specific implementation is implemented in each protocol family, in the follow-up article in the protocol family again when the xfrm implementation details.
static struct dst_entry *
xfrm_find_bundle (struct flowi * fl, struct xfrm_policy * policy, unsigned short family)
{
struct dst_entry * x;
struct xfrm_policy_afinfo * afinfo = xfrm_policy_get_afinfo (family);
if (unlikely (afinfo == NULL))
return ERR_PTR (-EINVAL);
x = afinfo-> find_bundle (fl, policy);
xfrm_policy_put_afinfo (afinfo);
return x;
}

/ * Allocate chain of dst_entry's, attach known xfrm's, calculate
* All the metrics ... Shortly, bundle a bundle.
* /

static int
xfrm_bundle_create (struct xfrm_policy * policy, struct xfrm_state ** xfrm, int nx,
struct flowi * fl, struct dst_entry ** dst_p,
unsigned short family)
{
int err;
struct xfrm_policy_afinfo * afinfo = xfrm_policy_get_afinfo (family);
if (unlikely (afinfo == NULL))
return-EINVAL;
err = afinfo-> bundle_create (policy, xfrm, nx, fl, dst_p);
xfrm_policy_put_afinfo (afinfo);
return err;
}

/ / Policy analysis to produce SA
static int
xfrm_tmpl_resolve (struct xfrm_policy ** pols, int npols, struct flowi * fl,
struct xfrm_state ** xfrm,
unsigned short family)
{
struct xfrm_state * tp [XFRM_MAX_DEPTH];
/ / Npols> 1 child policy is the definition of the situation, then save the array with the tp find the SA, but could not return to the original function of the
/ / Do not understand why they acted as
struct xfrm_state ** tpp = (npols> 1)? tp: xfrm;
int cnx = 0;
int error;
int ret;
int i;

/ / Traversal strategy, in general, is only 1 npols
for (i = 0; i <npols; i + +) {
/ / Check whether the buffer save SA's big enough
if (cnx + pols [i] -> xfrm_nr> = XFRM_MAX_DEPTH) {
error =-ENOBUFS;
goto fail;
}
/ / Protocol, a policy template
ret = xfrm_tmpl_resolve_one (pols [i], fl, & tpp [cnx], family);
if (ret <0) {
error = ret;
goto fail;
} Else
cnx + = ret;
}

/ * Found states are sorted for outbound processing * /
/ / If multiple policies are found in SA sort of, not the definition of sub-strategies in the case of an empty function
if (npols> 1)
xfrm_state_sort (xfrm, tpp, cnx, family);

return cnx;

fail:
for (cnx -; cnx> = 0; cnx -)
xfrm_state_put (tpp [cnx]);
return error;

}

/ * Resolve list of templates for the flow, given policy. * /

static int
xfrm_tmpl_resolve_one (struct xfrm_policy * policy, struct flowi * fl,
struct xfrm_state ** xfrm,
unsigned short family)
{
int nx;
int i, error;
/ / Get the address from the information flow structure
xfrm_address_t * daddr = xfrm_flowi_daddr (fl, family);
xfrm_address_t * saddr = xfrm_flowi_saddr (fl, family);
xfrm_address_t tmp;
/ / Iterate through all the SA strategy
for (nx = 0, i = 0; i <policy-> xfrm_nr; i + +) {
struct xfrm_state * x;
xfrm_address_t * remote = daddr;
xfrm_address_t * local = saddr;
struct xfrm_tmpl * tmpl = & policy-> xfrm_vec [i];

if (tmpl-> mode == XFRM_MODE_TUNNEL) {
/ / If the channel mode, adds the external IP header, IP header is encapsulated within the internal, external address so the address information
/ / SA policy templates that the address information
remote = & tmpl-> id.daddr;
local = & tmpl-> saddr;
/ / If the local address is not defined, select a source address as a local address, protocol family selection process is related
if (xfrm_addr_any (local, family)) {
error = xfrm_get_saddr (& tmp, remote, family);
if (error)
goto fail;
local = &tmp;
}
}
/ / According to the address, flow, strategy and other new search SA (xfrm_state), if no existing consultation process will inform the IKE
/ / Generate a new SA, but SA can be used before generating the type of return ACQUIRE SA, see the previous article
x = xfrm_state_find (remote, local, fl, tmpl, policy, & error, family);

if (x & & x-> km.state == XFRM_STATE_VALID) {
/ / If the SA is legal, save
xfrm [nx + +] = x;
daddr = remote;
saddr = local;
continue;
}
if (x) {
/ / X exists but is not VALID, as long as no error, it should be ACQUIRE type, such as the results of IKE negotiation process, the return-EAGAIN
error = (x-> km.state == XFRM_STATE_ERROR?
-EINVAL:-EAGAIN);
xfrm_state_put (x);
}

if (! tmpl-> optional)
goto fail;
}
return nx;

fail:
for (nx -; nx> = 0; nx -)
xfrm_state_put (xfrm [nx]);
return error;
}

On the routing process described later when the IPSEC packets sent during the routing process will be introduced in order to understand the role of secure routing.

5.6 change the size of HASH table

Change the policy status table is achieved through the work queue, and xfrm_state similar

Working definition:
static DECLARE_WORK (xfrm_hash_work, xfrm_hash_resize, NULL);

/ / Change the size of HASH table
static void xfrm_hash_resize (void * __unused)
{
int dir, total;

mutex_lock (& hash_resize_mutex);

total = 0;
/ / Note that strategies are two-way
for (dir = 0; dir <XFRM_POLICY_MAX * 2; dir + +) {
/ / Destination address by the HASH of the list: If you need to change the HASH table size, modified
if (xfrm_bydst_should_resize (dir, & total))
xfrm_bydst_resize (dir);
}
/ / HASH by index number for the list update
if (xfrm_byidx_should_resize (total))
xfrm_byidx_resize (total);

mutex_unlock (& hash_resize_mutex);
}

/ / Check the destination address by the HASH HASH list
static inline int xfrm_bydst_should_resize (int dir, int * total)
{
/ / The number of policy direction
unsigned int cnt = xfrm_policy_count [dir];
/ / Mask the direction of policy
unsigned int hmask = xfrm_policy_bydst [dir]. hmask;

/ / Cumulative number of policies
if (total)
* Total + = cnt;

/ / If the policy strategy of the mask is larger than the amount of the increase
if ((hmask + 1) <xfrm_policy_hashmax & &
cnt> hmask)
return 1;
/ / Otherwise do not
return 0;
}

/ / Check the index number by the HASH HASH list
static inline int xfrm_byidx_should_resize (int total)
{
unsigned int hmask = xfrm_idx_hmask;
/ / Strategy than the current index number of the total mask, which expanded the
if ((hmask + 1) <xfrm_policy_hashmax & &
total> hmask)
return 1;

return 0;
}

/ / Change the destination address by the HASH HASH list size
static void xfrm_bydst_resize (int dir)
{
/ / Mask the direction of the HASH table (maximum, usually 2 ^ N-1)
unsigned int hmask = xfrm_policy_bydst [dir]. hmask;
/ / New HASH Table mask (2 ^ (N +1) -1)
unsigned int nhashmask = xfrm_new_hash_mask (hmask);
/ / New size of HASH table
unsigned int nsize = (nhashmask + 1) * sizeof (struct hlist_head);
/ / Old HAHS list
struct hlist_head * odst = xfrm_policy_bydst [dir]. table;
/ / New HASH Table
struct hlist_head * ndst = xfrm_hash_alloc (nsize);
int i;

/ / New HASH Table space allocation does not come out, return
if (! ndst)
return;

write_lock_bh (& xfrm_policy_lock);

/ / Nodes of all strategies to the new HASH table
for (i = hmask; i> = 0; i -)
xfrm_dst_hash_transfer (odst + i, ndst, nhashmask);

/ / Update the global variable value HASH table parameters for the new
xfrm_policy_bydst [dir]. table = ndst;
xfrm_policy_bydst [dir]. hmask = nhashmask;

write_unlock_bh (& xfrm_policy_lock);
/ / Release old HASH table parameters
xfrm_hash_free (odst, (hmask + 1) * sizeof (struct hlist_head));
}

/ / Change the HASH HASH index number by the size of the list, the operation similar to the above
static void xfrm_byidx_resize (int total)
{
unsigned int hmask = xfrm_idx_hmask;
unsigned int nhashmask = xfrm_new_hash_mask (hmask);
unsigned int nsize = (nhashmask + 1) * sizeof (struct hlist_head);
struct hlist_head * oidx = xfrm_policy_byidx;
struct hlist_head * nidx = xfrm_hash_alloc (nsize);
int i;

if (! nidx)
return;

write_lock_bh (& xfrm_policy_lock);

for (i = hmask; i> = 0; i -)
xfrm_idx_hash_transfer (oidx + i, nidx, nhashmask);

xfrm_policy_byidx = nidx;
xfrm_idx_hmask = nhashmask;

write_unlock_bh (& xfrm_policy_lock);

xfrm_hash_free (oidx, (hmask + 1) * sizeof (struct hlist_head));
}

5.7 Garbage collection

Garbage collection is not a secure routing entries, and it is related protocol family
afinfo-> garbage_collect = __xfrm_garbage_collect;

/ / Is xfrm_prune_bundles () function of the packaging function, the condition that unused_bundle () function definition
static void __xfrm_garbage_collect (void)
{
xfrm_prune_bundles (unused_bundle);
}

/ / Deletion of secure routing
static void xfrm_prune_bundles (int (* func) (struct dst_entry *))
{
/ / Spam list
struct dst_entry * gc_list = NULL;
int dir;

read_lock_bh (& xfrm_policy_lock);
/ / Loop in all directions
for (dir = 0; dir <XFRM_POLICY_MAX * 2; dir + +) {
struct xfrm_policy * pol;
struct hlist_node * entry;
struct hlist_head * table;
int i;
/ / Iterate through the list inexact
hlist_for_each_entry (pol, entry,
& Xfrm_policy_inexact [dir], bydst)
/ / If the node to meet the conditions attached to the spam list to delete
prune_one_bundle (pol, func, & gc_list);

/ / Iterate through the list destination address HASH
table = xfrm_policy_bydst [dir]. table;
for (i = xfrm_policy_bydst [dir]. hmask; i> = 0; i -) {
/ / If the node to meet the conditions attached to the spam list to delete
hlist_for_each_entry (pol, entry, table + i, bydst)
prune_one_bundle (pol, func, & gc_list);
}
}
read_unlock_bh (& xfrm_policy_lock);
/ / If the garbage collected, the release of secure routing
while (gc_list) {
struct dst_entry * dst = gc_list;
gc_list = dst-> next;
dst_free (dst);
}
}

/ / No use of the route, use the number 0
static int unused_bundle (struct dst_entry * dst)
{
return! atomic_read (& dst-> __refcnt);
}

/ / Delete a single route
static void prune_one_bundle (struct xfrm_policy * pol, int (* func) (struct dst_entry *), struct dst_entry ** gc_list_p)
{
struct dst_entry * dst, ** dstp;
/ / Write lock strategy
write_lock (& pol-> lock);
/ / Starting point for policy routing table necklace
dstp = & pol-> bundles;
/ / Traverse the list
while ((dst =* dstp)! = NULL) {
if (func (dst)) {
/ / If the conditions of the node removed from the list, add to the spam list
* Dstp = dst-> next;
dst-> next = * gc_list_p;
* Gc_list_p = dst;
} Else {
dstp = & dst-> next;
}
}
write_unlock (& pol-> lock);
}

5.8 Miscellaneous

These miscellaneous functions are not directly deal with policy, but xfrm some correlation, but also on the xfrm_policy.c in the.

Type of treatment protocol processing 5.8.1

xfrm_type used to define the various types of protocol processing, such as AH, ESP, IPCOMP, IPIP, etc.

/ / Registration protocol processing type, return 0 on success, failure of non-0
int xfrm_register_type (struct xfrm_type * type, unsigned short family)
{
/ / Find the protocol structure of family-related policy information
struct xfrm_policy_afinfo * afinfo = xfrm_policy_lock_afinfo (family);
struct xfrm_type ** typemap;
int err = 0;

if (unlikely (afinfo == NULL))
return-EAFNOSUPPORT;
/ / The type of policy information structure array
typemap = afinfo-> type_map;

/ / If the array elements corresponding to the corresponding protocol is not empty, then the assignment, otherwise an error occurs
if (likely (typemap [type-> proto] == NULL))
typemap [type-> proto] = type;
else
err =-EEXIST;
xfrm_policy_unlock_afinfo (afinfo);
return err;
}
EXPORT_SYMBOL (xfrm_register_type);

/ / Remove protocol processing type, return 0 on success, failure of non-0
int xfrm_unregister_type (struct xfrm_type * type, unsigned short family)
{
/ / Find the protocol structure of family-related policy information
struct xfrm_policy_afinfo * afinfo = xfrm_policy_lock_afinfo (family);
struct xfrm_type ** typemap;
int err = 0;

if (unlikely (afinfo == NULL))
return-EAFNOSUPPORT;
/ / The type of policy information structure array
typemap = afinfo-> type_map;

/ / If the array is equal to the corresponding elements in the corresponding protocol to remove the structure, elements empty, otherwise an error occurs
if (unlikely (typemap [type-> proto]! = type))
err =-ENOENT;
else
typemap [type-> proto] = NULL;
xfrm_policy_unlock_afinfo (afinfo);
return err;
}
EXPORT_SYMBOL (xfrm_unregister_type);

/ / According to the agreement number and find the type of protocol family
struct xfrm_type * xfrm_get_type (u8 proto, unsigned short family)
{
struct xfrm_policy_afinfo * afinfo;
struct xfrm_type ** typemap;
struct xfrm_type * type;
int modload_attempted = 0;

retry:
/ / Find the protocol structure of family-related policy information
afinfo = xfrm_policy_get_afinfo (family);
if (unlikely (afinfo == NULL))
return NULL;
/ / The type of policy information structure array
typemap = afinfo-> type_map;

/ / Array of elements corresponding to the specified protocol
type = typemap [proto];
/ / Increase the use of type module count
if (unlikely (type & &! try_module_get (type-> owner)))
type = NULL;
/ / If the current type is empty, then type the kernel module loaded, re-locate
if (! type & &! modload_attempted) {
xfrm_policy_put_afinfo (afinfo);
request_module ("xfrm-type-% d-% d",
(Int) family, (int) proto);
modload_attempted = 1;
goto retry;
}

xfrm_policy_put_afinfo (afinfo);
return type;
}

/ / Release the type of module count
void xfrm_put_type (struct xfrm_type * type)
{
module_put (type-> owner);
}

5.8.2 protocol mode processing

Model now includes two kinds of channels and transmission.

/ / Registration mode, return 0 success, failure of non-0
int xfrm_register_mode (struct xfrm_mode * mode, int family)
{
struct xfrm_policy_afinfo * afinfo;
struct xfrm_mode ** modemap;
int err;

if (unlikely (mode-> encap> = XFRM_MODE_MAX))
return-EINVAL;

/ / Find the protocol structure of family-related policy information
afinfo = xfrm_policy_lock_afinfo (family);
if (unlikely (afinfo == NULL))
return-EAFNOSUPPORT;

err =-EEXIST;
/ / Policy information model structure array
modemap = afinfo-> mode_map;
/ / Array element is not empty, then the assignment, return success
if (likely (modemap [mode-> encap] == NULL)) {
modemap [mode-> encap] = mode;
err = 0;
}

xfrm_policy_unlock_afinfo (afinfo);
return err;
}
EXPORT_SYMBOL (xfrm_register_mode);

/ / Remove mode, and returns 0 on success, failure of non-0
int xfrm_unregister_mode (struct xfrm_mode * mode, int family)
{
struct xfrm_policy_afinfo * afinfo;
struct xfrm_mode ** modemap;
int err;

if (unlikely (mode-> encap> = XFRM_MODE_MAX))
return-EINVAL;

/ / Find the protocol structure of family-related policy information
afinfo = xfrm_policy_lock_afinfo (family);
if (unlikely (afinfo == NULL))
return-EAFNOSUPPORT;

err =-ENOENT;
/ / Policy information model structure array
modemap = afinfo-> mode_map;
/ / Array element is equal to the mode to remove, empty, return success
if (likely (modemap [mode-> encap] == mode)) {
modemap [mode-> encap] = NULL;
err = 0;
}

xfrm_policy_unlock_afinfo (afinfo);
return err;
}
EXPORT_SYMBOL (xfrm_unregister_mode);

/ / Search mode
struct xfrm_mode * xfrm_get_mode (unsigned int encap, int family)
{
struct xfrm_policy_afinfo * afinfo;
struct xfrm_mode * mode;
int modload_attempted = 0;

if (unlikely (encap> = XFRM_MODE_MAX))
return NULL;

retry:
/ / Find the protocol structure of family-related policy information
afinfo = xfrm_policy_get_afinfo (family);
if (unlikely (afinfo == NULL))
return NULL;

/ / Policy information model structure array
mode = afinfo-> mode_map [encap];
/ / Mode module to increase the use of counting
if (unlikely (mode & &! try_module_get (mode-> owner)))
mode = NULL;
/ / If the current mode is empty, the corresponding kernel module loading mode, re-locate
if (! mode & &! modload_attempted) {
xfrm_policy_put_afinfo (afinfo);
request_module ("xfrm-mode-% d-% d", family, encap);
modload_attempted = 1;
goto retry;
}

xfrm_policy_put_afinfo (afinfo);
return mode;
}

/ / Release mode module count
void xfrm_put_mode (struct xfrm_mode * mode)
{
module_put (mode-> owner);
}

5.8.3 Information Processing Agreement

/ / Registration protocol information structure
int xfrm_policy_register_afinfo (struct xfrm_policy_afinfo * afinfo)
{
int err = 0;
if (unlikely (afinfo == NULL))
return-EINVAL;
if (unlikely (afinfo-> family> = NPROTO))
return-EAFNOSUPPORT;
write_lock_bh (& xfrm_policy_afinfo_lock);
/ / Array structure of the corresponding agreement protocol information element should be empty
if (unlikely (xfrm_policy_afinfo [afinfo-> family]! = NULL))
err =-ENOBUFS;
else {
/ / Secure routing operating structure
struct dst_ops * dst_ops = afinfo-> dst_ops;
/ / Secure routing operation parameters of the structure and operation of the function assignment
if (likely (dst_ops-> kmem_cachep == NULL))
dst_ops-> kmem_cachep = xfrm_dst_cache;
if (likely (dst_ops-> check == NULL))
dst_ops-> check = xfrm_dst_check;
if (likely (dst_ops-> negative_advice == NULL))
dst_ops-> negative_advice = xfrm_negative_advice;
if (likely (dst_ops-> link_failure == NULL))
dst_ops-> link_failure = xfrm_link_failure;
if (likely (afinfo-> garbage_collect == NULL))
afinfo-> garbage_collect = __xfrm_garbage_collect;
/ / Array of corresponding structural elements of the agreement protocol information fill in the information structure for the agreement
xfrm_policy_afinfo [afinfo-> family] = afinfo;
}
write_unlock_bh (& xfrm_policy_afinfo_lock);
return err;
}
EXPORT_SYMBOL (xfrm_policy_register_afinfo);

/ / Remove protocol information structure
int xfrm_policy_unregister_afinfo (struct xfrm_policy_afinfo * afinfo)
{
int err = 0;
if (unlikely (afinfo == NULL))
return-EINVAL;
if (unlikely (afinfo-> family> = NPROTO))
return-EAFNOSUPPORT;
write_lock_bh (& xfrm_policy_afinfo_lock);
if (likely (xfrm_policy_afinfo [afinfo-> family]! = NULL)) {
/ / Array is equal to the specified protocol information structure of the information structure
if (unlikely (xfrm_policy_afinfo [afinfo-> family]! = afinfo))
err =-EINVAL;
else {
/ / Empty array elements and routing protocol information structure parameters of operation
struct dst_ops * dst_ops = afinfo-> dst_ops;
xfrm_policy_afinfo [afinfo-> family] = NULL;
dst_ops-> kmem_cachep = NULL;
dst_ops-> check = NULL;
dst_ops-> negative_advice = NULL;
dst_ops-> link_failure = NULL;
afinfo-> garbage_collect = NULL;
}
}
write_unlock_bh (& xfrm_policy_afinfo_lock);
return err;
}
EXPORT_SYMBOL (xfrm_policy_unregister_afinfo);

/ / Find protocol information structure, plus read lock
static struct xfrm_policy_afinfo * xfrm_policy_get_afinfo (unsigned short family)
{
struct xfrm_policy_afinfo * afinfo;
if (unlikely (family> = NPROTO))
return NULL;
read_lock (& xfrm_policy_afinfo_lock);
/ / Get the location specified in the agreement protocol information structure
afinfo = xfrm_policy_afinfo [family];
/ / If the protocol information structure does not exist, unlock
if (unlikely (! afinfo))
read_unlock (& xfrm_policy_afinfo_lock);
return afinfo;
}

/ / Release protocol information structure, interpretation of the lock
static void xfrm_policy_put_afinfo (struct xfrm_policy_afinfo * afinfo)
{
read_unlock (& xfrm_policy_afinfo_lock);
}

/ / Write-lock protocol information structure, information structure to return the specified protocol, the error returns NULL
static struct xfrm_policy_afinfo * xfrm_policy_lock_afinfo (unsigned int family)
{
struct xfrm_policy_afinfo * afinfo;
if (unlikely (family> = NPROTO))
return NULL;
write_lock_bh (& xfrm_policy_afinfo_lock);
/ / Get the location specified in the agreement protocol information structure
afinfo = xfrm_policy_afinfo [family];
/ / If the protocol information structure does not exist, unlock
if (unlikely (! afinfo))
write_unlock_bh (& xfrm_policy_afinfo_lock);
return afinfo;
}

/ / Write lock protocol information structure solution
static void xfrm_policy_unlock_afinfo (struct xfrm_policy_afinfo * afinfo)
{
write_unlock_bh (& xfrm_policy_afinfo_lock);
}

5.8.4 Callback Card

/ / Card notification structure
static struct notifier_block xfrm_dev_notifier = {
xfrm_dev_event,
NULL,
0
};

/ / Callback function
static int xfrm_dev_event (struct notifier_block * this, unsigned long event, void * ptr)
{
switch (event) {
/ / Stop the event to only respond card, delete, and LAN routing entries all security-related
case NETDEV_DOWN:
xfrm_flush_bundles ();
}
return NOTIFY_DONE;
}

static int xfrm_flush_bundles (void)
{
/ / Also used xfrm_prune_bundles () function to delete
/ / Conditional function is stale_bundle
xfrm_prune_bundles (stale_bundle);
return 0;
}

/ / Determine the availability of secure routing entries
/ / Returns 1 that is not available, 0 available
static int stale_bundle (struct dst_entry * dst)
{
return! xfrm_bundle_ok (NULL, (struct xfrm_dst *) dst, NULL, AF_UNSPEC, 0);
}

/ / Returns 0 is not available, one that can be used
int xfrm_bundle_ok (struct xfrm_policy * pol, struct xfrm_dst * first,
struct flowi * fl, int family, int strict)
{
struct dst_entry * dst = & first-> u.dst;
struct xfrm_dst * last;
u32 mtu;

/ / Check the routing entries
if (! dst_check (dst-> path, ((struct xfrm_dst *) dst) -> path_cookie) | |
/ / Check the card is running
(Dst-> dev & &! Netif_running (dst-> dev)))
return 0;

last = NULL;

do {
/ / Secure routing
struct xfrm_dst * xdst = (struct xfrm_dst *) dst;

/ / Check the SA selector matches flow structure
if (fl & &! xfrm_selector_match (& dst-> xfrm-> sel, fl, family))
return 0;
if (fl & &! security_xfrm_flow_state_match (fl, dst-> xfrm, pol))
return 0;
/ / Check the status of the legality of SA
if (dst-> xfrm-> km.state! = XFRM_STATE_VALID)
return 0;
if (xdst-> genid! = dst-> xfrm-> genid)
return 0;

/ / Strict check, the check of non-channel mode, the SA address and flow structure parameters match
if (strict & & fl & & dst-> xfrm-> props.mode! = XFRM_MODE_TUNNEL & &
! Xfrm_state_addr_flow_check (dst-> xfrm, fl, family))
return 0;
/ / Sub-route MTU items
mtu = dst_mtu (dst-> child);
if (xdst-> child_mtu_cached! = mtu) {
last = xdst;
xdst-> child_mtu_cached = mtu;
}
/ / Generic Routing Check
if (! dst_check (xdst-> route, xdst-> route_cookie))
return 0;

/ / Secure routing MTU related to general routing
mtu = dst_mtu (xdst-> route);
if (xdst-> route_mtu_cached! = mtu) {
last = xdst;
xdst-> route_mtu_cached = mtu;
}
/ / Traversal route list
dst = dst-> child;
} While (dst-> xfrm);

/ / Last is the last one and sub-routes and the general safety of the different routing MTU routes are generally the same
if (likely (! last))
return 1;

/ / Adjust the MTU of the route entry
mtu = last-> child_mtu_cached;
for (;;) {
dst = & last-> u.dst;

mtu = xfrm_state_mtu (dst-> xfrm, mtu);
if (mtu> last-> route_mtu_cached)
mtu = last-> route_mtu_cached;
dst-> metrics [RTAX_MTU-1] = mtu;

if (last == first)
break;

相关文章