diff options
author | Jamal Hadi Salim <hadi@cyberus.ca> | 2010-02-22 06:32:59 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-02-22 19:21:25 -0500 |
commit | 6f26b61e177e57a41795355f6222cf817f1212dc (patch) | |
tree | 6894f386ad84fa6d48ff860e6f04b9e5acd65024 /net/xfrm/xfrm_user.c | |
parent | 34f8d8846f69f3b5bc3916ba9145e4eebae9394e (diff) |
xfrm: Allow user space config of SAD mark
Add ability for netlink userspace to manipulate the SAD
and manipulate the mark, retrieve it and get events with a defined
mark.
MIGRATE may be added later.
Signed-off-by: Jamal Hadi Salim <hadi@cyberus.ca>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/xfrm/xfrm_user.c')
-rw-r--r-- | net/xfrm/xfrm_user.c | 72 |
1 files changed, 57 insertions, 15 deletions
diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index 02a67b4a64dd..303092f7088b 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c | |||
@@ -32,7 +32,6 @@ | |||
32 | #endif | 32 | #endif |
33 | 33 | ||
34 | #define DUMMY_MARK 0 | 34 | #define DUMMY_MARK 0 |
35 | static struct xfrm_mark dummy_mark = {0, 0}; | ||
36 | 35 | ||
37 | static inline int aead_len(struct xfrm_algo_aead *alg) | 36 | static inline int aead_len(struct xfrm_algo_aead *alg) |
38 | { | 37 | { |
@@ -449,6 +448,8 @@ static struct xfrm_state *xfrm_state_construct(struct net *net, | |||
449 | goto error; | 448 | goto error; |
450 | } | 449 | } |
451 | 450 | ||
451 | xfrm_mark_get(attrs, &x->mark); | ||
452 | |||
452 | err = xfrm_init_state(x); | 453 | err = xfrm_init_state(x); |
453 | if (err) | 454 | if (err) |
454 | goto error; | 455 | goto error; |
@@ -529,11 +530,13 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
529 | int *errp) | 530 | int *errp) |
530 | { | 531 | { |
531 | struct xfrm_state *x = NULL; | 532 | struct xfrm_state *x = NULL; |
533 | struct xfrm_mark m; | ||
532 | int err; | 534 | int err; |
535 | u32 mark = xfrm_mark_get(attrs, &m); | ||
533 | 536 | ||
534 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { | 537 | if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { |
535 | err = -ESRCH; | 538 | err = -ESRCH; |
536 | x = xfrm_state_lookup(net, DUMMY_MARK, &p->daddr, p->spi, p->proto, p->family); | 539 | x = xfrm_state_lookup(net, mark, &p->daddr, p->spi, p->proto, p->family); |
537 | } else { | 540 | } else { |
538 | xfrm_address_t *saddr = NULL; | 541 | xfrm_address_t *saddr = NULL; |
539 | 542 | ||
@@ -544,7 +547,8 @@ static struct xfrm_state *xfrm_user_state_lookup(struct net *net, | |||
544 | } | 547 | } |
545 | 548 | ||
546 | err = -ESRCH; | 549 | err = -ESRCH; |
547 | x = xfrm_state_lookup_byaddr(net, DUMMY_MARK, &p->daddr, saddr, | 550 | x = xfrm_state_lookup_byaddr(net, mark, |
551 | &p->daddr, saddr, | ||
548 | p->proto, p->family); | 552 | p->proto, p->family); |
549 | } | 553 | } |
550 | 554 | ||
@@ -686,6 +690,9 @@ static int copy_to_user_state_extra(struct xfrm_state *x, | |||
686 | if (x->encap) | 690 | if (x->encap) |
687 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); | 691 | NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); |
688 | 692 | ||
693 | if (xfrm_mark_put(skb, &x->mark)) | ||
694 | goto nla_put_failure; | ||
695 | |||
689 | if (x->security && copy_sec_ctx(x->security, skb) < 0) | 696 | if (x->security && copy_sec_ctx(x->security, skb) < 0) |
690 | goto nla_put_failure; | 697 | goto nla_put_failure; |
691 | 698 | ||
@@ -950,6 +957,8 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
950 | xfrm_address_t *daddr; | 957 | xfrm_address_t *daddr; |
951 | int family; | 958 | int family; |
952 | int err; | 959 | int err; |
960 | u32 mark; | ||
961 | struct xfrm_mark m; | ||
953 | 962 | ||
954 | p = nlmsg_data(nlh); | 963 | p = nlmsg_data(nlh); |
955 | err = verify_userspi_info(p); | 964 | err = verify_userspi_info(p); |
@@ -960,8 +969,10 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
960 | daddr = &p->info.id.daddr; | 969 | daddr = &p->info.id.daddr; |
961 | 970 | ||
962 | x = NULL; | 971 | x = NULL; |
972 | |||
973 | mark = xfrm_mark_get(attrs, &m); | ||
963 | if (p->info.seq) { | 974 | if (p->info.seq) { |
964 | x = xfrm_find_acq_byseq(net, DUMMY_MARK, p->info.seq); | 975 | x = xfrm_find_acq_byseq(net, mark, p->info.seq); |
965 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { | 976 | if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { |
966 | xfrm_state_put(x); | 977 | xfrm_state_put(x); |
967 | x = NULL; | 978 | x = NULL; |
@@ -969,7 +980,7 @@ static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
969 | } | 980 | } |
970 | 981 | ||
971 | if (!x) | 982 | if (!x) |
972 | x = xfrm_find_acq(net, &dummy_mark, p->info.mode, p->info.reqid, | 983 | x = xfrm_find_acq(net, &m, p->info.mode, p->info.reqid, |
973 | p->info.id.proto, daddr, | 984 | p->info.id.proto, daddr, |
974 | &p->info.saddr, 1, | 985 | &p->info.saddr, 1, |
975 | family); | 986 | family); |
@@ -1474,8 +1485,8 @@ static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1474 | if (err) | 1485 | if (err) |
1475 | return err; | 1486 | return err; |
1476 | } | 1487 | } |
1477 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, | 1488 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, &p->sel, |
1478 | &p->sel, ctx, delete, &err); | 1489 | ctx, delete, &err); |
1479 | security_xfrm_policy_free(ctx); | 1490 | security_xfrm_policy_free(ctx); |
1480 | } | 1491 | } |
1481 | if (xp == NULL) | 1492 | if (xp == NULL) |
@@ -1547,6 +1558,7 @@ static inline size_t xfrm_aevent_msgsize(void) | |||
1547 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) | 1558 | return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) |
1548 | + nla_total_size(sizeof(struct xfrm_replay_state)) | 1559 | + nla_total_size(sizeof(struct xfrm_replay_state)) |
1549 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) | 1560 | + nla_total_size(sizeof(struct xfrm_lifetime_cur)) |
1561 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
1550 | + nla_total_size(4) /* XFRM_AE_RTHR */ | 1562 | + nla_total_size(4) /* XFRM_AE_RTHR */ |
1551 | + nla_total_size(4); /* XFRM_AE_ETHR */ | 1563 | + nla_total_size(4); /* XFRM_AE_ETHR */ |
1552 | } | 1564 | } |
@@ -1579,6 +1591,9 @@ static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
1579 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, | 1591 | NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, |
1580 | x->replay_maxage * 10 / HZ); | 1592 | x->replay_maxage * 10 / HZ); |
1581 | 1593 | ||
1594 | if (xfrm_mark_put(skb, &x->mark)) | ||
1595 | goto nla_put_failure; | ||
1596 | |||
1582 | return nlmsg_end(skb, nlh); | 1597 | return nlmsg_end(skb, nlh); |
1583 | 1598 | ||
1584 | nla_put_failure: | 1599 | nla_put_failure: |
@@ -1594,6 +1609,8 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1594 | struct sk_buff *r_skb; | 1609 | struct sk_buff *r_skb; |
1595 | int err; | 1610 | int err; |
1596 | struct km_event c; | 1611 | struct km_event c; |
1612 | u32 mark; | ||
1613 | struct xfrm_mark m; | ||
1597 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1614 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1598 | struct xfrm_usersa_id *id = &p->sa_id; | 1615 | struct xfrm_usersa_id *id = &p->sa_id; |
1599 | 1616 | ||
@@ -1601,7 +1618,9 @@ static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1601 | if (r_skb == NULL) | 1618 | if (r_skb == NULL) |
1602 | return -ENOMEM; | 1619 | return -ENOMEM; |
1603 | 1620 | ||
1604 | x = xfrm_state_lookup(net, DUMMY_MARK, &id->daddr, id->spi, id->proto, id->family); | 1621 | mark = xfrm_mark_get(attrs, &m); |
1622 | |||
1623 | x = xfrm_state_lookup(net, mark, &id->daddr, id->spi, id->proto, id->family); | ||
1605 | if (x == NULL) { | 1624 | if (x == NULL) { |
1606 | kfree_skb(r_skb); | 1625 | kfree_skb(r_skb); |
1607 | return -ESRCH; | 1626 | return -ESRCH; |
@@ -1632,6 +1651,8 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1632 | struct xfrm_state *x; | 1651 | struct xfrm_state *x; |
1633 | struct km_event c; | 1652 | struct km_event c; |
1634 | int err = - EINVAL; | 1653 | int err = - EINVAL; |
1654 | u32 mark = 0; | ||
1655 | struct xfrm_mark m; | ||
1635 | struct xfrm_aevent_id *p = nlmsg_data(nlh); | 1656 | struct xfrm_aevent_id *p = nlmsg_data(nlh); |
1636 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; | 1657 | struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; |
1637 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; | 1658 | struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; |
@@ -1643,7 +1664,9 @@ static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1643 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) | 1664 | if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) |
1644 | return err; | 1665 | return err; |
1645 | 1666 | ||
1646 | x = xfrm_state_lookup(net, DUMMY_MARK, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | 1667 | mark = xfrm_mark_get(attrs, &m); |
1668 | |||
1669 | x = xfrm_state_lookup(net, mark, &p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); | ||
1647 | if (x == NULL) | 1670 | if (x == NULL) |
1648 | return -ESRCH; | 1671 | return -ESRCH; |
1649 | 1672 | ||
@@ -1729,7 +1752,8 @@ static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1729 | if (err) | 1752 | if (err) |
1730 | return err; | 1753 | return err; |
1731 | } | 1754 | } |
1732 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, &p->sel, ctx, 0, &err); | 1755 | xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, type, p->dir, |
1756 | &p->sel, ctx, 0, &err); | ||
1733 | security_xfrm_policy_free(ctx); | 1757 | security_xfrm_policy_free(ctx); |
1734 | } | 1758 | } |
1735 | if (xp == NULL) | 1759 | if (xp == NULL) |
@@ -1769,8 +1793,10 @@ static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1769 | int err; | 1793 | int err; |
1770 | struct xfrm_user_expire *ue = nlmsg_data(nlh); | 1794 | struct xfrm_user_expire *ue = nlmsg_data(nlh); |
1771 | struct xfrm_usersa_info *p = &ue->state; | 1795 | struct xfrm_usersa_info *p = &ue->state; |
1796 | struct xfrm_mark m; | ||
1797 | u32 mark = xfrm_mark_get(attrs, &m);; | ||
1772 | 1798 | ||
1773 | x = xfrm_state_lookup(net, DUMMY_MARK, &p->id.daddr, p->id.spi, p->id.proto, p->family); | 1799 | x = xfrm_state_lookup(net, mark, &p->id.daddr, p->id.spi, p->id.proto, p->family); |
1774 | 1800 | ||
1775 | err = -ENOENT; | 1801 | err = -ENOENT; |
1776 | if (x == NULL) | 1802 | if (x == NULL) |
@@ -1804,6 +1830,7 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1804 | struct xfrm_user_tmpl *ut; | 1830 | struct xfrm_user_tmpl *ut; |
1805 | int i; | 1831 | int i; |
1806 | struct nlattr *rt = attrs[XFRMA_TMPL]; | 1832 | struct nlattr *rt = attrs[XFRMA_TMPL]; |
1833 | struct xfrm_mark mark; | ||
1807 | 1834 | ||
1808 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); | 1835 | struct xfrm_user_acquire *ua = nlmsg_data(nlh); |
1809 | struct xfrm_state *x = xfrm_state_alloc(net); | 1836 | struct xfrm_state *x = xfrm_state_alloc(net); |
@@ -1812,6 +1839,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1812 | if (!x) | 1839 | if (!x) |
1813 | goto nomem; | 1840 | goto nomem; |
1814 | 1841 | ||
1842 | xfrm_mark_get(attrs, &mark); | ||
1843 | |||
1815 | err = verify_newpolicy_info(&ua->policy); | 1844 | err = verify_newpolicy_info(&ua->policy); |
1816 | if (err) | 1845 | if (err) |
1817 | goto bad_policy; | 1846 | goto bad_policy; |
@@ -1824,7 +1853,8 @@ static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, | |||
1824 | memcpy(&x->id, &ua->id, sizeof(ua->id)); | 1853 | memcpy(&x->id, &ua->id, sizeof(ua->id)); |
1825 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); | 1854 | memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); |
1826 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); | 1855 | memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); |
1827 | 1856 | xp->mark.m = x->mark.m = mark.m; | |
1857 | xp->mark.v = x->mark.v = mark.v; | ||
1828 | ut = nla_data(rt); | 1858 | ut = nla_data(rt); |
1829 | /* extract the templates and for each call km_key */ | 1859 | /* extract the templates and for each call km_key */ |
1830 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { | 1860 | for (i = 0; i < xp->xfrm_nr; i++, ut++) { |
@@ -2084,6 +2114,7 @@ static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { | |||
2084 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, | 2114 | [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, |
2085 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, | 2115 | [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, |
2086 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, | 2116 | [XFRMA_KMADDRESS] = { .len = sizeof(struct xfrm_user_kmaddress) }, |
2117 | [XFRMA_MARK] = { .len = sizeof(struct xfrm_mark) }, | ||
2087 | }; | 2118 | }; |
2088 | 2119 | ||
2089 | static struct xfrm_link { | 2120 | static struct xfrm_link { |
@@ -2163,7 +2194,8 @@ static void xfrm_netlink_rcv(struct sk_buff *skb) | |||
2163 | 2194 | ||
2164 | static inline size_t xfrm_expire_msgsize(void) | 2195 | static inline size_t xfrm_expire_msgsize(void) |
2165 | { | 2196 | { |
2166 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)); | 2197 | return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)) |
2198 | + nla_total_size(sizeof(struct xfrm_mark)); | ||
2167 | } | 2199 | } |
2168 | 2200 | ||
2169 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) | 2201 | static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) |
@@ -2179,7 +2211,13 @@ static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_eve | |||
2179 | copy_to_user_state(x, &ue->state); | 2211 | copy_to_user_state(x, &ue->state); |
2180 | ue->hard = (c->data.hard != 0) ? 1 : 0; | 2212 | ue->hard = (c->data.hard != 0) ? 1 : 0; |
2181 | 2213 | ||
2214 | if (xfrm_mark_put(skb, &x->mark)) | ||
2215 | goto nla_put_failure; | ||
2216 | |||
2182 | return nlmsg_end(skb, nlh); | 2217 | return nlmsg_end(skb, nlh); |
2218 | |||
2219 | nla_put_failure: | ||
2220 | return -EMSGSIZE; | ||
2183 | } | 2221 | } |
2184 | 2222 | ||
2185 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | 2223 | static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) |
@@ -2191,8 +2229,10 @@ static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) | |||
2191 | if (skb == NULL) | 2229 | if (skb == NULL) |
2192 | return -ENOMEM; | 2230 | return -ENOMEM; |
2193 | 2231 | ||
2194 | if (build_expire(skb, x, c) < 0) | 2232 | if (build_expire(skb, x, c) < 0) { |
2195 | BUG(); | 2233 | kfree_skb(skb); |
2234 | return -EMSGSIZE; | ||
2235 | } | ||
2196 | 2236 | ||
2197 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); | 2237 | return nlmsg_multicast(net->xfrm.nlsk, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); |
2198 | } | 2238 | } |
@@ -2280,6 +2320,7 @@ static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) | |||
2280 | if (c->event == XFRM_MSG_DELSA) { | 2320 | if (c->event == XFRM_MSG_DELSA) { |
2281 | len += nla_total_size(headlen); | 2321 | len += nla_total_size(headlen); |
2282 | headlen = sizeof(*id); | 2322 | headlen = sizeof(*id); |
2323 | len += nla_total_size(sizeof(struct xfrm_mark)); | ||
2283 | } | 2324 | } |
2284 | len += NLMSG_ALIGN(headlen); | 2325 | len += NLMSG_ALIGN(headlen); |
2285 | 2326 | ||
@@ -2350,6 +2391,7 @@ static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, | |||
2350 | { | 2391 | { |
2351 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) | 2392 | return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) |
2352 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) | 2393 | + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) |
2394 | + nla_total_size(sizeof(struct xfrm_mark)) | ||
2353 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) | 2395 | + nla_total_size(xfrm_user_sec_ctx_size(x->security)) |
2354 | + userpolicy_type_attrsize(); | 2396 | + userpolicy_type_attrsize(); |
2355 | } | 2397 | } |