11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * net/key/af_key.c An implementation of PF_KEYv2 sockets. 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * This program is free software; you can redistribute it and/or 51da177e4SLinus Torvalds * modify it under the terms of the GNU General Public License 61da177e4SLinus Torvalds * as published by the Free Software Foundation; either version 71da177e4SLinus Torvalds * 2 of the License, or (at your option) any later version. 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds * Authors: Maxim Giryaev <gem@asplinux.ru> 101da177e4SLinus Torvalds * David S. Miller <davem@redhat.com> 111da177e4SLinus Torvalds * Alexey Kuznetsov <kuznet@ms2.inr.ac.ru> 121da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 131da177e4SLinus Torvalds * Kazunori MIYAZAWA / USAGI Project <miyazawa@linux-ipv6.org> 141da177e4SLinus Torvalds * Derek Atkins <derek@ihtfp.com> 151da177e4SLinus Torvalds */ 161da177e4SLinus Torvalds 174fc268d2SRandy Dunlap #include <linux/capability.h> 181da177e4SLinus Torvalds #include <linux/module.h> 191da177e4SLinus Torvalds #include <linux/kernel.h> 201da177e4SLinus Torvalds #include <linux/socket.h> 211da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 221da177e4SLinus Torvalds #include <linux/ipsec.h> 231da177e4SLinus Torvalds #include <linux/skbuff.h> 241da177e4SLinus Torvalds #include <linux/rtnetlink.h> 251da177e4SLinus Torvalds #include <linux/in.h> 261da177e4SLinus Torvalds #include <linux/in6.h> 271da177e4SLinus Torvalds #include <linux/proc_fs.h> 281da177e4SLinus Torvalds #include <linux/init.h> 295a0e3ad6STejun Heo #include <linux/slab.h> 30457c4cbcSEric W. Biederman #include <net/net_namespace.h> 313fa87a32SAlexey Dobriyan #include <net/netns/generic.h> 321da177e4SLinus Torvalds #include <net/xfrm.h> 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #include <net/sock.h> 351da177e4SLinus Torvalds 361da177e4SLinus Torvalds #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) 371da177e4SLinus Torvalds #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) 381da177e4SLinus Torvalds 39f99189b1SEric Dumazet static int pfkey_net_id __read_mostly; 403fa87a32SAlexey Dobriyan struct netns_pfkey { 411da177e4SLinus Torvalds /* List of all pfkey sockets. */ 423fa87a32SAlexey Dobriyan struct hlist_head table; 433fa87a32SAlexey Dobriyan atomic_t socks_nr; 443fa87a32SAlexey Dobriyan }; 457f6b9dbdSstephen hemminger static DEFINE_MUTEX(pfkey_mutex); 461da177e4SLinus Torvalds 47bd55775cSJamal Hadi Salim #define DUMMY_MARK 0 48bd55775cSJamal Hadi Salim static struct xfrm_mark dummy_mark = {0, 0}; 491da177e4SLinus Torvalds struct pfkey_sock { 501da177e4SLinus Torvalds /* struct sock must be the first member of struct pfkey_sock */ 511da177e4SLinus Torvalds struct sock sk; 521da177e4SLinus Torvalds int registered; 531da177e4SLinus Torvalds int promisc; 5483321d6bSTimo Teras 5583321d6bSTimo Teras struct { 5683321d6bSTimo Teras uint8_t msg_version; 5783321d6bSTimo Teras uint32_t msg_pid; 5883321d6bSTimo Teras int (*dump)(struct pfkey_sock *sk); 5983321d6bSTimo Teras void (*done)(struct pfkey_sock *sk); 6083321d6bSTimo Teras union { 6183321d6bSTimo Teras struct xfrm_policy_walk policy; 6283321d6bSTimo Teras struct xfrm_state_walk state; 6383321d6bSTimo Teras } u; 6412a169e7SHerbert Xu struct sk_buff *skb; 6583321d6bSTimo Teras } dump; 661da177e4SLinus Torvalds }; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds static inline struct pfkey_sock *pfkey_sk(struct sock *sk) 691da177e4SLinus Torvalds { 701da177e4SLinus Torvalds return (struct pfkey_sock *)sk; 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 73*4c93fbb0SDavid S. Miller static int pfkey_can_dump(const struct sock *sk) 7483321d6bSTimo Teras { 7583321d6bSTimo Teras if (3 * atomic_read(&sk->sk_rmem_alloc) <= 2 * sk->sk_rcvbuf) 7683321d6bSTimo Teras return 1; 7783321d6bSTimo Teras return 0; 7883321d6bSTimo Teras } 7983321d6bSTimo Teras 8005238204STimo Teras static void pfkey_terminate_dump(struct pfkey_sock *pfk) 8183321d6bSTimo Teras { 8205238204STimo Teras if (pfk->dump.dump) { 8312a169e7SHerbert Xu if (pfk->dump.skb) { 8412a169e7SHerbert Xu kfree_skb(pfk->dump.skb); 8512a169e7SHerbert Xu pfk->dump.skb = NULL; 8612a169e7SHerbert Xu } 8783321d6bSTimo Teras pfk->dump.done(pfk); 8883321d6bSTimo Teras pfk->dump.dump = NULL; 8983321d6bSTimo Teras pfk->dump.done = NULL; 9005238204STimo Teras } 9183321d6bSTimo Teras } 9283321d6bSTimo Teras 931da177e4SLinus Torvalds static void pfkey_sock_destruct(struct sock *sk) 941da177e4SLinus Torvalds { 953fa87a32SAlexey Dobriyan struct net *net = sock_net(sk); 963fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 973fa87a32SAlexey Dobriyan 9805238204STimo Teras pfkey_terminate_dump(pfkey_sk(sk)); 991da177e4SLinus Torvalds skb_queue_purge(&sk->sk_receive_queue); 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) { 102207024b9Sstephen hemminger pr_err("Attempt to release alive pfkey socket: %p\n", sk); 1031da177e4SLinus Torvalds return; 1041da177e4SLinus Torvalds } 1051da177e4SLinus Torvalds 106547b792cSIlpo Järvinen WARN_ON(atomic_read(&sk->sk_rmem_alloc)); 107547b792cSIlpo Järvinen WARN_ON(atomic_read(&sk->sk_wmem_alloc)); 1081da177e4SLinus Torvalds 1093fa87a32SAlexey Dobriyan atomic_dec(&net_pfkey->socks_nr); 1101da177e4SLinus Torvalds } 1111da177e4SLinus Torvalds 11290ddc4f0SEric Dumazet static const struct proto_ops pfkey_ops; 1131da177e4SLinus Torvalds 1141da177e4SLinus Torvalds static void pfkey_insert(struct sock *sk) 1151da177e4SLinus Torvalds { 1163fa87a32SAlexey Dobriyan struct net *net = sock_net(sk); 1173fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 1183fa87a32SAlexey Dobriyan 1197f6b9dbdSstephen hemminger mutex_lock(&pfkey_mutex); 1207f6b9dbdSstephen hemminger sk_add_node_rcu(sk, &net_pfkey->table); 1217f6b9dbdSstephen hemminger mutex_unlock(&pfkey_mutex); 1221da177e4SLinus Torvalds } 1231da177e4SLinus Torvalds 1241da177e4SLinus Torvalds static void pfkey_remove(struct sock *sk) 1251da177e4SLinus Torvalds { 1267f6b9dbdSstephen hemminger mutex_lock(&pfkey_mutex); 1277f6b9dbdSstephen hemminger sk_del_node_init_rcu(sk); 1287f6b9dbdSstephen hemminger mutex_unlock(&pfkey_mutex); 1291da177e4SLinus Torvalds } 1301da177e4SLinus Torvalds 1311da177e4SLinus Torvalds static struct proto key_proto = { 1321da177e4SLinus Torvalds .name = "KEY", 1331da177e4SLinus Torvalds .owner = THIS_MODULE, 1341da177e4SLinus Torvalds .obj_size = sizeof(struct pfkey_sock), 1351da177e4SLinus Torvalds }; 1361da177e4SLinus Torvalds 1373f378b68SEric Paris static int pfkey_create(struct net *net, struct socket *sock, int protocol, 1383f378b68SEric Paris int kern) 1391da177e4SLinus Torvalds { 1403fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 1411da177e4SLinus Torvalds struct sock *sk; 1421da177e4SLinus Torvalds int err; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 1451da177e4SLinus Torvalds return -EPERM; 1461da177e4SLinus Torvalds if (sock->type != SOCK_RAW) 1471da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 1481da177e4SLinus Torvalds if (protocol != PF_KEY_V2) 1491da177e4SLinus Torvalds return -EPROTONOSUPPORT; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds err = -ENOMEM; 1526257ff21SPavel Emelyanov sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto); 1531da177e4SLinus Torvalds if (sk == NULL) 1541da177e4SLinus Torvalds goto out; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds sock->ops = &pfkey_ops; 1571da177e4SLinus Torvalds sock_init_data(sock, sk); 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds sk->sk_family = PF_KEY; 1601da177e4SLinus Torvalds sk->sk_destruct = pfkey_sock_destruct; 1611da177e4SLinus Torvalds 1623fa87a32SAlexey Dobriyan atomic_inc(&net_pfkey->socks_nr); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds pfkey_insert(sk); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds return 0; 1671da177e4SLinus Torvalds out: 1681da177e4SLinus Torvalds return err; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static int pfkey_release(struct socket *sock) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct sock *sk = sock->sk; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds if (!sk) 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds pfkey_remove(sk); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds sock_orphan(sk); 1811da177e4SLinus Torvalds sock->sk = NULL; 1821da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue); 1837f6b9dbdSstephen hemminger 1847f6b9dbdSstephen hemminger synchronize_rcu(); 1851da177e4SLinus Torvalds sock_put(sk); 1861da177e4SLinus Torvalds 1871da177e4SLinus Torvalds return 0; 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds 1901da177e4SLinus Torvalds static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, 191dd0fc66fSAl Viro gfp_t allocation, struct sock *sk) 1921da177e4SLinus Torvalds { 1931da177e4SLinus Torvalds int err = -ENOBUFS; 1941da177e4SLinus Torvalds 1951da177e4SLinus Torvalds sock_hold(sk); 1961da177e4SLinus Torvalds if (*skb2 == NULL) { 1971da177e4SLinus Torvalds if (atomic_read(&skb->users) != 1) { 1981da177e4SLinus Torvalds *skb2 = skb_clone(skb, allocation); 1991da177e4SLinus Torvalds } else { 2001da177e4SLinus Torvalds *skb2 = skb; 2011da177e4SLinus Torvalds atomic_inc(&skb->users); 2021da177e4SLinus Torvalds } 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds if (*skb2 != NULL) { 2051da177e4SLinus Torvalds if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { 2061da177e4SLinus Torvalds skb_orphan(*skb2); 2071da177e4SLinus Torvalds skb_set_owner_r(*skb2, sk); 2081da177e4SLinus Torvalds skb_queue_tail(&sk->sk_receive_queue, *skb2); 2091da177e4SLinus Torvalds sk->sk_data_ready(sk, (*skb2)->len); 2101da177e4SLinus Torvalds *skb2 = NULL; 2111da177e4SLinus Torvalds err = 0; 2121da177e4SLinus Torvalds } 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds sock_put(sk); 2151da177e4SLinus Torvalds return err; 2161da177e4SLinus Torvalds } 2171da177e4SLinus Torvalds 2181da177e4SLinus Torvalds /* Send SKB to all pfkey sockets matching selected criteria. */ 2191da177e4SLinus Torvalds #define BROADCAST_ALL 0 2201da177e4SLinus Torvalds #define BROADCAST_ONE 1 2211da177e4SLinus Torvalds #define BROADCAST_REGISTERED 2 2221da177e4SLinus Torvalds #define BROADCAST_PROMISC_ONLY 4 223dd0fc66fSAl Viro static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, 22407fb0f17SAlexey Dobriyan int broadcast_flags, struct sock *one_sk, 22507fb0f17SAlexey Dobriyan struct net *net) 2261da177e4SLinus Torvalds { 2273fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 2281da177e4SLinus Torvalds struct sock *sk; 2291da177e4SLinus Torvalds struct hlist_node *node; 2301da177e4SLinus Torvalds struct sk_buff *skb2 = NULL; 2311da177e4SLinus Torvalds int err = -ESRCH; 2321da177e4SLinus Torvalds 2331da177e4SLinus Torvalds /* XXX Do we need something like netlink_overrun? I think 2341da177e4SLinus Torvalds * XXX PF_KEY socket apps will not mind current behavior. 2351da177e4SLinus Torvalds */ 2361da177e4SLinus Torvalds if (!skb) 2371da177e4SLinus Torvalds return -ENOMEM; 2381da177e4SLinus Torvalds 2397f6b9dbdSstephen hemminger rcu_read_lock(); 2407f6b9dbdSstephen hemminger sk_for_each_rcu(sk, node, &net_pfkey->table) { 2411da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 2421da177e4SLinus Torvalds int err2; 2431da177e4SLinus Torvalds 2441da177e4SLinus Torvalds /* Yes, it means that if you are meant to receive this 2451da177e4SLinus Torvalds * pfkey message you receive it twice as promiscuous 2461da177e4SLinus Torvalds * socket. 2471da177e4SLinus Torvalds */ 2481da177e4SLinus Torvalds if (pfk->promisc) 2491da177e4SLinus Torvalds pfkey_broadcast_one(skb, &skb2, allocation, sk); 2501da177e4SLinus Torvalds 2511da177e4SLinus Torvalds /* the exact target will be processed later */ 2521da177e4SLinus Torvalds if (sk == one_sk) 2531da177e4SLinus Torvalds continue; 2541da177e4SLinus Torvalds if (broadcast_flags != BROADCAST_ALL) { 2551da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_PROMISC_ONLY) 2561da177e4SLinus Torvalds continue; 2571da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && 2581da177e4SLinus Torvalds !pfk->registered) 2591da177e4SLinus Torvalds continue; 2601da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_ONE) 2611da177e4SLinus Torvalds continue; 2621da177e4SLinus Torvalds } 2631da177e4SLinus Torvalds 2641da177e4SLinus Torvalds err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk); 2651da177e4SLinus Torvalds 2661da177e4SLinus Torvalds /* Error is cleare after succecful sending to at least one 2671da177e4SLinus Torvalds * registered KM */ 2681da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && err) 2691da177e4SLinus Torvalds err = err2; 2701da177e4SLinus Torvalds } 2717f6b9dbdSstephen hemminger rcu_read_unlock(); 2721da177e4SLinus Torvalds 2731da177e4SLinus Torvalds if (one_sk != NULL) 2741da177e4SLinus Torvalds err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); 2751da177e4SLinus Torvalds 2761da177e4SLinus Torvalds kfree_skb(skb2); 2771da177e4SLinus Torvalds kfree_skb(skb); 2781da177e4SLinus Torvalds return err; 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 28105238204STimo Teras static int pfkey_do_dump(struct pfkey_sock *pfk) 28205238204STimo Teras { 28312a169e7SHerbert Xu struct sadb_msg *hdr; 28405238204STimo Teras int rc; 28505238204STimo Teras 28605238204STimo Teras rc = pfk->dump.dump(pfk); 28705238204STimo Teras if (rc == -ENOBUFS) 28805238204STimo Teras return 0; 28905238204STimo Teras 29012a169e7SHerbert Xu if (pfk->dump.skb) { 29112a169e7SHerbert Xu if (!pfkey_can_dump(&pfk->sk)) 29212a169e7SHerbert Xu return 0; 29312a169e7SHerbert Xu 29412a169e7SHerbert Xu hdr = (struct sadb_msg *) pfk->dump.skb->data; 29512a169e7SHerbert Xu hdr->sadb_msg_seq = 0; 29612a169e7SHerbert Xu hdr->sadb_msg_errno = rc; 29712a169e7SHerbert Xu pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, 29807fb0f17SAlexey Dobriyan &pfk->sk, sock_net(&pfk->sk)); 29912a169e7SHerbert Xu pfk->dump.skb = NULL; 30012a169e7SHerbert Xu } 30112a169e7SHerbert Xu 30205238204STimo Teras pfkey_terminate_dump(pfk); 30305238204STimo Teras return rc; 30405238204STimo Teras } 30505238204STimo Teras 306*4c93fbb0SDavid S. Miller static inline void pfkey_hdr_dup(struct sadb_msg *new, 307*4c93fbb0SDavid S. Miller const struct sadb_msg *orig) 3081da177e4SLinus Torvalds { 3091da177e4SLinus Torvalds *new = *orig; 3101da177e4SLinus Torvalds } 3111da177e4SLinus Torvalds 312*4c93fbb0SDavid S. Miller static int pfkey_error(const struct sadb_msg *orig, int err, struct sock *sk) 3131da177e4SLinus Torvalds { 3141da177e4SLinus Torvalds struct sk_buff *skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); 3151da177e4SLinus Torvalds struct sadb_msg *hdr; 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds if (!skb) 3181da177e4SLinus Torvalds return -ENOBUFS; 3191da177e4SLinus Torvalds 3201da177e4SLinus Torvalds /* Woe be to the platform trying to support PFKEY yet 3211da177e4SLinus Torvalds * having normal errnos outside the 1-255 range, inclusive. 3221da177e4SLinus Torvalds */ 3231da177e4SLinus Torvalds err = -err; 3241da177e4SLinus Torvalds if (err == ERESTARTSYS || 3251da177e4SLinus Torvalds err == ERESTARTNOHAND || 3261da177e4SLinus Torvalds err == ERESTARTNOINTR) 3271da177e4SLinus Torvalds err = EINTR; 3281da177e4SLinus Torvalds if (err >= 512) 3291da177e4SLinus Torvalds err = EINVAL; 33009a62660SKris Katterjohn BUG_ON(err <= 0 || err >= 256); 3311da177e4SLinus Torvalds 3321da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 3331da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 3341da177e4SLinus Torvalds hdr->sadb_msg_errno = (uint8_t) err; 3351da177e4SLinus Torvalds hdr->sadb_msg_len = (sizeof(struct sadb_msg) / 3361da177e4SLinus Torvalds sizeof(uint64_t)); 3371da177e4SLinus Torvalds 33807fb0f17SAlexey Dobriyan pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk, sock_net(sk)); 3391da177e4SLinus Torvalds 3401da177e4SLinus Torvalds return 0; 3411da177e4SLinus Torvalds } 3421da177e4SLinus Torvalds 3431da177e4SLinus Torvalds static u8 sadb_ext_min_len[] = { 3441da177e4SLinus Torvalds [SADB_EXT_RESERVED] = (u8) 0, 3451da177e4SLinus Torvalds [SADB_EXT_SA] = (u8) sizeof(struct sadb_sa), 3461da177e4SLinus Torvalds [SADB_EXT_LIFETIME_CURRENT] = (u8) sizeof(struct sadb_lifetime), 3471da177e4SLinus Torvalds [SADB_EXT_LIFETIME_HARD] = (u8) sizeof(struct sadb_lifetime), 3481da177e4SLinus Torvalds [SADB_EXT_LIFETIME_SOFT] = (u8) sizeof(struct sadb_lifetime), 3491da177e4SLinus Torvalds [SADB_EXT_ADDRESS_SRC] = (u8) sizeof(struct sadb_address), 3501da177e4SLinus Torvalds [SADB_EXT_ADDRESS_DST] = (u8) sizeof(struct sadb_address), 3511da177e4SLinus Torvalds [SADB_EXT_ADDRESS_PROXY] = (u8) sizeof(struct sadb_address), 3521da177e4SLinus Torvalds [SADB_EXT_KEY_AUTH] = (u8) sizeof(struct sadb_key), 3531da177e4SLinus Torvalds [SADB_EXT_KEY_ENCRYPT] = (u8) sizeof(struct sadb_key), 3541da177e4SLinus Torvalds [SADB_EXT_IDENTITY_SRC] = (u8) sizeof(struct sadb_ident), 3551da177e4SLinus Torvalds [SADB_EXT_IDENTITY_DST] = (u8) sizeof(struct sadb_ident), 3561da177e4SLinus Torvalds [SADB_EXT_SENSITIVITY] = (u8) sizeof(struct sadb_sens), 3571da177e4SLinus Torvalds [SADB_EXT_PROPOSAL] = (u8) sizeof(struct sadb_prop), 3581da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_AUTH] = (u8) sizeof(struct sadb_supported), 3591da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_ENCRYPT] = (u8) sizeof(struct sadb_supported), 3601da177e4SLinus Torvalds [SADB_EXT_SPIRANGE] = (u8) sizeof(struct sadb_spirange), 3611da177e4SLinus Torvalds [SADB_X_EXT_KMPRIVATE] = (u8) sizeof(struct sadb_x_kmprivate), 3621da177e4SLinus Torvalds [SADB_X_EXT_POLICY] = (u8) sizeof(struct sadb_x_policy), 3631da177e4SLinus Torvalds [SADB_X_EXT_SA2] = (u8) sizeof(struct sadb_x_sa2), 3641da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_TYPE] = (u8) sizeof(struct sadb_x_nat_t_type), 3651da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_SPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3661da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3671da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), 368df71837dSTrent Jaeger [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), 36913c1d189SArnaud Ebalard [SADB_X_EXT_KMADDRESS] = (u8) sizeof(struct sadb_x_kmaddress), 3701da177e4SLinus Torvalds }; 3711da177e4SLinus Torvalds 3721da177e4SLinus Torvalds /* Verify sadb_address_{len,prefixlen} against sa_family. */ 373*4c93fbb0SDavid S. Miller static int verify_address_len(const void *p) 3741da177e4SLinus Torvalds { 375*4c93fbb0SDavid S. Miller const struct sadb_address *sp = p; 376*4c93fbb0SDavid S. Miller const struct sockaddr *addr = (const struct sockaddr *)(sp + 1); 377*4c93fbb0SDavid S. Miller const struct sockaddr_in *sin; 3781da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 379*4c93fbb0SDavid S. Miller const struct sockaddr_in6 *sin6; 3801da177e4SLinus Torvalds #endif 3811da177e4SLinus Torvalds int len; 3821da177e4SLinus Torvalds 3831da177e4SLinus Torvalds switch (addr->sa_family) { 3841da177e4SLinus Torvalds case AF_INET: 385356f89e1SIlpo Järvinen len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t)); 3861da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3871da177e4SLinus Torvalds sp->sadb_address_prefixlen > 32) 3881da177e4SLinus Torvalds return -EINVAL; 3891da177e4SLinus Torvalds break; 3901da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3911da177e4SLinus Torvalds case AF_INET6: 392356f89e1SIlpo Järvinen len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin6), sizeof(uint64_t)); 3931da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3941da177e4SLinus Torvalds sp->sadb_address_prefixlen > 128) 3951da177e4SLinus Torvalds return -EINVAL; 3961da177e4SLinus Torvalds break; 3971da177e4SLinus Torvalds #endif 3981da177e4SLinus Torvalds default: 3991da177e4SLinus Torvalds /* It is user using kernel to keep track of security 4001da177e4SLinus Torvalds * associations for another protocol, such as 4011da177e4SLinus Torvalds * OSPF/RSVP/RIPV2/MIP. It is user's job to verify 4021da177e4SLinus Torvalds * lengths. 4031da177e4SLinus Torvalds * 4041da177e4SLinus Torvalds * XXX Actually, association/policy database is not yet 4051da177e4SLinus Torvalds * XXX able to cope with arbitrary sockaddr families. 4061da177e4SLinus Torvalds * XXX When it can, remove this -EINVAL. -DaveM 4071da177e4SLinus Torvalds */ 4081da177e4SLinus Torvalds return -EINVAL; 4091da177e4SLinus Torvalds break; 4103ff50b79SStephen Hemminger } 4111da177e4SLinus Torvalds 4121da177e4SLinus Torvalds return 0; 4131da177e4SLinus Torvalds } 4141da177e4SLinus Torvalds 415*4c93fbb0SDavid S. Miller static inline int pfkey_sec_ctx_len(const struct sadb_x_sec_ctx *sec_ctx) 416df71837dSTrent Jaeger { 417356f89e1SIlpo Järvinen return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + 418356f89e1SIlpo Järvinen sec_ctx->sadb_x_ctx_len, 419356f89e1SIlpo Järvinen sizeof(uint64_t)); 420df71837dSTrent Jaeger } 421df71837dSTrent Jaeger 422*4c93fbb0SDavid S. Miller static inline int verify_sec_ctx_len(const void *p) 423df71837dSTrent Jaeger { 424*4c93fbb0SDavid S. Miller const struct sadb_x_sec_ctx *sec_ctx = p; 425298bb621SStephen Rothwell int len = sec_ctx->sadb_x_ctx_len; 426df71837dSTrent Jaeger 427298bb621SStephen Rothwell if (len > PAGE_SIZE) 428df71837dSTrent Jaeger return -EINVAL; 429df71837dSTrent Jaeger 430df71837dSTrent Jaeger len = pfkey_sec_ctx_len(sec_ctx); 431df71837dSTrent Jaeger 432df71837dSTrent Jaeger if (sec_ctx->sadb_x_sec_len != len) 433df71837dSTrent Jaeger return -EINVAL; 434df71837dSTrent Jaeger 435df71837dSTrent Jaeger return 0; 436df71837dSTrent Jaeger } 437df71837dSTrent Jaeger 438*4c93fbb0SDavid S. Miller static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(const struct sadb_x_sec_ctx *sec_ctx) 439df71837dSTrent Jaeger { 440df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = NULL; 441df71837dSTrent Jaeger int ctx_size = sec_ctx->sadb_x_ctx_len; 442df71837dSTrent Jaeger 443df71837dSTrent Jaeger uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL); 444df71837dSTrent Jaeger 445df71837dSTrent Jaeger if (!uctx) 446df71837dSTrent Jaeger return NULL; 447df71837dSTrent Jaeger 448df71837dSTrent Jaeger uctx->len = pfkey_sec_ctx_len(sec_ctx); 449df71837dSTrent Jaeger uctx->exttype = sec_ctx->sadb_x_sec_exttype; 450df71837dSTrent Jaeger uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi; 451df71837dSTrent Jaeger uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg; 452df71837dSTrent Jaeger uctx->ctx_len = sec_ctx->sadb_x_ctx_len; 453df71837dSTrent Jaeger memcpy(uctx + 1, sec_ctx + 1, 454df71837dSTrent Jaeger uctx->ctx_len); 455df71837dSTrent Jaeger 456df71837dSTrent Jaeger return uctx; 457df71837dSTrent Jaeger } 458df71837dSTrent Jaeger 459*4c93fbb0SDavid S. Miller static int present_and_same_family(const struct sadb_address *src, 460*4c93fbb0SDavid S. Miller const struct sadb_address *dst) 4611da177e4SLinus Torvalds { 462*4c93fbb0SDavid S. Miller const struct sockaddr *s_addr, *d_addr; 4631da177e4SLinus Torvalds 4641da177e4SLinus Torvalds if (!src || !dst) 4651da177e4SLinus Torvalds return 0; 4661da177e4SLinus Torvalds 467*4c93fbb0SDavid S. Miller s_addr = (const struct sockaddr *)(src + 1); 468*4c93fbb0SDavid S. Miller d_addr = (const struct sockaddr *)(dst + 1); 4691da177e4SLinus Torvalds if (s_addr->sa_family != d_addr->sa_family) 4701da177e4SLinus Torvalds return 0; 4711da177e4SLinus Torvalds if (s_addr->sa_family != AF_INET 4721da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4731da177e4SLinus Torvalds && s_addr->sa_family != AF_INET6 4741da177e4SLinus Torvalds #endif 4751da177e4SLinus Torvalds ) 4761da177e4SLinus Torvalds return 0; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds return 1; 4791da177e4SLinus Torvalds } 4801da177e4SLinus Torvalds 481*4c93fbb0SDavid S. Miller static int parse_exthdrs(struct sk_buff *skb, const struct sadb_msg *hdr, void **ext_hdrs) 4821da177e4SLinus Torvalds { 483*4c93fbb0SDavid S. Miller const char *p = (char *) hdr; 4841da177e4SLinus Torvalds int len = skb->len; 4851da177e4SLinus Torvalds 4861da177e4SLinus Torvalds len -= sizeof(*hdr); 4871da177e4SLinus Torvalds p += sizeof(*hdr); 4881da177e4SLinus Torvalds while (len > 0) { 489*4c93fbb0SDavid S. Miller const struct sadb_ext *ehdr = (const struct sadb_ext *) p; 4901da177e4SLinus Torvalds uint16_t ext_type; 4911da177e4SLinus Torvalds int ext_len; 4921da177e4SLinus Torvalds 4931da177e4SLinus Torvalds ext_len = ehdr->sadb_ext_len; 4941da177e4SLinus Torvalds ext_len *= sizeof(uint64_t); 4951da177e4SLinus Torvalds ext_type = ehdr->sadb_ext_type; 4961da177e4SLinus Torvalds if (ext_len < sizeof(uint64_t) || 4971da177e4SLinus Torvalds ext_len > len || 4981da177e4SLinus Torvalds ext_type == SADB_EXT_RESERVED) 4991da177e4SLinus Torvalds return -EINVAL; 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds if (ext_type <= SADB_EXT_MAX) { 5021da177e4SLinus Torvalds int min = (int) sadb_ext_min_len[ext_type]; 5031da177e4SLinus Torvalds if (ext_len < min) 5041da177e4SLinus Torvalds return -EINVAL; 5051da177e4SLinus Torvalds if (ext_hdrs[ext_type-1] != NULL) 5061da177e4SLinus Torvalds return -EINVAL; 5071da177e4SLinus Torvalds if (ext_type == SADB_EXT_ADDRESS_SRC || 5081da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_DST || 5091da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_PROXY || 5101da177e4SLinus Torvalds ext_type == SADB_X_EXT_NAT_T_OA) { 5111da177e4SLinus Torvalds if (verify_address_len(p)) 5121da177e4SLinus Torvalds return -EINVAL; 5131da177e4SLinus Torvalds } 514df71837dSTrent Jaeger if (ext_type == SADB_X_EXT_SEC_CTX) { 515df71837dSTrent Jaeger if (verify_sec_ctx_len(p)) 516df71837dSTrent Jaeger return -EINVAL; 517df71837dSTrent Jaeger } 518*4c93fbb0SDavid S. Miller ext_hdrs[ext_type-1] = (void *) p; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds p += ext_len; 5211da177e4SLinus Torvalds len -= ext_len; 5221da177e4SLinus Torvalds } 5231da177e4SLinus Torvalds 5241da177e4SLinus Torvalds return 0; 5251da177e4SLinus Torvalds } 5261da177e4SLinus Torvalds 5271da177e4SLinus Torvalds static uint16_t 5281da177e4SLinus Torvalds pfkey_satype2proto(uint8_t satype) 5291da177e4SLinus Torvalds { 5301da177e4SLinus Torvalds switch (satype) { 5311da177e4SLinus Torvalds case SADB_SATYPE_UNSPEC: 5321da177e4SLinus Torvalds return IPSEC_PROTO_ANY; 5331da177e4SLinus Torvalds case SADB_SATYPE_AH: 5341da177e4SLinus Torvalds return IPPROTO_AH; 5351da177e4SLinus Torvalds case SADB_SATYPE_ESP: 5361da177e4SLinus Torvalds return IPPROTO_ESP; 5371da177e4SLinus Torvalds case SADB_X_SATYPE_IPCOMP: 5381da177e4SLinus Torvalds return IPPROTO_COMP; 5391da177e4SLinus Torvalds break; 5401da177e4SLinus Torvalds default: 5411da177e4SLinus Torvalds return 0; 5421da177e4SLinus Torvalds } 5431da177e4SLinus Torvalds /* NOTREACHED */ 5441da177e4SLinus Torvalds } 5451da177e4SLinus Torvalds 5461da177e4SLinus Torvalds static uint8_t 5471da177e4SLinus Torvalds pfkey_proto2satype(uint16_t proto) 5481da177e4SLinus Torvalds { 5491da177e4SLinus Torvalds switch (proto) { 5501da177e4SLinus Torvalds case IPPROTO_AH: 5511da177e4SLinus Torvalds return SADB_SATYPE_AH; 5521da177e4SLinus Torvalds case IPPROTO_ESP: 5531da177e4SLinus Torvalds return SADB_SATYPE_ESP; 5541da177e4SLinus Torvalds case IPPROTO_COMP: 5551da177e4SLinus Torvalds return SADB_X_SATYPE_IPCOMP; 5561da177e4SLinus Torvalds break; 5571da177e4SLinus Torvalds default: 5581da177e4SLinus Torvalds return 0; 5591da177e4SLinus Torvalds } 5601da177e4SLinus Torvalds /* NOTREACHED */ 5611da177e4SLinus Torvalds } 5621da177e4SLinus Torvalds 5631da177e4SLinus Torvalds /* BTW, this scheme means that there is no way with PFKEY2 sockets to 5641da177e4SLinus Torvalds * say specifically 'just raw sockets' as we encode them as 255. 5651da177e4SLinus Torvalds */ 5661da177e4SLinus Torvalds 5671da177e4SLinus Torvalds static uint8_t pfkey_proto_to_xfrm(uint8_t proto) 5681da177e4SLinus Torvalds { 569a02cec21SEric Dumazet return proto == IPSEC_PROTO_ANY ? 0 : proto; 5701da177e4SLinus Torvalds } 5711da177e4SLinus Torvalds 5721da177e4SLinus Torvalds static uint8_t pfkey_proto_from_xfrm(uint8_t proto) 5731da177e4SLinus Torvalds { 574a02cec21SEric Dumazet return proto ? proto : IPSEC_PROTO_ANY; 5751da177e4SLinus Torvalds } 5761da177e4SLinus Torvalds 5779e8b4ed8SYOSHIFUJI Hideaki static inline int pfkey_sockaddr_len(sa_family_t family) 5789e8b4ed8SYOSHIFUJI Hideaki { 5799e8b4ed8SYOSHIFUJI Hideaki switch (family) { 5809e8b4ed8SYOSHIFUJI Hideaki case AF_INET: 5819e8b4ed8SYOSHIFUJI Hideaki return sizeof(struct sockaddr_in); 5829e8b4ed8SYOSHIFUJI Hideaki #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5839e8b4ed8SYOSHIFUJI Hideaki case AF_INET6: 5849e8b4ed8SYOSHIFUJI Hideaki return sizeof(struct sockaddr_in6); 5859e8b4ed8SYOSHIFUJI Hideaki #endif 5869e8b4ed8SYOSHIFUJI Hideaki } 5879e8b4ed8SYOSHIFUJI Hideaki return 0; 5889e8b4ed8SYOSHIFUJI Hideaki } 5899e8b4ed8SYOSHIFUJI Hideaki 5905f95ac91SYOSHIFUJI Hideaki static 5915f95ac91SYOSHIFUJI Hideaki int pfkey_sockaddr_extract(const struct sockaddr *sa, xfrm_address_t *xaddr) 5921da177e4SLinus Torvalds { 5935f95ac91SYOSHIFUJI Hideaki switch (sa->sa_family) { 5941da177e4SLinus Torvalds case AF_INET: 5951da177e4SLinus Torvalds xaddr->a4 = 5965f95ac91SYOSHIFUJI Hideaki ((struct sockaddr_in *)sa)->sin_addr.s_addr; 5971da177e4SLinus Torvalds return AF_INET; 5981da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5991da177e4SLinus Torvalds case AF_INET6: 6001da177e4SLinus Torvalds memcpy(xaddr->a6, 6015f95ac91SYOSHIFUJI Hideaki &((struct sockaddr_in6 *)sa)->sin6_addr, 6021da177e4SLinus Torvalds sizeof(struct in6_addr)); 6031da177e4SLinus Torvalds return AF_INET6; 6041da177e4SLinus Torvalds #endif 6055f95ac91SYOSHIFUJI Hideaki } 6061da177e4SLinus Torvalds return 0; 6071da177e4SLinus Torvalds } 6085f95ac91SYOSHIFUJI Hideaki 6095f95ac91SYOSHIFUJI Hideaki static 610*4c93fbb0SDavid S. Miller int pfkey_sadb_addr2xfrm_addr(const struct sadb_address *addr, xfrm_address_t *xaddr) 6115f95ac91SYOSHIFUJI Hideaki { 6125f95ac91SYOSHIFUJI Hideaki return pfkey_sockaddr_extract((struct sockaddr *)(addr + 1), 6135f95ac91SYOSHIFUJI Hideaki xaddr); 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds 616*4c93fbb0SDavid S. Miller static struct xfrm_state *pfkey_xfrm_state_lookup(struct net *net, const struct sadb_msg *hdr, void * const *ext_hdrs) 6171da177e4SLinus Torvalds { 618*4c93fbb0SDavid S. Miller const struct sadb_sa *sa; 619*4c93fbb0SDavid S. Miller const struct sadb_address *addr; 6201da177e4SLinus Torvalds uint16_t proto; 6211da177e4SLinus Torvalds unsigned short family; 6221da177e4SLinus Torvalds xfrm_address_t *xaddr; 6231da177e4SLinus Torvalds 624*4c93fbb0SDavid S. Miller sa = (const struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 6251da177e4SLinus Torvalds if (sa == NULL) 6261da177e4SLinus Torvalds return NULL; 6271da177e4SLinus Torvalds 6281da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 6291da177e4SLinus Torvalds if (proto == 0) 6301da177e4SLinus Torvalds return NULL; 6311da177e4SLinus Torvalds 6321da177e4SLinus Torvalds /* sadb_address_len should be checked by caller */ 633*4c93fbb0SDavid S. Miller addr = (const struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 6341da177e4SLinus Torvalds if (addr == NULL) 6351da177e4SLinus Torvalds return NULL; 6361da177e4SLinus Torvalds 637*4c93fbb0SDavid S. Miller family = ((const struct sockaddr *)(addr + 1))->sa_family; 6381da177e4SLinus Torvalds switch (family) { 6391da177e4SLinus Torvalds case AF_INET: 640*4c93fbb0SDavid S. Miller xaddr = (xfrm_address_t *)&((const struct sockaddr_in *)(addr + 1))->sin_addr; 6411da177e4SLinus Torvalds break; 6421da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6431da177e4SLinus Torvalds case AF_INET6: 644*4c93fbb0SDavid S. Miller xaddr = (xfrm_address_t *)&((const struct sockaddr_in6 *)(addr + 1))->sin6_addr; 6451da177e4SLinus Torvalds break; 6461da177e4SLinus Torvalds #endif 6471da177e4SLinus Torvalds default: 6481da177e4SLinus Torvalds xaddr = NULL; 6491da177e4SLinus Torvalds } 6501da177e4SLinus Torvalds 6511da177e4SLinus Torvalds if (!xaddr) 6521da177e4SLinus Torvalds return NULL; 6531da177e4SLinus Torvalds 654bd55775cSJamal Hadi Salim return xfrm_state_lookup(net, DUMMY_MARK, xaddr, sa->sadb_sa_spi, proto, family); 6551da177e4SLinus Torvalds } 6561da177e4SLinus Torvalds 6571da177e4SLinus Torvalds #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) 6589e8b4ed8SYOSHIFUJI Hideaki 6591da177e4SLinus Torvalds static int 6601da177e4SLinus Torvalds pfkey_sockaddr_size(sa_family_t family) 6611da177e4SLinus Torvalds { 6629e8b4ed8SYOSHIFUJI Hideaki return PFKEY_ALIGN8(pfkey_sockaddr_len(family)); 6631da177e4SLinus Torvalds } 6641da177e4SLinus Torvalds 66555569ce2SKazunori MIYAZAWA static inline int pfkey_mode_from_xfrm(int mode) 66655569ce2SKazunori MIYAZAWA { 66755569ce2SKazunori MIYAZAWA switch(mode) { 66855569ce2SKazunori MIYAZAWA case XFRM_MODE_TRANSPORT: 66955569ce2SKazunori MIYAZAWA return IPSEC_MODE_TRANSPORT; 67055569ce2SKazunori MIYAZAWA case XFRM_MODE_TUNNEL: 67155569ce2SKazunori MIYAZAWA return IPSEC_MODE_TUNNEL; 67255569ce2SKazunori MIYAZAWA case XFRM_MODE_BEET: 67355569ce2SKazunori MIYAZAWA return IPSEC_MODE_BEET; 67455569ce2SKazunori MIYAZAWA default: 67555569ce2SKazunori MIYAZAWA return -1; 67655569ce2SKazunori MIYAZAWA } 67755569ce2SKazunori MIYAZAWA } 67855569ce2SKazunori MIYAZAWA 67955569ce2SKazunori MIYAZAWA static inline int pfkey_mode_to_xfrm(int mode) 68055569ce2SKazunori MIYAZAWA { 68155569ce2SKazunori MIYAZAWA switch(mode) { 68255569ce2SKazunori MIYAZAWA case IPSEC_MODE_ANY: /*XXX*/ 68355569ce2SKazunori MIYAZAWA case IPSEC_MODE_TRANSPORT: 68455569ce2SKazunori MIYAZAWA return XFRM_MODE_TRANSPORT; 68555569ce2SKazunori MIYAZAWA case IPSEC_MODE_TUNNEL: 68655569ce2SKazunori MIYAZAWA return XFRM_MODE_TUNNEL; 68755569ce2SKazunori MIYAZAWA case IPSEC_MODE_BEET: 68855569ce2SKazunori MIYAZAWA return XFRM_MODE_BEET; 68955569ce2SKazunori MIYAZAWA default: 69055569ce2SKazunori MIYAZAWA return -1; 69155569ce2SKazunori MIYAZAWA } 69255569ce2SKazunori MIYAZAWA } 69355569ce2SKazunori MIYAZAWA 694183cad12SDavid S. Miller static unsigned int pfkey_sockaddr_fill(const xfrm_address_t *xaddr, __be16 port, 695e5b56652SYOSHIFUJI Hideaki struct sockaddr *sa, 696e5b56652SYOSHIFUJI Hideaki unsigned short family) 697e5b56652SYOSHIFUJI Hideaki { 698e5b56652SYOSHIFUJI Hideaki switch (family) { 699e5b56652SYOSHIFUJI Hideaki case AF_INET: 700e5b56652SYOSHIFUJI Hideaki { 701e5b56652SYOSHIFUJI Hideaki struct sockaddr_in *sin = (struct sockaddr_in *)sa; 702e5b56652SYOSHIFUJI Hideaki sin->sin_family = AF_INET; 703e5b56652SYOSHIFUJI Hideaki sin->sin_port = port; 704e5b56652SYOSHIFUJI Hideaki sin->sin_addr.s_addr = xaddr->a4; 705e5b56652SYOSHIFUJI Hideaki memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 706e5b56652SYOSHIFUJI Hideaki return 32; 707e5b56652SYOSHIFUJI Hideaki } 708e5b56652SYOSHIFUJI Hideaki #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 709e5b56652SYOSHIFUJI Hideaki case AF_INET6: 710e5b56652SYOSHIFUJI Hideaki { 711e5b56652SYOSHIFUJI Hideaki struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa; 712e5b56652SYOSHIFUJI Hideaki sin6->sin6_family = AF_INET6; 713e5b56652SYOSHIFUJI Hideaki sin6->sin6_port = port; 714e5b56652SYOSHIFUJI Hideaki sin6->sin6_flowinfo = 0; 715e5b56652SYOSHIFUJI Hideaki ipv6_addr_copy(&sin6->sin6_addr, (struct in6_addr *)xaddr->a6); 716e5b56652SYOSHIFUJI Hideaki sin6->sin6_scope_id = 0; 717e5b56652SYOSHIFUJI Hideaki return 128; 718e5b56652SYOSHIFUJI Hideaki } 719e5b56652SYOSHIFUJI Hideaki #endif 720e5b56652SYOSHIFUJI Hideaki } 721e5b56652SYOSHIFUJI Hideaki return 0; 722e5b56652SYOSHIFUJI Hideaki } 723e5b56652SYOSHIFUJI Hideaki 724*4c93fbb0SDavid S. Miller static struct sk_buff *__pfkey_xfrm_state2msg(const struct xfrm_state *x, 725050f009eSHerbert Xu int add_keys, int hsc) 7261da177e4SLinus Torvalds { 7271da177e4SLinus Torvalds struct sk_buff *skb; 7281da177e4SLinus Torvalds struct sadb_msg *hdr; 7291da177e4SLinus Torvalds struct sadb_sa *sa; 7301da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 7311da177e4SLinus Torvalds struct sadb_address *addr; 7321da177e4SLinus Torvalds struct sadb_key *key; 7331da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 734df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 735df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 736df71837dSTrent Jaeger int ctx_size = 0; 7371da177e4SLinus Torvalds int size; 7381da177e4SLinus Torvalds int auth_key_size = 0; 7391da177e4SLinus Torvalds int encrypt_key_size = 0; 7401da177e4SLinus Torvalds int sockaddr_size; 7411da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 74255569ce2SKazunori MIYAZAWA int mode; 7431da177e4SLinus Torvalds 7441da177e4SLinus Torvalds /* address family check */ 7451da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 7461da177e4SLinus Torvalds if (!sockaddr_size) 7471da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 7481da177e4SLinus Torvalds 7491da177e4SLinus Torvalds /* base, SA, (lifetime (HSC),) address(SD), (address(P),) 7501da177e4SLinus Torvalds key(AE), (identity(SD),) (sensitivity)> */ 7511da177e4SLinus Torvalds size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) + 7521da177e4SLinus Torvalds sizeof(struct sadb_lifetime) + 7531da177e4SLinus Torvalds ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) + 7541da177e4SLinus Torvalds ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) + 7551da177e4SLinus Torvalds sizeof(struct sadb_address)*2 + 7561da177e4SLinus Torvalds sockaddr_size*2 + 7571da177e4SLinus Torvalds sizeof(struct sadb_x_sa2); 758df71837dSTrent Jaeger 759df71837dSTrent Jaeger if ((xfrm_ctx = x->security)) { 760df71837dSTrent Jaeger ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 761df71837dSTrent Jaeger size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 762df71837dSTrent Jaeger } 763df71837dSTrent Jaeger 7641da177e4SLinus Torvalds /* identity & sensitivity */ 76581b302a3SYOSHIFUJI Hideaki if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, x->props.family)) 7661da177e4SLinus Torvalds size += sizeof(struct sadb_address) + sockaddr_size; 7671da177e4SLinus Torvalds 7681da177e4SLinus Torvalds if (add_keys) { 7691da177e4SLinus Torvalds if (x->aalg && x->aalg->alg_key_len) { 7701da177e4SLinus Torvalds auth_key_size = 7711da177e4SLinus Torvalds PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8); 7721da177e4SLinus Torvalds size += sizeof(struct sadb_key) + auth_key_size; 7731da177e4SLinus Torvalds } 7741da177e4SLinus Torvalds if (x->ealg && x->ealg->alg_key_len) { 7751da177e4SLinus Torvalds encrypt_key_size = 7761da177e4SLinus Torvalds PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8); 7771da177e4SLinus Torvalds size += sizeof(struct sadb_key) + encrypt_key_size; 7781da177e4SLinus Torvalds } 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds if (x->encap) 7811da177e4SLinus Torvalds natt = x->encap; 7821da177e4SLinus Torvalds 7831da177e4SLinus Torvalds if (natt && natt->encap_type) { 7841da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_type); 7851da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7861da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7871da177e4SLinus Torvalds } 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 7901da177e4SLinus Torvalds if (skb == NULL) 7911da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 7921da177e4SLinus Torvalds 7931da177e4SLinus Torvalds /* call should fill header later */ 7941da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 7951da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 7961da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 7971da177e4SLinus Torvalds 7981da177e4SLinus Torvalds /* sa */ 7991da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 8001da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 8011da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 8021da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 8031da177e4SLinus Torvalds sa->sadb_sa_replay = x->props.replay_window; 8044f09f0bbSHerbert Xu switch (x->km.state) { 8054f09f0bbSHerbert Xu case XFRM_STATE_VALID: 8064f09f0bbSHerbert Xu sa->sadb_sa_state = x->km.dying ? 8074f09f0bbSHerbert Xu SADB_SASTATE_DYING : SADB_SASTATE_MATURE; 8084f09f0bbSHerbert Xu break; 8094f09f0bbSHerbert Xu case XFRM_STATE_ACQ: 8101da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_LARVAL; 8114f09f0bbSHerbert Xu break; 8124f09f0bbSHerbert Xu default: 8131da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_DEAD; 8144f09f0bbSHerbert Xu break; 8154f09f0bbSHerbert Xu } 8161da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 8171da177e4SLinus Torvalds if (x->aalg) { 8181da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 8191da177e4SLinus Torvalds sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0; 8201da177e4SLinus Torvalds } 8211da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 8221da177e4SLinus Torvalds BUG_ON(x->ealg && x->calg); 8231da177e4SLinus Torvalds if (x->ealg) { 8241da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0); 8251da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 8261da177e4SLinus Torvalds } 8271da177e4SLinus Torvalds /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */ 8281da177e4SLinus Torvalds if (x->calg) { 8291da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0); 8301da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 8311da177e4SLinus Torvalds } 8321da177e4SLinus Torvalds 8331da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 8341da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_NOECN) 8351da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; 8361da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_DECAP_DSCP) 8371da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; 838dd87147eSHerbert Xu if (x->props.flags & XFRM_STATE_NOPMTUDISC) 839dd87147eSHerbert Xu sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; 8401da177e4SLinus Torvalds 8411da177e4SLinus Torvalds /* hard time */ 8421da177e4SLinus Torvalds if (hsc & 2) { 8431da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8441da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8451da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8461da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8471da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 8481da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.hard_packet_limit); 8491da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit); 8501da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds; 8511da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds /* soft time */ 8541da177e4SLinus Torvalds if (hsc & 1) { 8551da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8561da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8571da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8581da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8591da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 8601da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.soft_packet_limit); 8611da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit); 8621da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds; 8631da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds; 8641da177e4SLinus Torvalds } 8651da177e4SLinus Torvalds /* current time */ 8661da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8671da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8681da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8691da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8701da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 8711da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = x->curlft.packets; 8721da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = x->curlft.bytes; 8731da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->curlft.add_time; 8741da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->curlft.use_time; 8751da177e4SLinus Torvalds /* src address */ 8761da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8771da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8781da177e4SLinus Torvalds addr->sadb_address_len = 8791da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8801da177e4SLinus Torvalds sizeof(uint64_t); 8811da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 8821da177e4SLinus Torvalds /* "if the ports are non-zero, then the sadb_address_proto field, 8831da177e4SLinus Torvalds normally zero, MUST be filled in with the transport 8841da177e4SLinus Torvalds protocol's number." - RFC2367 */ 8851da177e4SLinus Torvalds addr->sadb_address_proto = 0; 8861da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8871da177e4SLinus Torvalds 888e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 889e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->props.saddr, 0, 890e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 891e5b56652SYOSHIFUJI Hideaki x->props.family); 892e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 8931da177e4SLinus Torvalds BUG(); 8941da177e4SLinus Torvalds 8951da177e4SLinus Torvalds /* dst address */ 8961da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8971da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8981da177e4SLinus Torvalds addr->sadb_address_len = 8991da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 9001da177e4SLinus Torvalds sizeof(uint64_t); 9011da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 9021da177e4SLinus Torvalds addr->sadb_address_proto = 0; 9031da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 9041da177e4SLinus Torvalds 905e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 906e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->id.daddr, 0, 907e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 908e5b56652SYOSHIFUJI Hideaki x->props.family); 909e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 9101da177e4SLinus Torvalds BUG(); 9111da177e4SLinus Torvalds 912e5b56652SYOSHIFUJI Hideaki if (xfrm_addr_cmp(&x->sel.saddr, &x->props.saddr, 913e5b56652SYOSHIFUJI Hideaki x->props.family)) { 914e5b56652SYOSHIFUJI Hideaki addr = (struct sadb_address*) skb_put(skb, 915e5b56652SYOSHIFUJI Hideaki sizeof(struct sadb_address)+sockaddr_size); 916e5b56652SYOSHIFUJI Hideaki addr->sadb_address_len = 917e5b56652SYOSHIFUJI Hideaki (sizeof(struct sadb_address)+sockaddr_size)/ 918e5b56652SYOSHIFUJI Hideaki sizeof(uint64_t); 919e5b56652SYOSHIFUJI Hideaki addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 920e5b56652SYOSHIFUJI Hideaki addr->sadb_address_proto = 921e5b56652SYOSHIFUJI Hideaki pfkey_proto_from_xfrm(x->sel.proto); 922e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = x->sel.prefixlen_s; 923e5b56652SYOSHIFUJI Hideaki addr->sadb_address_reserved = 0; 924e5b56652SYOSHIFUJI Hideaki 925e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->sel.saddr, x->sel.sport, 926e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 927e5b56652SYOSHIFUJI Hideaki x->props.family); 928e5b56652SYOSHIFUJI Hideaki } 929e5b56652SYOSHIFUJI Hideaki 9301da177e4SLinus Torvalds /* auth key */ 9311da177e4SLinus Torvalds if (add_keys && auth_key_size) { 9321da177e4SLinus Torvalds key = (struct sadb_key *) skb_put(skb, 9331da177e4SLinus Torvalds sizeof(struct sadb_key)+auth_key_size); 9341da177e4SLinus Torvalds key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) / 9351da177e4SLinus Torvalds sizeof(uint64_t); 9361da177e4SLinus Torvalds key->sadb_key_exttype = SADB_EXT_KEY_AUTH; 9371da177e4SLinus Torvalds key->sadb_key_bits = x->aalg->alg_key_len; 9381da177e4SLinus Torvalds key->sadb_key_reserved = 0; 9391da177e4SLinus Torvalds memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8); 9401da177e4SLinus Torvalds } 9411da177e4SLinus Torvalds /* encrypt key */ 9421da177e4SLinus Torvalds if (add_keys && encrypt_key_size) { 9431da177e4SLinus Torvalds key = (struct sadb_key *) skb_put(skb, 9441da177e4SLinus Torvalds sizeof(struct sadb_key)+encrypt_key_size); 9451da177e4SLinus Torvalds key->sadb_key_len = (sizeof(struct sadb_key) + 9461da177e4SLinus Torvalds encrypt_key_size) / sizeof(uint64_t); 9471da177e4SLinus Torvalds key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 9481da177e4SLinus Torvalds key->sadb_key_bits = x->ealg->alg_key_len; 9491da177e4SLinus Torvalds key->sadb_key_reserved = 0; 9501da177e4SLinus Torvalds memcpy(key + 1, x->ealg->alg_key, 9511da177e4SLinus Torvalds (x->ealg->alg_key_len+7)/8); 9521da177e4SLinus Torvalds } 9531da177e4SLinus Torvalds 9541da177e4SLinus Torvalds /* sa */ 9551da177e4SLinus Torvalds sa2 = (struct sadb_x_sa2 *) skb_put(skb, sizeof(struct sadb_x_sa2)); 9561da177e4SLinus Torvalds sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t); 9571da177e4SLinus Torvalds sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; 95855569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) { 95955569ce2SKazunori MIYAZAWA kfree_skb(skb); 96055569ce2SKazunori MIYAZAWA return ERR_PTR(-EINVAL); 96155569ce2SKazunori MIYAZAWA } 96255569ce2SKazunori MIYAZAWA sa2->sadb_x_sa2_mode = mode; 9631da177e4SLinus Torvalds sa2->sadb_x_sa2_reserved1 = 0; 9641da177e4SLinus Torvalds sa2->sadb_x_sa2_reserved2 = 0; 9651da177e4SLinus Torvalds sa2->sadb_x_sa2_sequence = 0; 9661da177e4SLinus Torvalds sa2->sadb_x_sa2_reqid = x->props.reqid; 9671da177e4SLinus Torvalds 9681da177e4SLinus Torvalds if (natt && natt->encap_type) { 9691da177e4SLinus Torvalds struct sadb_x_nat_t_type *n_type; 9701da177e4SLinus Torvalds struct sadb_x_nat_t_port *n_port; 9711da177e4SLinus Torvalds 9721da177e4SLinus Torvalds /* type */ 9731da177e4SLinus Torvalds n_type = (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type)); 9741da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_len = sizeof(*n_type)/sizeof(uint64_t); 9751da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; 9761da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_type = natt->encap_type; 9771da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[0] = 0; 9781da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[1] = 0; 9791da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[2] = 0; 9801da177e4SLinus Torvalds 9811da177e4SLinus Torvalds /* source port */ 9821da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 9831da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 9841da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; 9851da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_sport; 9861da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 9871da177e4SLinus Torvalds 9881da177e4SLinus Torvalds /* dest port */ 9891da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 9901da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 9911da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; 9921da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_dport; 9931da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 9941da177e4SLinus Torvalds } 9951da177e4SLinus Torvalds 996df71837dSTrent Jaeger /* security context */ 997df71837dSTrent Jaeger if (xfrm_ctx) { 998df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, 999df71837dSTrent Jaeger sizeof(struct sadb_x_sec_ctx) + ctx_size); 1000df71837dSTrent Jaeger sec_ctx->sadb_x_sec_len = 1001df71837dSTrent Jaeger (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); 1002df71837dSTrent Jaeger sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 1003df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 1004df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 1005df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 1006df71837dSTrent Jaeger memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 1007df71837dSTrent Jaeger xfrm_ctx->ctx_len); 1008df71837dSTrent Jaeger } 1009df71837dSTrent Jaeger 10101da177e4SLinus Torvalds return skb; 10111da177e4SLinus Torvalds } 10121da177e4SLinus Torvalds 1013050f009eSHerbert Xu 1014*4c93fbb0SDavid S. Miller static inline struct sk_buff *pfkey_xfrm_state2msg(const struct xfrm_state *x) 1015050f009eSHerbert Xu { 1016050f009eSHerbert Xu struct sk_buff *skb; 1017050f009eSHerbert Xu 1018050f009eSHerbert Xu skb = __pfkey_xfrm_state2msg(x, 1, 3); 1019050f009eSHerbert Xu 1020050f009eSHerbert Xu return skb; 1021050f009eSHerbert Xu } 1022050f009eSHerbert Xu 1023*4c93fbb0SDavid S. Miller static inline struct sk_buff *pfkey_xfrm_state2msg_expire(const struct xfrm_state *x, 1024050f009eSHerbert Xu int hsc) 1025050f009eSHerbert Xu { 1026050f009eSHerbert Xu return __pfkey_xfrm_state2msg(x, 0, hsc); 1027050f009eSHerbert Xu } 1028050f009eSHerbert Xu 102907fb0f17SAlexey Dobriyan static struct xfrm_state * pfkey_msg2xfrm_state(struct net *net, 1030*4c93fbb0SDavid S. Miller const struct sadb_msg *hdr, 1031*4c93fbb0SDavid S. Miller void * const *ext_hdrs) 10321da177e4SLinus Torvalds { 10331da177e4SLinus Torvalds struct xfrm_state *x; 1034*4c93fbb0SDavid S. Miller const struct sadb_lifetime *lifetime; 1035*4c93fbb0SDavid S. Miller const struct sadb_sa *sa; 1036*4c93fbb0SDavid S. Miller const struct sadb_key *key; 1037*4c93fbb0SDavid S. Miller const struct sadb_x_sec_ctx *sec_ctx; 10381da177e4SLinus Torvalds uint16_t proto; 10391da177e4SLinus Torvalds int err; 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds 1042*4c93fbb0SDavid S. Miller sa = (const struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 10431da177e4SLinus Torvalds if (!sa || 10441da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 10451da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 10461da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10471da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_ESP && 10481da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]) 10491da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10501da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_AH && 10511da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_AUTH-1]) 10521da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10531da177e4SLinus Torvalds if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] != 10541da177e4SLinus Torvalds !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) 10551da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10561da177e4SLinus Torvalds 10571da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 10581da177e4SLinus Torvalds if (proto == 0) 10591da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10601da177e4SLinus Torvalds 10611da177e4SLinus Torvalds /* default error is no buffer space */ 10621da177e4SLinus Torvalds err = -ENOBUFS; 10631da177e4SLinus Torvalds 10641da177e4SLinus Torvalds /* RFC2367: 10651da177e4SLinus Torvalds 10661da177e4SLinus Torvalds Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message. 10671da177e4SLinus Torvalds SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not 10681da177e4SLinus Torvalds sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state. 10691da177e4SLinus Torvalds Therefore, the sadb_sa_state field of all submitted SAs MUST be 10701da177e4SLinus Torvalds SADB_SASTATE_MATURE and the kernel MUST return an error if this is 10711da177e4SLinus Torvalds not true. 10721da177e4SLinus Torvalds 10731da177e4SLinus Torvalds However, KAME setkey always uses SADB_SASTATE_LARVAL. 10741da177e4SLinus Torvalds Hence, we have to _ignore_ sadb_sa_state, which is also reasonable. 10751da177e4SLinus Torvalds */ 10761da177e4SLinus Torvalds if (sa->sadb_sa_auth > SADB_AALG_MAX || 10771da177e4SLinus Torvalds (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP && 10781da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_X_CALG_MAX) || 10791da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_EALG_MAX) 10801da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 1081*4c93fbb0SDavid S. Miller key = (const struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 10821da177e4SLinus Torvalds if (key != NULL && 10831da177e4SLinus Torvalds sa->sadb_sa_auth != SADB_X_AALG_NULL && 10841da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10851da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10861da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10871da177e4SLinus Torvalds key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 10881da177e4SLinus Torvalds if (key != NULL && 10891da177e4SLinus Torvalds sa->sadb_sa_encrypt != SADB_EALG_NULL && 10901da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10911da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10921da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10931da177e4SLinus Torvalds 109407fb0f17SAlexey Dobriyan x = xfrm_state_alloc(net); 10951da177e4SLinus Torvalds if (x == NULL) 10961da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 10971da177e4SLinus Torvalds 10981da177e4SLinus Torvalds x->id.proto = proto; 10991da177e4SLinus Torvalds x->id.spi = sa->sadb_sa_spi; 11001da177e4SLinus Torvalds x->props.replay_window = sa->sadb_sa_replay; 11011da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN) 11021da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_NOECN; 11031da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) 11041da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_DECAP_DSCP; 1105dd87147eSHerbert Xu if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC) 1106dd87147eSHerbert Xu x->props.flags |= XFRM_STATE_NOPMTUDISC; 11071da177e4SLinus Torvalds 1108*4c93fbb0SDavid S. Miller lifetime = (const struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; 11091da177e4SLinus Torvalds if (lifetime != NULL) { 11101da177e4SLinus Torvalds x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 11111da177e4SLinus Torvalds x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 11121da177e4SLinus Torvalds x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 11131da177e4SLinus Torvalds x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11141da177e4SLinus Torvalds } 1115*4c93fbb0SDavid S. Miller lifetime = (const struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]; 11161da177e4SLinus Torvalds if (lifetime != NULL) { 11171da177e4SLinus Torvalds x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 11181da177e4SLinus Torvalds x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 11191da177e4SLinus Torvalds x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 11201da177e4SLinus Torvalds x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11211da177e4SLinus Torvalds } 1122df71837dSTrent Jaeger 1123*4c93fbb0SDavid S. Miller sec_ctx = (const struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 1124df71837dSTrent Jaeger if (sec_ctx != NULL) { 1125df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 1126df71837dSTrent Jaeger 1127df71837dSTrent Jaeger if (!uctx) 1128df71837dSTrent Jaeger goto out; 1129df71837dSTrent Jaeger 1130df71837dSTrent Jaeger err = security_xfrm_state_alloc(x, uctx); 1131df71837dSTrent Jaeger kfree(uctx); 1132df71837dSTrent Jaeger 1133df71837dSTrent Jaeger if (err) 1134df71837dSTrent Jaeger goto out; 1135df71837dSTrent Jaeger } 1136df71837dSTrent Jaeger 1137*4c93fbb0SDavid S. Miller key = (const struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 11381da177e4SLinus Torvalds if (sa->sadb_sa_auth) { 11391da177e4SLinus Torvalds int keysize = 0; 11401da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth); 11411da177e4SLinus Torvalds if (!a) { 11421da177e4SLinus Torvalds err = -ENOSYS; 11431da177e4SLinus Torvalds goto out; 11441da177e4SLinus Torvalds } 11451da177e4SLinus Torvalds if (key) 11461da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11471da177e4SLinus Torvalds x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); 11481da177e4SLinus Torvalds if (!x->aalg) 11491da177e4SLinus Torvalds goto out; 11501da177e4SLinus Torvalds strcpy(x->aalg->alg_name, a->name); 11511da177e4SLinus Torvalds x->aalg->alg_key_len = 0; 11521da177e4SLinus Torvalds if (key) { 11531da177e4SLinus Torvalds x->aalg->alg_key_len = key->sadb_key_bits; 11541da177e4SLinus Torvalds memcpy(x->aalg->alg_key, key+1, keysize); 11551da177e4SLinus Torvalds } 1156c20a66f4SMartin Willi x->aalg->alg_trunc_len = a->uinfo.auth.icv_truncbits; 11571da177e4SLinus Torvalds x->props.aalgo = sa->sadb_sa_auth; 11581da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11591da177e4SLinus Torvalds } 11601da177e4SLinus Torvalds if (sa->sadb_sa_encrypt) { 11611da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { 11621da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt); 11631da177e4SLinus Torvalds if (!a) { 11641da177e4SLinus Torvalds err = -ENOSYS; 11651da177e4SLinus Torvalds goto out; 11661da177e4SLinus Torvalds } 11671da177e4SLinus Torvalds x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL); 11681da177e4SLinus Torvalds if (!x->calg) 11691da177e4SLinus Torvalds goto out; 11701da177e4SLinus Torvalds strcpy(x->calg->alg_name, a->name); 11711da177e4SLinus Torvalds x->props.calgo = sa->sadb_sa_encrypt; 11721da177e4SLinus Torvalds } else { 11731da177e4SLinus Torvalds int keysize = 0; 11741da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt); 11751da177e4SLinus Torvalds if (!a) { 11761da177e4SLinus Torvalds err = -ENOSYS; 11771da177e4SLinus Torvalds goto out; 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 11801da177e4SLinus Torvalds if (key) 11811da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11821da177e4SLinus Torvalds x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); 11831da177e4SLinus Torvalds if (!x->ealg) 11841da177e4SLinus Torvalds goto out; 11851da177e4SLinus Torvalds strcpy(x->ealg->alg_name, a->name); 11861da177e4SLinus Torvalds x->ealg->alg_key_len = 0; 11871da177e4SLinus Torvalds if (key) { 11881da177e4SLinus Torvalds x->ealg->alg_key_len = key->sadb_key_bits; 11891da177e4SLinus Torvalds memcpy(x->ealg->alg_key, key+1, keysize); 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds x->props.ealgo = sa->sadb_sa_encrypt; 11921da177e4SLinus Torvalds } 11931da177e4SLinus Torvalds } 11941da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11951da177e4SLinus Torvalds 11961da177e4SLinus Torvalds x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 11971da177e4SLinus Torvalds &x->props.saddr); 11981da177e4SLinus Torvalds if (!x->props.family) { 11991da177e4SLinus Torvalds err = -EAFNOSUPPORT; 12001da177e4SLinus Torvalds goto out; 12011da177e4SLinus Torvalds } 12021da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 12031da177e4SLinus Torvalds &x->id.daddr); 12041da177e4SLinus Torvalds 12051da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_SA2-1]) { 1206*4c93fbb0SDavid S. Miller const struct sadb_x_sa2 *sa2 = ext_hdrs[SADB_X_EXT_SA2-1]; 120755569ce2SKazunori MIYAZAWA int mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 120855569ce2SKazunori MIYAZAWA if (mode < 0) { 120955569ce2SKazunori MIYAZAWA err = -EINVAL; 121055569ce2SKazunori MIYAZAWA goto out; 121155569ce2SKazunori MIYAZAWA } 121255569ce2SKazunori MIYAZAWA x->props.mode = mode; 12131da177e4SLinus Torvalds x->props.reqid = sa2->sadb_x_sa2_reqid; 12141da177e4SLinus Torvalds } 12151da177e4SLinus Torvalds 12161da177e4SLinus Torvalds if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) { 1217*4c93fbb0SDavid S. Miller const struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]; 12181da177e4SLinus Torvalds 12191da177e4SLinus Torvalds /* Nobody uses this, but we try. */ 12201da177e4SLinus Torvalds x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr); 12211da177e4SLinus Torvalds x->sel.prefixlen_s = addr->sadb_address_prefixlen; 12221da177e4SLinus Torvalds } 12231da177e4SLinus Torvalds 12244da51056SKazunori MIYAZAWA if (!x->sel.family) 12254a4b6271SJoy Latten x->sel.family = x->props.family; 12264a4b6271SJoy Latten 12271da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { 1228*4c93fbb0SDavid S. Miller const struct sadb_x_nat_t_type* n_type; 12291da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt; 12301da177e4SLinus Torvalds 12311da177e4SLinus Torvalds x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL); 12321da177e4SLinus Torvalds if (!x->encap) 12331da177e4SLinus Torvalds goto out; 12341da177e4SLinus Torvalds 12351da177e4SLinus Torvalds natt = x->encap; 12361da177e4SLinus Torvalds n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; 12371da177e4SLinus Torvalds natt->encap_type = n_type->sadb_x_nat_t_type_type; 12381da177e4SLinus Torvalds 12391da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) { 1240*4c93fbb0SDavid S. Miller const struct sadb_x_nat_t_port *n_port = 12411da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]; 12421da177e4SLinus Torvalds natt->encap_sport = n_port->sadb_x_nat_t_port_port; 12431da177e4SLinus Torvalds } 12441da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) { 1245*4c93fbb0SDavid S. Miller const struct sadb_x_nat_t_port *n_port = 12461da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]; 12471da177e4SLinus Torvalds natt->encap_dport = n_port->sadb_x_nat_t_port_port; 12481da177e4SLinus Torvalds } 1249a8d694c6STimo Teras memset(&natt->encap_oa, 0, sizeof(natt->encap_oa)); 12501da177e4SLinus Torvalds } 12511da177e4SLinus Torvalds 125272cb6962SHerbert Xu err = xfrm_init_state(x); 125372cb6962SHerbert Xu if (err) 12541da177e4SLinus Torvalds goto out; 125572cb6962SHerbert Xu 12561da177e4SLinus Torvalds x->km.seq = hdr->sadb_msg_seq; 12571da177e4SLinus Torvalds return x; 12581da177e4SLinus Torvalds 12591da177e4SLinus Torvalds out: 12601da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 12611da177e4SLinus Torvalds xfrm_state_put(x); 12621da177e4SLinus Torvalds return ERR_PTR(err); 12631da177e4SLinus Torvalds } 12641da177e4SLinus Torvalds 1265*4c93fbb0SDavid S. Miller static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 12661da177e4SLinus Torvalds { 12671da177e4SLinus Torvalds return -EOPNOTSUPP; 12681da177e4SLinus Torvalds } 12691da177e4SLinus Torvalds 1270*4c93fbb0SDavid S. Miller static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 12711da177e4SLinus Torvalds { 127207fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 12731da177e4SLinus Torvalds struct sk_buff *resp_skb; 12741da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 12751da177e4SLinus Torvalds struct sadb_address *saddr, *daddr; 12761da177e4SLinus Torvalds struct sadb_msg *out_hdr; 1277658b219eSHerbert Xu struct sadb_spirange *range; 12781da177e4SLinus Torvalds struct xfrm_state *x = NULL; 127955569ce2SKazunori MIYAZAWA int mode; 1280658b219eSHerbert Xu int err; 1281658b219eSHerbert Xu u32 min_spi, max_spi; 12821da177e4SLinus Torvalds u32 reqid; 12831da177e4SLinus Torvalds u8 proto; 12841da177e4SLinus Torvalds unsigned short family; 12851da177e4SLinus Torvalds xfrm_address_t *xsaddr = NULL, *xdaddr = NULL; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 12881da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 12891da177e4SLinus Torvalds return -EINVAL; 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 12921da177e4SLinus Torvalds if (proto == 0) 12931da177e4SLinus Torvalds return -EINVAL; 12941da177e4SLinus Torvalds 12951da177e4SLinus Torvalds if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) { 129655569ce2SKazunori MIYAZAWA mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 129755569ce2SKazunori MIYAZAWA if (mode < 0) 129855569ce2SKazunori MIYAZAWA return -EINVAL; 12991da177e4SLinus Torvalds reqid = sa2->sadb_x_sa2_reqid; 13001da177e4SLinus Torvalds } else { 13011da177e4SLinus Torvalds mode = 0; 13021da177e4SLinus Torvalds reqid = 0; 13031da177e4SLinus Torvalds } 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1]; 13061da177e4SLinus Torvalds daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 13071da177e4SLinus Torvalds 13081da177e4SLinus Torvalds family = ((struct sockaddr *)(saddr + 1))->sa_family; 13091da177e4SLinus Torvalds switch (family) { 13101da177e4SLinus Torvalds case AF_INET: 13111da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr; 13121da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr; 13131da177e4SLinus Torvalds break; 13141da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 13151da177e4SLinus Torvalds case AF_INET6: 13161da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6_addr; 13171da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6_addr; 13181da177e4SLinus Torvalds break; 13191da177e4SLinus Torvalds #endif 13201da177e4SLinus Torvalds } 13211da177e4SLinus Torvalds 13221da177e4SLinus Torvalds if (hdr->sadb_msg_seq) { 1323bd55775cSJamal Hadi Salim x = xfrm_find_acq_byseq(net, DUMMY_MARK, hdr->sadb_msg_seq); 13241da177e4SLinus Torvalds if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) { 13251da177e4SLinus Torvalds xfrm_state_put(x); 13261da177e4SLinus Torvalds x = NULL; 13271da177e4SLinus Torvalds } 13281da177e4SLinus Torvalds } 13291da177e4SLinus Torvalds 13301da177e4SLinus Torvalds if (!x) 1331bd55775cSJamal Hadi Salim x = xfrm_find_acq(net, &dummy_mark, mode, reqid, proto, xdaddr, xsaddr, 1, family); 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds if (x == NULL) 13341da177e4SLinus Torvalds return -ENOENT; 13351da177e4SLinus Torvalds 13361da177e4SLinus Torvalds min_spi = 0x100; 13371da177e4SLinus Torvalds max_spi = 0x0fffffff; 1338658b219eSHerbert Xu 1339658b219eSHerbert Xu range = ext_hdrs[SADB_EXT_SPIRANGE-1]; 1340658b219eSHerbert Xu if (range) { 1341658b219eSHerbert Xu min_spi = range->sadb_spirange_min; 1342658b219eSHerbert Xu max_spi = range->sadb_spirange_max; 13431da177e4SLinus Torvalds } 1344658b219eSHerbert Xu 1345658b219eSHerbert Xu err = xfrm_alloc_spi(x, min_spi, max_spi); 1346050f009eSHerbert Xu resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); 13471da177e4SLinus Torvalds 13481da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 13491da177e4SLinus Torvalds xfrm_state_put(x); 13501da177e4SLinus Torvalds return PTR_ERR(resp_skb); 13511da177e4SLinus Torvalds } 13521da177e4SLinus Torvalds 13531da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) resp_skb->data; 13541da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 13551da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_GETSPI; 13561da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 13571da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 13581da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 13591da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 13601da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds xfrm_state_put(x); 13631da177e4SLinus Torvalds 136407fb0f17SAlexey Dobriyan pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk, net); 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds return 0; 13671da177e4SLinus Torvalds } 13681da177e4SLinus Torvalds 1369*4c93fbb0SDavid S. Miller static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 13701da177e4SLinus Torvalds { 137107fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 13721da177e4SLinus Torvalds struct xfrm_state *x; 13731da177e4SLinus Torvalds 13741da177e4SLinus Torvalds if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8) 13751da177e4SLinus Torvalds return -EOPNOTSUPP; 13761da177e4SLinus Torvalds 13771da177e4SLinus Torvalds if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0) 13781da177e4SLinus Torvalds return 0; 13791da177e4SLinus Torvalds 1380bd55775cSJamal Hadi Salim x = xfrm_find_acq_byseq(net, DUMMY_MARK, hdr->sadb_msg_seq); 13811da177e4SLinus Torvalds if (x == NULL) 13821da177e4SLinus Torvalds return 0; 13831da177e4SLinus Torvalds 13841da177e4SLinus Torvalds spin_lock_bh(&x->lock); 13851da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ) { 13861da177e4SLinus Torvalds x->km.state = XFRM_STATE_ERROR; 138707fb0f17SAlexey Dobriyan wake_up(&net->xfrm.km_waitq); 13881da177e4SLinus Torvalds } 13891da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 13901da177e4SLinus Torvalds xfrm_state_put(x); 13911da177e4SLinus Torvalds return 0; 13921da177e4SLinus Torvalds } 13931da177e4SLinus Torvalds 139426b15dadSJamal Hadi Salim static inline int event2poltype(int event) 139526b15dadSJamal Hadi Salim { 139626b15dadSJamal Hadi Salim switch (event) { 1397f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 139826b15dadSJamal Hadi Salim return SADB_X_SPDDELETE; 1399f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 140026b15dadSJamal Hadi Salim return SADB_X_SPDADD; 1401f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 140226b15dadSJamal Hadi Salim return SADB_X_SPDUPDATE; 1403f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 140426b15dadSJamal Hadi Salim // return SADB_X_SPDEXPIRE; 140526b15dadSJamal Hadi Salim default: 1406207024b9Sstephen hemminger pr_err("pfkey: Unknown policy event %d\n", event); 140726b15dadSJamal Hadi Salim break; 140826b15dadSJamal Hadi Salim } 140926b15dadSJamal Hadi Salim 141026b15dadSJamal Hadi Salim return 0; 141126b15dadSJamal Hadi Salim } 141226b15dadSJamal Hadi Salim 141326b15dadSJamal Hadi Salim static inline int event2keytype(int event) 141426b15dadSJamal Hadi Salim { 141526b15dadSJamal Hadi Salim switch (event) { 1416f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 141726b15dadSJamal Hadi Salim return SADB_DELETE; 1418f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 141926b15dadSJamal Hadi Salim return SADB_ADD; 1420f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 142126b15dadSJamal Hadi Salim return SADB_UPDATE; 1422f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 142326b15dadSJamal Hadi Salim return SADB_EXPIRE; 142426b15dadSJamal Hadi Salim default: 1425207024b9Sstephen hemminger pr_err("pfkey: Unknown SA event %d\n", event); 142626b15dadSJamal Hadi Salim break; 142726b15dadSJamal Hadi Salim } 142826b15dadSJamal Hadi Salim 142926b15dadSJamal Hadi Salim return 0; 143026b15dadSJamal Hadi Salim } 143126b15dadSJamal Hadi Salim 143226b15dadSJamal Hadi Salim /* ADD/UPD/DEL */ 1433214e005bSDavid S. Miller static int key_notify_sa(struct xfrm_state *x, const struct km_event *c) 143426b15dadSJamal Hadi Salim { 143526b15dadSJamal Hadi Salim struct sk_buff *skb; 143626b15dadSJamal Hadi Salim struct sadb_msg *hdr; 143726b15dadSJamal Hadi Salim 1438050f009eSHerbert Xu skb = pfkey_xfrm_state2msg(x); 143926b15dadSJamal Hadi Salim 144026b15dadSJamal Hadi Salim if (IS_ERR(skb)) 144126b15dadSJamal Hadi Salim return PTR_ERR(skb); 144226b15dadSJamal Hadi Salim 144326b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb->data; 144426b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 144526b15dadSJamal Hadi Salim hdr->sadb_msg_type = event2keytype(c->event); 144626b15dadSJamal Hadi Salim hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 144726b15dadSJamal Hadi Salim hdr->sadb_msg_errno = 0; 144826b15dadSJamal Hadi Salim hdr->sadb_msg_reserved = 0; 144926b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 145026b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 145126b15dadSJamal Hadi Salim 145207fb0f17SAlexey Dobriyan pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xs_net(x)); 145326b15dadSJamal Hadi Salim 145426b15dadSJamal Hadi Salim return 0; 145526b15dadSJamal Hadi Salim } 14561da177e4SLinus Torvalds 1457*4c93fbb0SDavid S. Miller static int pfkey_add(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 14581da177e4SLinus Torvalds { 145907fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 14601da177e4SLinus Torvalds struct xfrm_state *x; 14611da177e4SLinus Torvalds int err; 146226b15dadSJamal Hadi Salim struct km_event c; 14631da177e4SLinus Torvalds 146407fb0f17SAlexey Dobriyan x = pfkey_msg2xfrm_state(net, hdr, ext_hdrs); 14651da177e4SLinus Torvalds if (IS_ERR(x)) 14661da177e4SLinus Torvalds return PTR_ERR(x); 14671da177e4SLinus Torvalds 146826b15dadSJamal Hadi Salim xfrm_state_hold(x); 14691da177e4SLinus Torvalds if (hdr->sadb_msg_type == SADB_ADD) 14701da177e4SLinus Torvalds err = xfrm_state_add(x); 14711da177e4SLinus Torvalds else 14721da177e4SLinus Torvalds err = xfrm_state_update(x); 14731da177e4SLinus Torvalds 1474ab5f5e8bSJoy Latten xfrm_audit_state_add(x, err ? 0 : 1, 14752532386fSEric Paris audit_get_loginuid(current), 14762532386fSEric Paris audit_get_sessionid(current), 0); 1477161a09e7SJoy Latten 14781da177e4SLinus Torvalds if (err < 0) { 14791da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 148021380b81SHerbert Xu __xfrm_state_put(x); 14817d6dfe1fSPatrick McHardy goto out; 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 148426b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_ADD) 1485f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWSA; 148626b15dadSJamal Hadi Salim else 1487f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDSA; 148826b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 148926b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 149026b15dadSJamal Hadi Salim km_state_notify(x, &c); 14917d6dfe1fSPatrick McHardy out: 149226b15dadSJamal Hadi Salim xfrm_state_put(x); 149326b15dadSJamal Hadi Salim return err; 14941da177e4SLinus Torvalds } 14951da177e4SLinus Torvalds 1496*4c93fbb0SDavid S. Miller static int pfkey_delete(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 14971da177e4SLinus Torvalds { 149807fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 14991da177e4SLinus Torvalds struct xfrm_state *x; 150026b15dadSJamal Hadi Salim struct km_event c; 150126b15dadSJamal Hadi Salim int err; 15021da177e4SLinus Torvalds 15031da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 15041da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 15051da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 15061da177e4SLinus Torvalds return -EINVAL; 15071da177e4SLinus Torvalds 150807fb0f17SAlexey Dobriyan x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs); 15091da177e4SLinus Torvalds if (x == NULL) 15101da177e4SLinus Torvalds return -ESRCH; 15111da177e4SLinus Torvalds 1512c8c05a8eSCatherine Zhang if ((err = security_xfrm_state_delete(x))) 1513c8c05a8eSCatherine Zhang goto out; 1514c8c05a8eSCatherine Zhang 15151da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 1516c8c05a8eSCatherine Zhang err = -EPERM; 1517c8c05a8eSCatherine Zhang goto out; 15181da177e4SLinus Torvalds } 15191da177e4SLinus Torvalds 152026b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 1521161a09e7SJoy Latten 1522c8c05a8eSCatherine Zhang if (err < 0) 1523c8c05a8eSCatherine Zhang goto out; 152426b15dadSJamal Hadi Salim 152526b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 152626b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1527f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELSA; 152826b15dadSJamal Hadi Salim km_state_notify(x, &c); 1529c8c05a8eSCatherine Zhang out: 1530ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 15312532386fSEric Paris audit_get_loginuid(current), 15322532386fSEric Paris audit_get_sessionid(current), 0); 15331da177e4SLinus Torvalds xfrm_state_put(x); 15341da177e4SLinus Torvalds 153526b15dadSJamal Hadi Salim return err; 15361da177e4SLinus Torvalds } 15371da177e4SLinus Torvalds 1538*4c93fbb0SDavid S. Miller static int pfkey_get(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 15391da177e4SLinus Torvalds { 154007fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 15411da177e4SLinus Torvalds __u8 proto; 15421da177e4SLinus Torvalds struct sk_buff *out_skb; 15431da177e4SLinus Torvalds struct sadb_msg *out_hdr; 15441da177e4SLinus Torvalds struct xfrm_state *x; 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 15471da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 15481da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 15491da177e4SLinus Torvalds return -EINVAL; 15501da177e4SLinus Torvalds 155107fb0f17SAlexey Dobriyan x = pfkey_xfrm_state_lookup(net, hdr, ext_hdrs); 15521da177e4SLinus Torvalds if (x == NULL) 15531da177e4SLinus Torvalds return -ESRCH; 15541da177e4SLinus Torvalds 1555050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg(x); 15561da177e4SLinus Torvalds proto = x->id.proto; 15571da177e4SLinus Torvalds xfrm_state_put(x); 15581da177e4SLinus Torvalds if (IS_ERR(out_skb)) 15591da177e4SLinus Torvalds return PTR_ERR(out_skb); 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 15621da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 1563435000beSCharles Hardin out_hdr->sadb_msg_type = SADB_GET; 15641da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 15651da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 15661da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 15671da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 15681da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 156907fb0f17SAlexey Dobriyan pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds return 0; 15721da177e4SLinus Torvalds } 15731da177e4SLinus Torvalds 1574*4c93fbb0SDavid S. Miller static struct sk_buff *compose_sadb_supported(const struct sadb_msg *orig, 1575dd0fc66fSAl Viro gfp_t allocation) 15761da177e4SLinus Torvalds { 15771da177e4SLinus Torvalds struct sk_buff *skb; 15781da177e4SLinus Torvalds struct sadb_msg *hdr; 15791da177e4SLinus Torvalds int len, auth_len, enc_len, i; 15801da177e4SLinus Torvalds 15811da177e4SLinus Torvalds auth_len = xfrm_count_auth_supported(); 15821da177e4SLinus Torvalds if (auth_len) { 15831da177e4SLinus Torvalds auth_len *= sizeof(struct sadb_alg); 15841da177e4SLinus Torvalds auth_len += sizeof(struct sadb_supported); 15851da177e4SLinus Torvalds } 15861da177e4SLinus Torvalds 15871da177e4SLinus Torvalds enc_len = xfrm_count_enc_supported(); 15881da177e4SLinus Torvalds if (enc_len) { 15891da177e4SLinus Torvalds enc_len *= sizeof(struct sadb_alg); 15901da177e4SLinus Torvalds enc_len += sizeof(struct sadb_supported); 15911da177e4SLinus Torvalds } 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds len = enc_len + auth_len + sizeof(struct sadb_msg); 15941da177e4SLinus Torvalds 15951da177e4SLinus Torvalds skb = alloc_skb(len + 16, allocation); 15961da177e4SLinus Torvalds if (!skb) 15971da177e4SLinus Torvalds goto out_put_algs; 15981da177e4SLinus Torvalds 15991da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr)); 16001da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 16011da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 16021da177e4SLinus Torvalds hdr->sadb_msg_len = len / sizeof(uint64_t); 16031da177e4SLinus Torvalds 16041da177e4SLinus Torvalds if (auth_len) { 16051da177e4SLinus Torvalds struct sadb_supported *sp; 16061da177e4SLinus Torvalds struct sadb_alg *ap; 16071da177e4SLinus Torvalds 16081da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, auth_len); 16091da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 16101da177e4SLinus Torvalds 16111da177e4SLinus Torvalds sp->sadb_supported_len = auth_len / sizeof(uint64_t); 16121da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 16131da177e4SLinus Torvalds 16141da177e4SLinus Torvalds for (i = 0; ; i++) { 16151da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 16161da177e4SLinus Torvalds if (!aalg) 16171da177e4SLinus Torvalds break; 16181da177e4SLinus Torvalds if (aalg->available) 16191da177e4SLinus Torvalds *ap++ = aalg->desc; 16201da177e4SLinus Torvalds } 16211da177e4SLinus Torvalds } 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds if (enc_len) { 16241da177e4SLinus Torvalds struct sadb_supported *sp; 16251da177e4SLinus Torvalds struct sadb_alg *ap; 16261da177e4SLinus Torvalds 16271da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, enc_len); 16281da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 16291da177e4SLinus Torvalds 16301da177e4SLinus Torvalds sp->sadb_supported_len = enc_len / sizeof(uint64_t); 16311da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; 16321da177e4SLinus Torvalds 16331da177e4SLinus Torvalds for (i = 0; ; i++) { 16341da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 16351da177e4SLinus Torvalds if (!ealg) 16361da177e4SLinus Torvalds break; 16371da177e4SLinus Torvalds if (ealg->available) 16381da177e4SLinus Torvalds *ap++ = ealg->desc; 16391da177e4SLinus Torvalds } 16401da177e4SLinus Torvalds } 16411da177e4SLinus Torvalds 16421da177e4SLinus Torvalds out_put_algs: 16431da177e4SLinus Torvalds return skb; 16441da177e4SLinus Torvalds } 16451da177e4SLinus Torvalds 1646*4c93fbb0SDavid S. Miller static int pfkey_register(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 16471da177e4SLinus Torvalds { 16481da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 16491da177e4SLinus Torvalds struct sk_buff *supp_skb; 16501da177e4SLinus Torvalds 16511da177e4SLinus Torvalds if (hdr->sadb_msg_satype > SADB_SATYPE_MAX) 16521da177e4SLinus Torvalds return -EINVAL; 16531da177e4SLinus Torvalds 16541da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) { 16551da177e4SLinus Torvalds if (pfk->registered&(1<<hdr->sadb_msg_satype)) 16561da177e4SLinus Torvalds return -EEXIST; 16571da177e4SLinus Torvalds pfk->registered |= (1<<hdr->sadb_msg_satype); 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds xfrm_probe_algs(); 16611da177e4SLinus Torvalds 16621da177e4SLinus Torvalds supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); 16631da177e4SLinus Torvalds if (!supp_skb) { 16641da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) 16651da177e4SLinus Torvalds pfk->registered &= ~(1<<hdr->sadb_msg_satype); 16661da177e4SLinus Torvalds 16671da177e4SLinus Torvalds return -ENOBUFS; 16681da177e4SLinus Torvalds } 16691da177e4SLinus Torvalds 167007fb0f17SAlexey Dobriyan pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk, sock_net(sk)); 16711da177e4SLinus Torvalds 16721da177e4SLinus Torvalds return 0; 16731da177e4SLinus Torvalds } 16741da177e4SLinus Torvalds 1675*4c93fbb0SDavid S. Miller static int unicast_flush_resp(struct sock *sk, const struct sadb_msg *ihdr) 16768be987d7SJamal Hadi Salim { 16778be987d7SJamal Hadi Salim struct sk_buff *skb; 16788be987d7SJamal Hadi Salim struct sadb_msg *hdr; 16798be987d7SJamal Hadi Salim 16808be987d7SJamal Hadi Salim skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 16818be987d7SJamal Hadi Salim if (!skb) 16828be987d7SJamal Hadi Salim return -ENOBUFS; 16838be987d7SJamal Hadi Salim 16848be987d7SJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 16858be987d7SJamal Hadi Salim memcpy(hdr, ihdr, sizeof(struct sadb_msg)); 16868be987d7SJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 16878be987d7SJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 16888be987d7SJamal Hadi Salim 16898be987d7SJamal Hadi Salim return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ONE, sk, sock_net(sk)); 16908be987d7SJamal Hadi Salim } 16918be987d7SJamal Hadi Salim 1692214e005bSDavid S. Miller static int key_notify_sa_flush(const struct km_event *c) 169326b15dadSJamal Hadi Salim { 169426b15dadSJamal Hadi Salim struct sk_buff *skb; 169526b15dadSJamal Hadi Salim struct sadb_msg *hdr; 169626b15dadSJamal Hadi Salim 169726b15dadSJamal Hadi Salim skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 169826b15dadSJamal Hadi Salim if (!skb) 169926b15dadSJamal Hadi Salim return -ENOBUFS; 170026b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 1701bf08867fSHerbert Xu hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto); 1702151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_FLUSH; 170326b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 170426b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 170526b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 170626b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 170726b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 170826b15dadSJamal Hadi Salim 170907fb0f17SAlexey Dobriyan pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); 171026b15dadSJamal Hadi Salim 171126b15dadSJamal Hadi Salim return 0; 171226b15dadSJamal Hadi Salim } 171326b15dadSJamal Hadi Salim 1714*4c93fbb0SDavid S. Miller static int pfkey_flush(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 17151da177e4SLinus Torvalds { 171607fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 17171da177e4SLinus Torvalds unsigned proto; 171826b15dadSJamal Hadi Salim struct km_event c; 1719161a09e7SJoy Latten struct xfrm_audit audit_info; 17208be987d7SJamal Hadi Salim int err, err2; 17211da177e4SLinus Torvalds 17221da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 17231da177e4SLinus Torvalds if (proto == 0) 17241da177e4SLinus Torvalds return -EINVAL; 17251da177e4SLinus Torvalds 17260c11b942SAl Viro audit_info.loginuid = audit_get_loginuid(current); 17272532386fSEric Paris audit_info.sessionid = audit_get_sessionid(current); 1728161a09e7SJoy Latten audit_info.secid = 0; 172907fb0f17SAlexey Dobriyan err = xfrm_state_flush(net, proto, &audit_info); 17308be987d7SJamal Hadi Salim err2 = unicast_flush_resp(sk, hdr); 17319e64cc95SJamal Hadi Salim if (err || err2) { 17329e64cc95SJamal Hadi Salim if (err == -ESRCH) /* empty table - go quietly */ 17339e64cc95SJamal Hadi Salim err = 0; 17348be987d7SJamal Hadi Salim return err ? err : err2; 17359e64cc95SJamal Hadi Salim } 17368be987d7SJamal Hadi Salim 1737bf08867fSHerbert Xu c.data.proto = proto; 173826b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 173926b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1740f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHSA; 174107fb0f17SAlexey Dobriyan c.net = net; 174226b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 17431da177e4SLinus Torvalds 17441da177e4SLinus Torvalds return 0; 17451da177e4SLinus Torvalds } 17461da177e4SLinus Torvalds 17471da177e4SLinus Torvalds static int dump_sa(struct xfrm_state *x, int count, void *ptr) 17481da177e4SLinus Torvalds { 174983321d6bSTimo Teras struct pfkey_sock *pfk = ptr; 17501da177e4SLinus Torvalds struct sk_buff *out_skb; 17511da177e4SLinus Torvalds struct sadb_msg *out_hdr; 17521da177e4SLinus Torvalds 175383321d6bSTimo Teras if (!pfkey_can_dump(&pfk->sk)) 175483321d6bSTimo Teras return -ENOBUFS; 175583321d6bSTimo Teras 1756050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg(x); 17571da177e4SLinus Torvalds if (IS_ERR(out_skb)) 17581da177e4SLinus Torvalds return PTR_ERR(out_skb); 17591da177e4SLinus Torvalds 17601da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 176183321d6bSTimo Teras out_hdr->sadb_msg_version = pfk->dump.msg_version; 17621da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_DUMP; 17631da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 17641da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 17651da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 176612a169e7SHerbert Xu out_hdr->sadb_msg_seq = count + 1; 176783321d6bSTimo Teras out_hdr->sadb_msg_pid = pfk->dump.msg_pid; 176812a169e7SHerbert Xu 176912a169e7SHerbert Xu if (pfk->dump.skb) 177012a169e7SHerbert Xu pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, 177107fb0f17SAlexey Dobriyan &pfk->sk, sock_net(&pfk->sk)); 177212a169e7SHerbert Xu pfk->dump.skb = out_skb; 177312a169e7SHerbert Xu 17741da177e4SLinus Torvalds return 0; 17751da177e4SLinus Torvalds } 17761da177e4SLinus Torvalds 177783321d6bSTimo Teras static int pfkey_dump_sa(struct pfkey_sock *pfk) 177883321d6bSTimo Teras { 177907fb0f17SAlexey Dobriyan struct net *net = sock_net(&pfk->sk); 178007fb0f17SAlexey Dobriyan return xfrm_state_walk(net, &pfk->dump.u.state, dump_sa, (void *) pfk); 178183321d6bSTimo Teras } 178283321d6bSTimo Teras 178383321d6bSTimo Teras static void pfkey_dump_sa_done(struct pfkey_sock *pfk) 178483321d6bSTimo Teras { 178583321d6bSTimo Teras xfrm_state_walk_done(&pfk->dump.u.state); 178683321d6bSTimo Teras } 178783321d6bSTimo Teras 1788*4c93fbb0SDavid S. Miller static int pfkey_dump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 17891da177e4SLinus Torvalds { 17901da177e4SLinus Torvalds u8 proto; 179183321d6bSTimo Teras struct pfkey_sock *pfk = pfkey_sk(sk); 179283321d6bSTimo Teras 179383321d6bSTimo Teras if (pfk->dump.dump != NULL) 179483321d6bSTimo Teras return -EBUSY; 17951da177e4SLinus Torvalds 17961da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 17971da177e4SLinus Torvalds if (proto == 0) 17981da177e4SLinus Torvalds return -EINVAL; 17991da177e4SLinus Torvalds 180083321d6bSTimo Teras pfk->dump.msg_version = hdr->sadb_msg_version; 180183321d6bSTimo Teras pfk->dump.msg_pid = hdr->sadb_msg_pid; 180283321d6bSTimo Teras pfk->dump.dump = pfkey_dump_sa; 180383321d6bSTimo Teras pfk->dump.done = pfkey_dump_sa_done; 180483321d6bSTimo Teras xfrm_state_walk_init(&pfk->dump.u.state, proto); 18054c563f76STimo Teras 180683321d6bSTimo Teras return pfkey_do_dump(pfk); 18071da177e4SLinus Torvalds } 18081da177e4SLinus Torvalds 1809*4c93fbb0SDavid S. Miller static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 18101da177e4SLinus Torvalds { 18111da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 18121da177e4SLinus Torvalds int satype = hdr->sadb_msg_satype; 1813*4c93fbb0SDavid S. Miller bool reset_errno = false; 18141da177e4SLinus Torvalds 18151da177e4SLinus Torvalds if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) { 1816*4c93fbb0SDavid S. Miller reset_errno = true; 18171da177e4SLinus Torvalds if (satype != 0 && satype != 1) 18181da177e4SLinus Torvalds return -EINVAL; 18191da177e4SLinus Torvalds pfk->promisc = satype; 18201da177e4SLinus Torvalds } 1821*4c93fbb0SDavid S. Miller if (reset_errno && skb_cloned(skb)) 1822*4c93fbb0SDavid S. Miller skb = skb_copy(skb, GFP_KERNEL); 1823*4c93fbb0SDavid S. Miller else 1824*4c93fbb0SDavid S. Miller skb = skb_clone(skb, GFP_KERNEL); 1825*4c93fbb0SDavid S. Miller 1826*4c93fbb0SDavid S. Miller if (reset_errno && skb) { 1827*4c93fbb0SDavid S. Miller struct sadb_msg *new_hdr = (struct sadb_msg *) skb->data; 1828*4c93fbb0SDavid S. Miller new_hdr->sadb_msg_errno = 0; 1829*4c93fbb0SDavid S. Miller } 1830*4c93fbb0SDavid S. Miller 1831*4c93fbb0SDavid S. Miller pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ALL, NULL, sock_net(sk)); 18321da177e4SLinus Torvalds return 0; 18331da177e4SLinus Torvalds } 18341da177e4SLinus Torvalds 18351da177e4SLinus Torvalds static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) 18361da177e4SLinus Torvalds { 18371da177e4SLinus Torvalds int i; 18381da177e4SLinus Torvalds u32 reqid = *(u32*)ptr; 18391da177e4SLinus Torvalds 18401da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 18411da177e4SLinus Torvalds if (xp->xfrm_vec[i].reqid == reqid) 18421da177e4SLinus Torvalds return -EEXIST; 18431da177e4SLinus Torvalds } 18441da177e4SLinus Torvalds return 0; 18451da177e4SLinus Torvalds } 18461da177e4SLinus Torvalds 184707fb0f17SAlexey Dobriyan static u32 gen_reqid(struct net *net) 18481da177e4SLinus Torvalds { 18494c563f76STimo Teras struct xfrm_policy_walk walk; 18501da177e4SLinus Torvalds u32 start; 18514c563f76STimo Teras int rc; 18521da177e4SLinus Torvalds static u32 reqid = IPSEC_MANUAL_REQID_MAX; 18531da177e4SLinus Torvalds 18541da177e4SLinus Torvalds start = reqid; 18551da177e4SLinus Torvalds do { 18561da177e4SLinus Torvalds ++reqid; 18571da177e4SLinus Torvalds if (reqid == 0) 18581da177e4SLinus Torvalds reqid = IPSEC_MANUAL_REQID_MAX+1; 18594c563f76STimo Teras xfrm_policy_walk_init(&walk, XFRM_POLICY_TYPE_MAIN); 186007fb0f17SAlexey Dobriyan rc = xfrm_policy_walk(net, &walk, check_reqid, (void*)&reqid); 18614c563f76STimo Teras xfrm_policy_walk_done(&walk); 18624c563f76STimo Teras if (rc != -EEXIST) 18631da177e4SLinus Torvalds return reqid; 18641da177e4SLinus Torvalds } while (reqid != start); 18651da177e4SLinus Torvalds return 0; 18661da177e4SLinus Torvalds } 18671da177e4SLinus Torvalds 18681da177e4SLinus Torvalds static int 18691da177e4SLinus Torvalds parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) 18701da177e4SLinus Torvalds { 187107fb0f17SAlexey Dobriyan struct net *net = xp_net(xp); 18721da177e4SLinus Torvalds struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr; 187355569ce2SKazunori MIYAZAWA int mode; 18741da177e4SLinus Torvalds 18751da177e4SLinus Torvalds if (xp->xfrm_nr >= XFRM_MAX_DEPTH) 18761da177e4SLinus Torvalds return -ELOOP; 18771da177e4SLinus Torvalds 18781da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_mode == 0) 18791da177e4SLinus Torvalds return -EINVAL; 18801da177e4SLinus Torvalds 18811da177e4SLinus Torvalds t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */ 188255569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0) 188355569ce2SKazunori MIYAZAWA return -EINVAL; 188455569ce2SKazunori MIYAZAWA t->mode = mode; 18851da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) 18861da177e4SLinus Torvalds t->optional = 1; 18871da177e4SLinus Torvalds else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) { 18881da177e4SLinus Torvalds t->reqid = rq->sadb_x_ipsecrequest_reqid; 18891da177e4SLinus Torvalds if (t->reqid > IPSEC_MANUAL_REQID_MAX) 18901da177e4SLinus Torvalds t->reqid = 0; 189107fb0f17SAlexey Dobriyan if (!t->reqid && !(t->reqid = gen_reqid(net))) 18921da177e4SLinus Torvalds return -ENOBUFS; 18931da177e4SLinus Torvalds } 18941da177e4SLinus Torvalds 18951da177e4SLinus Torvalds /* addresses present only in tunnel mode */ 18967e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) { 18975f95ac91SYOSHIFUJI Hideaki u8 *sa = (u8 *) (rq + 1); 18985f95ac91SYOSHIFUJI Hideaki int family, socklen; 18995f95ac91SYOSHIFUJI Hideaki 19005f95ac91SYOSHIFUJI Hideaki family = pfkey_sockaddr_extract((struct sockaddr *)sa, 19015f95ac91SYOSHIFUJI Hideaki &t->saddr); 19025f95ac91SYOSHIFUJI Hideaki if (!family) 19031da177e4SLinus Torvalds return -EINVAL; 19045f95ac91SYOSHIFUJI Hideaki 19055f95ac91SYOSHIFUJI Hideaki socklen = pfkey_sockaddr_len(family); 19065f95ac91SYOSHIFUJI Hideaki if (pfkey_sockaddr_extract((struct sockaddr *)(sa + socklen), 19075f95ac91SYOSHIFUJI Hideaki &t->id.daddr) != family) 19081da177e4SLinus Torvalds return -EINVAL; 19095f95ac91SYOSHIFUJI Hideaki t->encap_family = family; 19102718aa7cSMiika Komu } else 19112718aa7cSMiika Komu t->encap_family = xp->family; 19122718aa7cSMiika Komu 19131da177e4SLinus Torvalds /* No way to set this via kame pfkey */ 1914c5d18e98SHerbert Xu t->allalgs = 1; 19151da177e4SLinus Torvalds xp->xfrm_nr++; 19161da177e4SLinus Torvalds return 0; 19171da177e4SLinus Torvalds } 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds static int 19201da177e4SLinus Torvalds parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) 19211da177e4SLinus Torvalds { 19221da177e4SLinus Torvalds int err; 19231da177e4SLinus Torvalds int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy); 19241da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq = (void*)(pol+1); 19251da177e4SLinus Torvalds 19261da177e4SLinus Torvalds while (len >= sizeof(struct sadb_x_ipsecrequest)) { 19271da177e4SLinus Torvalds if ((err = parse_ipsecrequest(xp, rq)) < 0) 19281da177e4SLinus Torvalds return err; 19291da177e4SLinus Torvalds len -= rq->sadb_x_ipsecrequest_len; 19301da177e4SLinus Torvalds rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len); 19311da177e4SLinus Torvalds } 19321da177e4SLinus Torvalds return 0; 19331da177e4SLinus Torvalds } 19341da177e4SLinus Torvalds 1935*4c93fbb0SDavid S. Miller static inline int pfkey_xfrm_policy2sec_ctx_size(const struct xfrm_policy *xp) 1936df71837dSTrent Jaeger { 1937df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx = xp->security; 1938df71837dSTrent Jaeger 1939df71837dSTrent Jaeger if (xfrm_ctx) { 1940df71837dSTrent Jaeger int len = sizeof(struct sadb_x_sec_ctx); 1941df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 1942df71837dSTrent Jaeger return PFKEY_ALIGN8(len); 1943df71837dSTrent Jaeger } 1944df71837dSTrent Jaeger return 0; 1945df71837dSTrent Jaeger } 1946df71837dSTrent Jaeger 1947*4c93fbb0SDavid S. Miller static int pfkey_xfrm_policy2msg_size(const struct xfrm_policy *xp) 19481da177e4SLinus Torvalds { 1949*4c93fbb0SDavid S. Miller const struct xfrm_tmpl *t; 19501da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 19512718aa7cSMiika Komu int socklen = 0; 19522718aa7cSMiika Komu int i; 19532718aa7cSMiika Komu 19542718aa7cSMiika Komu for (i=0; i<xp->xfrm_nr; i++) { 19552718aa7cSMiika Komu t = xp->xfrm_vec + i; 19569e8b4ed8SYOSHIFUJI Hideaki socklen += pfkey_sockaddr_len(t->encap_family); 19572718aa7cSMiika Komu } 19581da177e4SLinus Torvalds 19591da177e4SLinus Torvalds return sizeof(struct sadb_msg) + 19601da177e4SLinus Torvalds (sizeof(struct sadb_lifetime) * 3) + 19611da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 19621da177e4SLinus Torvalds (sockaddr_size * 2) + 19631da177e4SLinus Torvalds sizeof(struct sadb_x_policy) + 19642718aa7cSMiika Komu (xp->xfrm_nr * sizeof(struct sadb_x_ipsecrequest)) + 19652718aa7cSMiika Komu (socklen * 2) + 1966df71837dSTrent Jaeger pfkey_xfrm_policy2sec_ctx_size(xp); 19671da177e4SLinus Torvalds } 19681da177e4SLinus Torvalds 1969*4c93fbb0SDavid S. Miller static struct sk_buff * pfkey_xfrm_policy2msg_prep(const struct xfrm_policy *xp) 19701da177e4SLinus Torvalds { 19711da177e4SLinus Torvalds struct sk_buff *skb; 19721da177e4SLinus Torvalds int size; 19731da177e4SLinus Torvalds 19741da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19751da177e4SLinus Torvalds 19761da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 19771da177e4SLinus Torvalds if (skb == NULL) 19781da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 19791da177e4SLinus Torvalds 19801da177e4SLinus Torvalds return skb; 19811da177e4SLinus Torvalds } 19821da177e4SLinus Torvalds 1983*4c93fbb0SDavid S. Miller static int pfkey_xfrm_policy2msg(struct sk_buff *skb, const struct xfrm_policy *xp, int dir) 19841da177e4SLinus Torvalds { 19851da177e4SLinus Torvalds struct sadb_msg *hdr; 19861da177e4SLinus Torvalds struct sadb_address *addr; 19871da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 19881da177e4SLinus Torvalds struct sadb_x_policy *pol; 1989df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 1990df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 19911da177e4SLinus Torvalds int i; 19921da177e4SLinus Torvalds int size; 19931da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 19949e8b4ed8SYOSHIFUJI Hideaki int socklen = pfkey_sockaddr_len(xp->family); 19951da177e4SLinus Torvalds 19961da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19971da177e4SLinus Torvalds 19981da177e4SLinus Torvalds /* call should fill header later */ 19991da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 20001da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 20011da177e4SLinus Torvalds 20021da177e4SLinus Torvalds /* src address */ 20031da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 20041da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 20051da177e4SLinus Torvalds addr->sadb_address_len = 20061da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 20071da177e4SLinus Torvalds sizeof(uint64_t); 20081da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 20091da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 20101da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_s; 20111da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 2012e5b56652SYOSHIFUJI Hideaki if (!pfkey_sockaddr_fill(&xp->selector.saddr, 2013e5b56652SYOSHIFUJI Hideaki xp->selector.sport, 2014e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 2015e5b56652SYOSHIFUJI Hideaki xp->family)) 20161da177e4SLinus Torvalds BUG(); 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds /* dst address */ 20191da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 20201da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 20211da177e4SLinus Torvalds addr->sadb_address_len = 20221da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 20231da177e4SLinus Torvalds sizeof(uint64_t); 20241da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 20251da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 20261da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_d; 20271da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 2028e5b56652SYOSHIFUJI Hideaki 2029e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&xp->selector.daddr, xp->selector.dport, 2030e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 2031e5b56652SYOSHIFUJI Hideaki xp->family); 20321da177e4SLinus Torvalds 20331da177e4SLinus Torvalds /* hard time */ 20341da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20351da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20361da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20371da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20381da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 20391da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.hard_packet_limit); 20401da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.hard_byte_limit); 20411da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds; 20421da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds; 20431da177e4SLinus Torvalds /* soft time */ 20441da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20451da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20461da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20471da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20481da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 20491da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.soft_packet_limit); 20501da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.soft_byte_limit); 20511da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds; 20521da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds; 20531da177e4SLinus Torvalds /* current time */ 20541da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20551da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20561da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20571da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20581da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 20591da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = xp->curlft.packets; 20601da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = xp->curlft.bytes; 20611da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->curlft.add_time; 20621da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->curlft.use_time; 20631da177e4SLinus Torvalds 20641da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 20651da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 20661da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 20671da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD; 20681da177e4SLinus Torvalds if (xp->action == XFRM_POLICY_ALLOW) { 20691da177e4SLinus Torvalds if (xp->xfrm_nr) 20701da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 20711da177e4SLinus Torvalds else 20721da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_NONE; 20731da177e4SLinus Torvalds } 20741da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 20751da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 20761da177e4SLinus Torvalds pol->sadb_x_policy_priority = xp->priority; 20771da177e4SLinus Torvalds 20781da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 2079*4c93fbb0SDavid S. Miller const struct xfrm_tmpl *t = xp->xfrm_vec + i; 20801da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq; 20811da177e4SLinus Torvalds int req_size; 208255569ce2SKazunori MIYAZAWA int mode; 20831da177e4SLinus Torvalds 20841da177e4SLinus Torvalds req_size = sizeof(struct sadb_x_ipsecrequest); 2085e5b56652SYOSHIFUJI Hideaki if (t->mode == XFRM_MODE_TUNNEL) { 2086e5b56652SYOSHIFUJI Hideaki socklen = pfkey_sockaddr_len(t->encap_family); 2087e5b56652SYOSHIFUJI Hideaki req_size += socklen * 2; 2088e5b56652SYOSHIFUJI Hideaki } else { 20891da177e4SLinus Torvalds size -= 2*socklen; 2090e5b56652SYOSHIFUJI Hideaki } 20911da177e4SLinus Torvalds rq = (void*)skb_put(skb, req_size); 20921da177e4SLinus Torvalds pol->sadb_x_policy_len += req_size/8; 20931da177e4SLinus Torvalds memset(rq, 0, sizeof(*rq)); 20941da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_len = req_size; 20951da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_proto = t->id.proto; 209655569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_from_xfrm(t->mode)) < 0) 209755569ce2SKazunori MIYAZAWA return -EINVAL; 2098fefaa75eSDavid S. Miller rq->sadb_x_ipsecrequest_mode = mode; 20991da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; 21001da177e4SLinus Torvalds if (t->reqid) 21011da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; 21021da177e4SLinus Torvalds if (t->optional) 21031da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; 21041da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_reqid = t->reqid; 21051da177e4SLinus Torvalds 2106e5b56652SYOSHIFUJI Hideaki if (t->mode == XFRM_MODE_TUNNEL) { 2107e5b56652SYOSHIFUJI Hideaki u8 *sa = (void *)(rq + 1); 2108e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&t->saddr, 0, 2109e5b56652SYOSHIFUJI Hideaki (struct sockaddr *)sa, 2110e5b56652SYOSHIFUJI Hideaki t->encap_family); 2111e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&t->id.daddr, 0, 2112e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (sa + socklen), 2113e5b56652SYOSHIFUJI Hideaki t->encap_family); 21141da177e4SLinus Torvalds } 21151da177e4SLinus Torvalds } 2116df71837dSTrent Jaeger 2117df71837dSTrent Jaeger /* security context */ 2118df71837dSTrent Jaeger if ((xfrm_ctx = xp->security)) { 2119df71837dSTrent Jaeger int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp); 2120df71837dSTrent Jaeger 2121df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size); 2122df71837dSTrent Jaeger sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t); 2123df71837dSTrent Jaeger sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 2124df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 2125df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 2126df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 2127df71837dSTrent Jaeger memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 2128df71837dSTrent Jaeger xfrm_ctx->ctx_len); 2129df71837dSTrent Jaeger } 2130df71837dSTrent Jaeger 21311da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 21321da177e4SLinus Torvalds hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); 213355569ce2SKazunori MIYAZAWA 213455569ce2SKazunori MIYAZAWA return 0; 21351da177e4SLinus Torvalds } 21361da177e4SLinus Torvalds 2137214e005bSDavid S. Miller static int key_notify_policy(struct xfrm_policy *xp, int dir, const struct km_event *c) 213826b15dadSJamal Hadi Salim { 213926b15dadSJamal Hadi Salim struct sk_buff *out_skb; 214026b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 214126b15dadSJamal Hadi Salim int err; 214226b15dadSJamal Hadi Salim 214326b15dadSJamal Hadi Salim out_skb = pfkey_xfrm_policy2msg_prep(xp); 21449a127aadSDan Carpenter if (IS_ERR(out_skb)) 21459a127aadSDan Carpenter return PTR_ERR(out_skb); 21469a127aadSDan Carpenter 214755569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 214855569ce2SKazunori MIYAZAWA if (err < 0) 214955569ce2SKazunori MIYAZAWA return err; 215026b15dadSJamal Hadi Salim 215126b15dadSJamal Hadi Salim out_hdr = (struct sadb_msg *) out_skb->data; 215226b15dadSJamal Hadi Salim out_hdr->sadb_msg_version = PF_KEY_V2; 215326b15dadSJamal Hadi Salim 2154f60f6b8fSHerbert Xu if (c->data.byid && c->event == XFRM_MSG_DELPOLICY) 215526b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; 215626b15dadSJamal Hadi Salim else 215726b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = event2poltype(c->event); 215826b15dadSJamal Hadi Salim out_hdr->sadb_msg_errno = 0; 215926b15dadSJamal Hadi Salim out_hdr->sadb_msg_seq = c->seq; 216026b15dadSJamal Hadi Salim out_hdr->sadb_msg_pid = c->pid; 216107fb0f17SAlexey Dobriyan pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL, xp_net(xp)); 216226b15dadSJamal Hadi Salim return 0; 216326b15dadSJamal Hadi Salim 216426b15dadSJamal Hadi Salim } 216526b15dadSJamal Hadi Salim 2166*4c93fbb0SDavid S. Miller static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 21671da177e4SLinus Torvalds { 216807fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 2169df71837dSTrent Jaeger int err = 0; 21701da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 21711da177e4SLinus Torvalds struct sadb_address *sa; 21721da177e4SLinus Torvalds struct sadb_x_policy *pol; 21731da177e4SLinus Torvalds struct xfrm_policy *xp; 217426b15dadSJamal Hadi Salim struct km_event c; 2175df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 21761da177e4SLinus Torvalds 21771da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 21781da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 21791da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 21801da177e4SLinus Torvalds return -EINVAL; 21811da177e4SLinus Torvalds 21821da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 21831da177e4SLinus Torvalds if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC) 21841da177e4SLinus Torvalds return -EINVAL; 21851da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 21861da177e4SLinus Torvalds return -EINVAL; 21871da177e4SLinus Torvalds 218807fb0f17SAlexey Dobriyan xp = xfrm_policy_alloc(net, GFP_KERNEL); 21891da177e4SLinus Torvalds if (xp == NULL) 21901da177e4SLinus Torvalds return -ENOBUFS; 21911da177e4SLinus Torvalds 21921da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 21931da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 21941da177e4SLinus Torvalds xp->priority = pol->sadb_x_policy_priority; 21951da177e4SLinus Torvalds 21961da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 21971da177e4SLinus Torvalds xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr); 21981da177e4SLinus Torvalds if (!xp->family) { 21991da177e4SLinus Torvalds err = -EINVAL; 22001da177e4SLinus Torvalds goto out; 22011da177e4SLinus Torvalds } 22021da177e4SLinus Torvalds xp->selector.family = xp->family; 22031da177e4SLinus Torvalds xp->selector.prefixlen_s = sa->sadb_address_prefixlen; 22041da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22051da177e4SLinus Torvalds xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 22061da177e4SLinus Torvalds if (xp->selector.sport) 22078f83f23eSAl Viro xp->selector.sport_mask = htons(0xffff); 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 22101da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); 22111da177e4SLinus Torvalds xp->selector.prefixlen_d = sa->sadb_address_prefixlen; 22121da177e4SLinus Torvalds 22131da177e4SLinus Torvalds /* Amusing, we set this twice. KAME apps appear to set same value 22141da177e4SLinus Torvalds * in both addresses. 22151da177e4SLinus Torvalds */ 22161da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 22191da177e4SLinus Torvalds if (xp->selector.dport) 22208f83f23eSAl Viro xp->selector.dport_mask = htons(0xffff); 22211da177e4SLinus Torvalds 2222df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2223df71837dSTrent Jaeger if (sec_ctx != NULL) { 2224df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2225df71837dSTrent Jaeger 2226df71837dSTrent Jaeger if (!uctx) { 2227df71837dSTrent Jaeger err = -ENOBUFS; 2228df71837dSTrent Jaeger goto out; 2229df71837dSTrent Jaeger } 2230df71837dSTrent Jaeger 223103e1ad7bSPaul Moore err = security_xfrm_policy_alloc(&xp->security, uctx); 2232df71837dSTrent Jaeger kfree(uctx); 2233df71837dSTrent Jaeger 2234df71837dSTrent Jaeger if (err) 2235df71837dSTrent Jaeger goto out; 2236df71837dSTrent Jaeger } 2237df71837dSTrent Jaeger 22381da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 22391da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 22401da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 22411da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 22421da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) { 22431da177e4SLinus Torvalds xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22441da177e4SLinus Torvalds xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22451da177e4SLinus Torvalds xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22461da177e4SLinus Torvalds xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22471da177e4SLinus Torvalds } 22481da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) { 22491da177e4SLinus Torvalds xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22501da177e4SLinus Torvalds xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22511da177e4SLinus Torvalds xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22521da177e4SLinus Torvalds xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22531da177e4SLinus Torvalds } 22541da177e4SLinus Torvalds xp->xfrm_nr = 0; 22551da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 22561da177e4SLinus Torvalds (err = parse_ipsecrequests(xp, pol)) < 0) 22571da177e4SLinus Torvalds goto out; 22581da177e4SLinus Torvalds 22591da177e4SLinus Torvalds err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, 22601da177e4SLinus Torvalds hdr->sadb_msg_type != SADB_X_SPDUPDATE); 2261df71837dSTrent Jaeger 2262ab5f5e8bSJoy Latten xfrm_audit_policy_add(xp, err ? 0 : 1, 22632532386fSEric Paris audit_get_loginuid(current), 22642532386fSEric Paris audit_get_sessionid(current), 0); 2265161a09e7SJoy Latten 2266df71837dSTrent Jaeger if (err) 2267df71837dSTrent Jaeger goto out; 22681da177e4SLinus Torvalds 226926b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) 2270f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDPOLICY; 227126b15dadSJamal Hadi Salim else 2272f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWPOLICY; 22731da177e4SLinus Torvalds 227426b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 227526b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 227626b15dadSJamal Hadi Salim 227726b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 22781da177e4SLinus Torvalds xfrm_pol_put(xp); 22791da177e4SLinus Torvalds return 0; 22801da177e4SLinus Torvalds 22811da177e4SLinus Torvalds out: 228212a169e7SHerbert Xu xp->walk.dead = 1; 228364c31b3fSWANG Cong xfrm_policy_destroy(xp); 22841da177e4SLinus Torvalds return err; 22851da177e4SLinus Torvalds } 22861da177e4SLinus Torvalds 2287*4c93fbb0SDavid S. Miller static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 22881da177e4SLinus Torvalds { 228907fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 22901da177e4SLinus Torvalds int err; 22911da177e4SLinus Torvalds struct sadb_address *sa; 22921da177e4SLinus Torvalds struct sadb_x_policy *pol; 229303e1ad7bSPaul Moore struct xfrm_policy *xp; 22941da177e4SLinus Torvalds struct xfrm_selector sel; 229526b15dadSJamal Hadi Salim struct km_event c; 2296df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 22972db3e47eSBrian Haley struct xfrm_sec_ctx *pol_ctx = NULL; 22981da177e4SLinus Torvalds 22991da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23001da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 23011da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 23021da177e4SLinus Torvalds return -EINVAL; 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 23051da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 23061da177e4SLinus Torvalds return -EINVAL; 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds memset(&sel, 0, sizeof(sel)); 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23111da177e4SLinus Torvalds sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 23121da177e4SLinus Torvalds sel.prefixlen_s = sa->sadb_address_prefixlen; 23131da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23141da177e4SLinus Torvalds sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 23151da177e4SLinus Torvalds if (sel.sport) 23168f83f23eSAl Viro sel.sport_mask = htons(0xffff); 23171da177e4SLinus Torvalds 23181da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 23191da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 23201da177e4SLinus Torvalds sel.prefixlen_d = sa->sadb_address_prefixlen; 23211da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23221da177e4SLinus Torvalds sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 23231da177e4SLinus Torvalds if (sel.dport) 23248f83f23eSAl Viro sel.dport_mask = htons(0xffff); 23251da177e4SLinus Torvalds 2326df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2327df71837dSTrent Jaeger if (sec_ctx != NULL) { 2328df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2329df71837dSTrent Jaeger 2330df71837dSTrent Jaeger if (!uctx) 2331df71837dSTrent Jaeger return -ENOMEM; 2332df71837dSTrent Jaeger 233303e1ad7bSPaul Moore err = security_xfrm_policy_alloc(&pol_ctx, uctx); 2334df71837dSTrent Jaeger kfree(uctx); 2335df71837dSTrent Jaeger if (err) 2336df71837dSTrent Jaeger return err; 23372db3e47eSBrian Haley } 2338df71837dSTrent Jaeger 23398ca2e93bSJamal Hadi Salim xp = xfrm_policy_bysel_ctx(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, 234003e1ad7bSPaul Moore pol->sadb_x_policy_dir - 1, &sel, pol_ctx, 234103e1ad7bSPaul Moore 1, &err); 234203e1ad7bSPaul Moore security_xfrm_policy_free(pol_ctx); 23431da177e4SLinus Torvalds if (xp == NULL) 23441da177e4SLinus Torvalds return -ENOENT; 23451da177e4SLinus Torvalds 2346ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, err ? 0 : 1, 23472532386fSEric Paris audit_get_loginuid(current), 23482532386fSEric Paris audit_get_sessionid(current), 0); 234913fcfbb0SDavid S. Miller 235013fcfbb0SDavid S. Miller if (err) 2351c8c05a8eSCatherine Zhang goto out; 235213fcfbb0SDavid S. Miller 235326b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 235426b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 23551839faabSTobias Brunner c.data.byid = 0; 2356f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 235726b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 235826b15dadSJamal Hadi Salim 2359c8c05a8eSCatherine Zhang out: 236026b15dadSJamal Hadi Salim xfrm_pol_put(xp); 236126b15dadSJamal Hadi Salim return err; 236226b15dadSJamal Hadi Salim } 236326b15dadSJamal Hadi Salim 2364*4c93fbb0SDavid S. Miller static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, const struct sadb_msg *hdr, int dir) 236526b15dadSJamal Hadi Salim { 236626b15dadSJamal Hadi Salim int err; 236726b15dadSJamal Hadi Salim struct sk_buff *out_skb; 236826b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 236926b15dadSJamal Hadi Salim err = 0; 237026b15dadSJamal Hadi Salim 23711da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 23721da177e4SLinus Torvalds if (IS_ERR(out_skb)) { 23731da177e4SLinus Torvalds err = PTR_ERR(out_skb); 23741da177e4SLinus Torvalds goto out; 23751da177e4SLinus Torvalds } 237655569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 237755569ce2SKazunori MIYAZAWA if (err < 0) 237855569ce2SKazunori MIYAZAWA goto out; 23791da177e4SLinus Torvalds 23801da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 23811da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 238226b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = hdr->sadb_msg_type; 23831da177e4SLinus Torvalds out_hdr->sadb_msg_satype = 0; 23841da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 23851da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 23861da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 238707fb0f17SAlexey Dobriyan pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk, xp_net(xp)); 23881da177e4SLinus Torvalds err = 0; 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds out: 23911da177e4SLinus Torvalds return err; 23921da177e4SLinus Torvalds } 23931da177e4SLinus Torvalds 239408de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 239508de61beSShinta Sugimoto static int pfkey_sockaddr_pair_size(sa_family_t family) 239608de61beSShinta Sugimoto { 23979e8b4ed8SYOSHIFUJI Hideaki return PFKEY_ALIGN8(pfkey_sockaddr_len(family) * 2); 239808de61beSShinta Sugimoto } 239908de61beSShinta Sugimoto 240013c1d189SArnaud Ebalard static int parse_sockaddr_pair(struct sockaddr *sa, int ext_len, 240108de61beSShinta Sugimoto xfrm_address_t *saddr, xfrm_address_t *daddr, 240208de61beSShinta Sugimoto u16 *family) 240308de61beSShinta Sugimoto { 24045f95ac91SYOSHIFUJI Hideaki int af, socklen; 24055f95ac91SYOSHIFUJI Hideaki 240613c1d189SArnaud Ebalard if (ext_len < pfkey_sockaddr_pair_size(sa->sa_family)) 240708de61beSShinta Sugimoto return -EINVAL; 240808de61beSShinta Sugimoto 240913c1d189SArnaud Ebalard af = pfkey_sockaddr_extract(sa, saddr); 24105f95ac91SYOSHIFUJI Hideaki if (!af) 241108de61beSShinta Sugimoto return -EINVAL; 241208de61beSShinta Sugimoto 24135f95ac91SYOSHIFUJI Hideaki socklen = pfkey_sockaddr_len(af); 241413c1d189SArnaud Ebalard if (pfkey_sockaddr_extract((struct sockaddr *) (((u8 *)sa) + socklen), 24155f95ac91SYOSHIFUJI Hideaki daddr) != af) 24165f95ac91SYOSHIFUJI Hideaki return -EINVAL; 24175f95ac91SYOSHIFUJI Hideaki 24185f95ac91SYOSHIFUJI Hideaki *family = af; 241908de61beSShinta Sugimoto return 0; 242008de61beSShinta Sugimoto } 242108de61beSShinta Sugimoto 242208de61beSShinta Sugimoto static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, 242308de61beSShinta Sugimoto struct xfrm_migrate *m) 242408de61beSShinta Sugimoto { 242508de61beSShinta Sugimoto int err; 242608de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq2; 242755569ce2SKazunori MIYAZAWA int mode; 242808de61beSShinta Sugimoto 242908de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 243008de61beSShinta Sugimoto len < rq1->sadb_x_ipsecrequest_len) 243108de61beSShinta Sugimoto return -EINVAL; 243208de61beSShinta Sugimoto 243308de61beSShinta Sugimoto /* old endoints */ 243413c1d189SArnaud Ebalard err = parse_sockaddr_pair((struct sockaddr *)(rq1 + 1), 243513c1d189SArnaud Ebalard rq1->sadb_x_ipsecrequest_len, 243613c1d189SArnaud Ebalard &m->old_saddr, &m->old_daddr, 243708de61beSShinta Sugimoto &m->old_family); 243808de61beSShinta Sugimoto if (err) 243908de61beSShinta Sugimoto return err; 244008de61beSShinta Sugimoto 244108de61beSShinta Sugimoto rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); 244208de61beSShinta Sugimoto len -= rq1->sadb_x_ipsecrequest_len; 244308de61beSShinta Sugimoto 244408de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 244508de61beSShinta Sugimoto len < rq2->sadb_x_ipsecrequest_len) 244608de61beSShinta Sugimoto return -EINVAL; 244708de61beSShinta Sugimoto 244808de61beSShinta Sugimoto /* new endpoints */ 244913c1d189SArnaud Ebalard err = parse_sockaddr_pair((struct sockaddr *)(rq2 + 1), 245013c1d189SArnaud Ebalard rq2->sadb_x_ipsecrequest_len, 245113c1d189SArnaud Ebalard &m->new_saddr, &m->new_daddr, 245208de61beSShinta Sugimoto &m->new_family); 245308de61beSShinta Sugimoto if (err) 245408de61beSShinta Sugimoto return err; 245508de61beSShinta Sugimoto 245608de61beSShinta Sugimoto if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto || 245708de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode || 245808de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid) 245908de61beSShinta Sugimoto return -EINVAL; 246008de61beSShinta Sugimoto 246108de61beSShinta Sugimoto m->proto = rq1->sadb_x_ipsecrequest_proto; 246255569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq1->sadb_x_ipsecrequest_mode)) < 0) 246355569ce2SKazunori MIYAZAWA return -EINVAL; 246455569ce2SKazunori MIYAZAWA m->mode = mode; 246508de61beSShinta Sugimoto m->reqid = rq1->sadb_x_ipsecrequest_reqid; 246608de61beSShinta Sugimoto 246708de61beSShinta Sugimoto return ((int)(rq1->sadb_x_ipsecrequest_len + 246808de61beSShinta Sugimoto rq2->sadb_x_ipsecrequest_len)); 246908de61beSShinta Sugimoto } 247008de61beSShinta Sugimoto 247108de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 2472*4c93fbb0SDavid S. Miller const struct sadb_msg *hdr, void * const *ext_hdrs) 247308de61beSShinta Sugimoto { 247408de61beSShinta Sugimoto int i, len, ret, err = -EINVAL; 247508de61beSShinta Sugimoto u8 dir; 247608de61beSShinta Sugimoto struct sadb_address *sa; 247713c1d189SArnaud Ebalard struct sadb_x_kmaddress *kma; 247808de61beSShinta Sugimoto struct sadb_x_policy *pol; 247908de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 248008de61beSShinta Sugimoto struct xfrm_selector sel; 248108de61beSShinta Sugimoto struct xfrm_migrate m[XFRM_MAX_DEPTH]; 248213c1d189SArnaud Ebalard struct xfrm_kmaddress k; 248308de61beSShinta Sugimoto 248408de61beSShinta Sugimoto if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], 248508de61beSShinta Sugimoto ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || 248608de61beSShinta Sugimoto !ext_hdrs[SADB_X_EXT_POLICY - 1]) { 248708de61beSShinta Sugimoto err = -EINVAL; 248808de61beSShinta Sugimoto goto out; 248908de61beSShinta Sugimoto } 249008de61beSShinta Sugimoto 249113c1d189SArnaud Ebalard kma = ext_hdrs[SADB_X_EXT_KMADDRESS - 1]; 249208de61beSShinta Sugimoto pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; 249308de61beSShinta Sugimoto 249408de61beSShinta Sugimoto if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { 249508de61beSShinta Sugimoto err = -EINVAL; 249608de61beSShinta Sugimoto goto out; 249708de61beSShinta Sugimoto } 249808de61beSShinta Sugimoto 249913c1d189SArnaud Ebalard if (kma) { 250013c1d189SArnaud Ebalard /* convert sadb_x_kmaddress to xfrm_kmaddress */ 250113c1d189SArnaud Ebalard k.reserved = kma->sadb_x_kmaddress_reserved; 250213c1d189SArnaud Ebalard ret = parse_sockaddr_pair((struct sockaddr *)(kma + 1), 250313c1d189SArnaud Ebalard 8*(kma->sadb_x_kmaddress_len) - sizeof(*kma), 250413c1d189SArnaud Ebalard &k.local, &k.remote, &k.family); 250513c1d189SArnaud Ebalard if (ret < 0) { 250613c1d189SArnaud Ebalard err = ret; 250713c1d189SArnaud Ebalard goto out; 250813c1d189SArnaud Ebalard } 250913c1d189SArnaud Ebalard } 251013c1d189SArnaud Ebalard 251108de61beSShinta Sugimoto dir = pol->sadb_x_policy_dir - 1; 251208de61beSShinta Sugimoto memset(&sel, 0, sizeof(sel)); 251308de61beSShinta Sugimoto 251408de61beSShinta Sugimoto /* set source address info of selector */ 251508de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1]; 251608de61beSShinta Sugimoto sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 251708de61beSShinta Sugimoto sel.prefixlen_s = sa->sadb_address_prefixlen; 251808de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 251908de61beSShinta Sugimoto sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port; 252008de61beSShinta Sugimoto if (sel.sport) 2521582ee43dSAl Viro sel.sport_mask = htons(0xffff); 252208de61beSShinta Sugimoto 252308de61beSShinta Sugimoto /* set destination address info of selector */ 252408de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1], 252508de61beSShinta Sugimoto pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 252608de61beSShinta Sugimoto sel.prefixlen_d = sa->sadb_address_prefixlen; 252708de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 252808de61beSShinta Sugimoto sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port; 252908de61beSShinta Sugimoto if (sel.dport) 2530582ee43dSAl Viro sel.dport_mask = htons(0xffff); 253108de61beSShinta Sugimoto 253208de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)(pol + 1); 253308de61beSShinta Sugimoto 253408de61beSShinta Sugimoto /* extract ipsecrequests */ 253508de61beSShinta Sugimoto i = 0; 253608de61beSShinta Sugimoto len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy); 253708de61beSShinta Sugimoto 253808de61beSShinta Sugimoto while (len > 0 && i < XFRM_MAX_DEPTH) { 253908de61beSShinta Sugimoto ret = ipsecrequests_to_migrate(rq, len, &m[i]); 254008de61beSShinta Sugimoto if (ret < 0) { 254108de61beSShinta Sugimoto err = ret; 254208de61beSShinta Sugimoto goto out; 254308de61beSShinta Sugimoto } else { 254408de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret); 254508de61beSShinta Sugimoto len -= ret; 254608de61beSShinta Sugimoto i++; 254708de61beSShinta Sugimoto } 254808de61beSShinta Sugimoto } 254908de61beSShinta Sugimoto 255008de61beSShinta Sugimoto if (!i || len > 0) { 255108de61beSShinta Sugimoto err = -EINVAL; 255208de61beSShinta Sugimoto goto out; 255308de61beSShinta Sugimoto } 255408de61beSShinta Sugimoto 255513c1d189SArnaud Ebalard return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i, 255613c1d189SArnaud Ebalard kma ? &k : NULL); 255708de61beSShinta Sugimoto 255808de61beSShinta Sugimoto out: 255908de61beSShinta Sugimoto return err; 256008de61beSShinta Sugimoto } 256108de61beSShinta Sugimoto #else 256208de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 256308de61beSShinta Sugimoto struct sadb_msg *hdr, void **ext_hdrs) 256408de61beSShinta Sugimoto { 256508de61beSShinta Sugimoto return -ENOPROTOOPT; 256608de61beSShinta Sugimoto } 256708de61beSShinta Sugimoto #endif 256808de61beSShinta Sugimoto 256908de61beSShinta Sugimoto 2570*4c93fbb0SDavid S. Miller static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 25711da177e4SLinus Torvalds { 257207fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 257377d8d7a6SHerbert Xu unsigned int dir; 2574215a2dd3SEric Paris int err = 0, delete; 25751da177e4SLinus Torvalds struct sadb_x_policy *pol; 25761da177e4SLinus Torvalds struct xfrm_policy *xp; 257726b15dadSJamal Hadi Salim struct km_event c; 25781da177e4SLinus Torvalds 25791da177e4SLinus Torvalds if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) 25801da177e4SLinus Torvalds return -EINVAL; 25811da177e4SLinus Torvalds 258277d8d7a6SHerbert Xu dir = xfrm_policy_id2dir(pol->sadb_x_policy_id); 258377d8d7a6SHerbert Xu if (dir >= XFRM_POLICY_MAX) 258477d8d7a6SHerbert Xu return -EINVAL; 258577d8d7a6SHerbert Xu 2586215a2dd3SEric Paris delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); 25878ca2e93bSJamal Hadi Salim xp = xfrm_policy_byid(net, DUMMY_MARK, XFRM_POLICY_TYPE_MAIN, 2588bd55775cSJamal Hadi Salim dir, pol->sadb_x_policy_id, delete, &err); 25891da177e4SLinus Torvalds if (xp == NULL) 25901da177e4SLinus Torvalds return -ENOENT; 25911da177e4SLinus Torvalds 2592215a2dd3SEric Paris if (delete) { 2593ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, err ? 0 : 1, 25942532386fSEric Paris audit_get_loginuid(current), 25952532386fSEric Paris audit_get_sessionid(current), 0); 25961da177e4SLinus Torvalds 2597215a2dd3SEric Paris if (err) 2598215a2dd3SEric Paris goto out; 259926b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 260026b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 2601bf08867fSHerbert Xu c.data.byid = 1; 2602f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 260377d8d7a6SHerbert Xu km_policy_notify(xp, dir, &c); 260426b15dadSJamal Hadi Salim } else { 260577d8d7a6SHerbert Xu err = key_pol_get_resp(sk, xp, hdr, dir); 26061da177e4SLinus Torvalds } 26071da177e4SLinus Torvalds 2608215a2dd3SEric Paris out: 26091da177e4SLinus Torvalds xfrm_pol_put(xp); 26101da177e4SLinus Torvalds return err; 26111da177e4SLinus Torvalds } 26121da177e4SLinus Torvalds 26131da177e4SLinus Torvalds static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) 26141da177e4SLinus Torvalds { 261583321d6bSTimo Teras struct pfkey_sock *pfk = ptr; 26161da177e4SLinus Torvalds struct sk_buff *out_skb; 26171da177e4SLinus Torvalds struct sadb_msg *out_hdr; 261855569ce2SKazunori MIYAZAWA int err; 26191da177e4SLinus Torvalds 262083321d6bSTimo Teras if (!pfkey_can_dump(&pfk->sk)) 262183321d6bSTimo Teras return -ENOBUFS; 262283321d6bSTimo Teras 26231da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 26241da177e4SLinus Torvalds if (IS_ERR(out_skb)) 26251da177e4SLinus Torvalds return PTR_ERR(out_skb); 26261da177e4SLinus Torvalds 262755569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 262855569ce2SKazunori MIYAZAWA if (err < 0) 262955569ce2SKazunori MIYAZAWA return err; 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 263283321d6bSTimo Teras out_hdr->sadb_msg_version = pfk->dump.msg_version; 26331da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_X_SPDDUMP; 26341da177e4SLinus Torvalds out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; 26351da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 263612a169e7SHerbert Xu out_hdr->sadb_msg_seq = count + 1; 263783321d6bSTimo Teras out_hdr->sadb_msg_pid = pfk->dump.msg_pid; 263812a169e7SHerbert Xu 263912a169e7SHerbert Xu if (pfk->dump.skb) 264012a169e7SHerbert Xu pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE, 264107fb0f17SAlexey Dobriyan &pfk->sk, sock_net(&pfk->sk)); 264212a169e7SHerbert Xu pfk->dump.skb = out_skb; 264312a169e7SHerbert Xu 26441da177e4SLinus Torvalds return 0; 26451da177e4SLinus Torvalds } 26461da177e4SLinus Torvalds 264783321d6bSTimo Teras static int pfkey_dump_sp(struct pfkey_sock *pfk) 264883321d6bSTimo Teras { 264907fb0f17SAlexey Dobriyan struct net *net = sock_net(&pfk->sk); 265007fb0f17SAlexey Dobriyan return xfrm_policy_walk(net, &pfk->dump.u.policy, dump_sp, (void *) pfk); 265183321d6bSTimo Teras } 265283321d6bSTimo Teras 265383321d6bSTimo Teras static void pfkey_dump_sp_done(struct pfkey_sock *pfk) 265483321d6bSTimo Teras { 265583321d6bSTimo Teras xfrm_policy_walk_done(&pfk->dump.u.policy); 265683321d6bSTimo Teras } 265783321d6bSTimo Teras 2658*4c93fbb0SDavid S. Miller static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 26591da177e4SLinus Torvalds { 266083321d6bSTimo Teras struct pfkey_sock *pfk = pfkey_sk(sk); 26611da177e4SLinus Torvalds 266283321d6bSTimo Teras if (pfk->dump.dump != NULL) 266383321d6bSTimo Teras return -EBUSY; 26644c563f76STimo Teras 266583321d6bSTimo Teras pfk->dump.msg_version = hdr->sadb_msg_version; 266683321d6bSTimo Teras pfk->dump.msg_pid = hdr->sadb_msg_pid; 266783321d6bSTimo Teras pfk->dump.dump = pfkey_dump_sp; 266883321d6bSTimo Teras pfk->dump.done = pfkey_dump_sp_done; 266983321d6bSTimo Teras xfrm_policy_walk_init(&pfk->dump.u.policy, XFRM_POLICY_TYPE_MAIN); 267083321d6bSTimo Teras 267183321d6bSTimo Teras return pfkey_do_dump(pfk); 26721da177e4SLinus Torvalds } 26731da177e4SLinus Torvalds 2674214e005bSDavid S. Miller static int key_notify_policy_flush(const struct km_event *c) 26751da177e4SLinus Torvalds { 26761da177e4SLinus Torvalds struct sk_buff *skb_out; 267726b15dadSJamal Hadi Salim struct sadb_msg *hdr; 26781da177e4SLinus Torvalds 267926b15dadSJamal Hadi Salim skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 26801da177e4SLinus Torvalds if (!skb_out) 26811da177e4SLinus Torvalds return -ENOBUFS; 268226b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); 2683151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_X_SPDFLUSH; 268426b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 268526b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 268626b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 268726b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 268826b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 268907fb0f17SAlexey Dobriyan pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL, c->net); 269026b15dadSJamal Hadi Salim return 0; 269126b15dadSJamal Hadi Salim 269226b15dadSJamal Hadi Salim } 269326b15dadSJamal Hadi Salim 2694*4c93fbb0SDavid S. Miller static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr, void * const *ext_hdrs) 269526b15dadSJamal Hadi Salim { 269607fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 269726b15dadSJamal Hadi Salim struct km_event c; 2698161a09e7SJoy Latten struct xfrm_audit audit_info; 26998be987d7SJamal Hadi Salim int err, err2; 27001da177e4SLinus Torvalds 27010c11b942SAl Viro audit_info.loginuid = audit_get_loginuid(current); 27022532386fSEric Paris audit_info.sessionid = audit_get_sessionid(current); 2703161a09e7SJoy Latten audit_info.secid = 0; 270407fb0f17SAlexey Dobriyan err = xfrm_policy_flush(net, XFRM_POLICY_TYPE_MAIN, &audit_info); 27058be987d7SJamal Hadi Salim err2 = unicast_flush_resp(sk, hdr); 27062f1eb65fSJamal Hadi Salim if (err || err2) { 27072f1eb65fSJamal Hadi Salim if (err == -ESRCH) /* empty table - old silent behavior */ 27082f1eb65fSJamal Hadi Salim return 0; 27092f1eb65fSJamal Hadi Salim return err; 27102f1eb65fSJamal Hadi Salim } 27118be987d7SJamal Hadi Salim 2712f7b6983fSMasahide NAKAMURA c.data.type = XFRM_POLICY_TYPE_MAIN; 2713f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHPOLICY; 271426b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 271526b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 271607fb0f17SAlexey Dobriyan c.net = net; 271726b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 27181da177e4SLinus Torvalds 27191da177e4SLinus Torvalds return 0; 27201da177e4SLinus Torvalds } 27211da177e4SLinus Torvalds 27221da177e4SLinus Torvalds typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb, 2723*4c93fbb0SDavid S. Miller const struct sadb_msg *hdr, void * const *ext_hdrs); 27241da177e4SLinus Torvalds static pfkey_handler pfkey_funcs[SADB_MAX + 1] = { 27251da177e4SLinus Torvalds [SADB_RESERVED] = pfkey_reserved, 27261da177e4SLinus Torvalds [SADB_GETSPI] = pfkey_getspi, 27271da177e4SLinus Torvalds [SADB_UPDATE] = pfkey_add, 27281da177e4SLinus Torvalds [SADB_ADD] = pfkey_add, 27291da177e4SLinus Torvalds [SADB_DELETE] = pfkey_delete, 27301da177e4SLinus Torvalds [SADB_GET] = pfkey_get, 27311da177e4SLinus Torvalds [SADB_ACQUIRE] = pfkey_acquire, 27321da177e4SLinus Torvalds [SADB_REGISTER] = pfkey_register, 27331da177e4SLinus Torvalds [SADB_EXPIRE] = NULL, 27341da177e4SLinus Torvalds [SADB_FLUSH] = pfkey_flush, 27351da177e4SLinus Torvalds [SADB_DUMP] = pfkey_dump, 27361da177e4SLinus Torvalds [SADB_X_PROMISC] = pfkey_promisc, 27371da177e4SLinus Torvalds [SADB_X_PCHANGE] = NULL, 27381da177e4SLinus Torvalds [SADB_X_SPDUPDATE] = pfkey_spdadd, 27391da177e4SLinus Torvalds [SADB_X_SPDADD] = pfkey_spdadd, 27401da177e4SLinus Torvalds [SADB_X_SPDDELETE] = pfkey_spddelete, 27411da177e4SLinus Torvalds [SADB_X_SPDGET] = pfkey_spdget, 27421da177e4SLinus Torvalds [SADB_X_SPDACQUIRE] = NULL, 27431da177e4SLinus Torvalds [SADB_X_SPDDUMP] = pfkey_spddump, 27441da177e4SLinus Torvalds [SADB_X_SPDFLUSH] = pfkey_spdflush, 27451da177e4SLinus Torvalds [SADB_X_SPDSETIDX] = pfkey_spdadd, 27461da177e4SLinus Torvalds [SADB_X_SPDDELETE2] = pfkey_spdget, 274708de61beSShinta Sugimoto [SADB_X_MIGRATE] = pfkey_migrate, 27481da177e4SLinus Torvalds }; 27491da177e4SLinus Torvalds 2750*4c93fbb0SDavid S. Miller static int pfkey_process(struct sock *sk, struct sk_buff *skb, const struct sadb_msg *hdr) 27511da177e4SLinus Torvalds { 27521da177e4SLinus Torvalds void *ext_hdrs[SADB_EXT_MAX]; 27531da177e4SLinus Torvalds int err; 27541da177e4SLinus Torvalds 27551da177e4SLinus Torvalds pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, 275607fb0f17SAlexey Dobriyan BROADCAST_PROMISC_ONLY, NULL, sock_net(sk)); 27571da177e4SLinus Torvalds 27581da177e4SLinus Torvalds memset(ext_hdrs, 0, sizeof(ext_hdrs)); 27591da177e4SLinus Torvalds err = parse_exthdrs(skb, hdr, ext_hdrs); 27601da177e4SLinus Torvalds if (!err) { 27611da177e4SLinus Torvalds err = -EOPNOTSUPP; 27621da177e4SLinus Torvalds if (pfkey_funcs[hdr->sadb_msg_type]) 27631da177e4SLinus Torvalds err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs); 27641da177e4SLinus Torvalds } 27651da177e4SLinus Torvalds return err; 27661da177e4SLinus Torvalds } 27671da177e4SLinus Torvalds 27681da177e4SLinus Torvalds static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp) 27691da177e4SLinus Torvalds { 27701da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 27711da177e4SLinus Torvalds 27721da177e4SLinus Torvalds if (skb->len < sizeof(*hdr)) { 27731da177e4SLinus Torvalds *errp = -EMSGSIZE; 27741da177e4SLinus Torvalds } else { 27751da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb->data; 27761da177e4SLinus Torvalds if (hdr->sadb_msg_version != PF_KEY_V2 || 27771da177e4SLinus Torvalds hdr->sadb_msg_reserved != 0 || 27781da177e4SLinus Torvalds (hdr->sadb_msg_type <= SADB_RESERVED || 27791da177e4SLinus Torvalds hdr->sadb_msg_type > SADB_MAX)) { 27801da177e4SLinus Torvalds hdr = NULL; 27811da177e4SLinus Torvalds *errp = -EINVAL; 27821da177e4SLinus Torvalds } else if (hdr->sadb_msg_len != (skb->len / 27831da177e4SLinus Torvalds sizeof(uint64_t)) || 27841da177e4SLinus Torvalds hdr->sadb_msg_len < (sizeof(struct sadb_msg) / 27851da177e4SLinus Torvalds sizeof(uint64_t))) { 27861da177e4SLinus Torvalds hdr = NULL; 27871da177e4SLinus Torvalds *errp = -EMSGSIZE; 27881da177e4SLinus Torvalds } else { 27891da177e4SLinus Torvalds *errp = 0; 27901da177e4SLinus Torvalds } 27911da177e4SLinus Torvalds } 27921da177e4SLinus Torvalds return hdr; 27931da177e4SLinus Torvalds } 27941da177e4SLinus Torvalds 2795*4c93fbb0SDavid S. Miller static inline int aalg_tmpl_set(const struct xfrm_tmpl *t, 2796*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *d) 27971da177e4SLinus Torvalds { 2798f398035fSHerbert Xu unsigned int id = d->desc.sadb_alg_id; 2799f398035fSHerbert Xu 2800f398035fSHerbert Xu if (id >= sizeof(t->aalgos) * 8) 2801f398035fSHerbert Xu return 0; 2802f398035fSHerbert Xu 2803f398035fSHerbert Xu return (t->aalgos >> id) & 1; 28041da177e4SLinus Torvalds } 28051da177e4SLinus Torvalds 2806*4c93fbb0SDavid S. Miller static inline int ealg_tmpl_set(const struct xfrm_tmpl *t, 2807*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *d) 28081da177e4SLinus Torvalds { 2809f398035fSHerbert Xu unsigned int id = d->desc.sadb_alg_id; 2810f398035fSHerbert Xu 2811f398035fSHerbert Xu if (id >= sizeof(t->ealgos) * 8) 2812f398035fSHerbert Xu return 0; 2813f398035fSHerbert Xu 2814f398035fSHerbert Xu return (t->ealgos >> id) & 1; 28151da177e4SLinus Torvalds } 28161da177e4SLinus Torvalds 2817*4c93fbb0SDavid S. Miller static int count_ah_combs(const struct xfrm_tmpl *t) 28181da177e4SLinus Torvalds { 28191da177e4SLinus Torvalds int i, sz = 0; 28201da177e4SLinus Torvalds 28211da177e4SLinus Torvalds for (i = 0; ; i++) { 2822*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 28231da177e4SLinus Torvalds if (!aalg) 28241da177e4SLinus Torvalds break; 28251da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 28261da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 28271da177e4SLinus Torvalds } 28281da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 28291da177e4SLinus Torvalds } 28301da177e4SLinus Torvalds 2831*4c93fbb0SDavid S. Miller static int count_esp_combs(const struct xfrm_tmpl *t) 28321da177e4SLinus Torvalds { 28331da177e4SLinus Torvalds int i, k, sz = 0; 28341da177e4SLinus Torvalds 28351da177e4SLinus Torvalds for (i = 0; ; i++) { 2836*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 28371da177e4SLinus Torvalds if (!ealg) 28381da177e4SLinus Torvalds break; 28391da177e4SLinus Torvalds 28401da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 28411da177e4SLinus Torvalds continue; 28421da177e4SLinus Torvalds 28431da177e4SLinus Torvalds for (k = 1; ; k++) { 2844*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 28451da177e4SLinus Torvalds if (!aalg) 28461da177e4SLinus Torvalds break; 28471da177e4SLinus Torvalds 28481da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 28491da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 28501da177e4SLinus Torvalds } 28511da177e4SLinus Torvalds } 28521da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 28531da177e4SLinus Torvalds } 28541da177e4SLinus Torvalds 2855*4c93fbb0SDavid S. Miller static void dump_ah_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) 28561da177e4SLinus Torvalds { 28571da177e4SLinus Torvalds struct sadb_prop *p; 28581da177e4SLinus Torvalds int i; 28591da177e4SLinus Torvalds 28601da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28611da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28621da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28631da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28641da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28651da177e4SLinus Torvalds 28661da177e4SLinus Torvalds for (i = 0; ; i++) { 2867*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 28681da177e4SLinus Torvalds if (!aalg) 28691da177e4SLinus Torvalds break; 28701da177e4SLinus Torvalds 28711da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) { 28721da177e4SLinus Torvalds struct sadb_comb *c; 28731da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 28741da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 28751da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 28761da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 28771da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 28781da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 28791da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 28801da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 28811da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 28821da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 28831da177e4SLinus Torvalds } 28841da177e4SLinus Torvalds } 28851da177e4SLinus Torvalds } 28861da177e4SLinus Torvalds 2887*4c93fbb0SDavid S. Miller static void dump_esp_combs(struct sk_buff *skb, const struct xfrm_tmpl *t) 28881da177e4SLinus Torvalds { 28891da177e4SLinus Torvalds struct sadb_prop *p; 28901da177e4SLinus Torvalds int i, k; 28911da177e4SLinus Torvalds 28921da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28931da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28941da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28951da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28961da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28971da177e4SLinus Torvalds 28981da177e4SLinus Torvalds for (i=0; ; i++) { 2899*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 29001da177e4SLinus Torvalds if (!ealg) 29011da177e4SLinus Torvalds break; 29021da177e4SLinus Torvalds 29031da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 29041da177e4SLinus Torvalds continue; 29051da177e4SLinus Torvalds 29061da177e4SLinus Torvalds for (k = 1; ; k++) { 29071da177e4SLinus Torvalds struct sadb_comb *c; 2908*4c93fbb0SDavid S. Miller const struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 29091da177e4SLinus Torvalds if (!aalg) 29101da177e4SLinus Torvalds break; 29111da177e4SLinus Torvalds if (!(aalg_tmpl_set(t, aalg) && aalg->available)) 29121da177e4SLinus Torvalds continue; 29131da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 29141da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 29151da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 29161da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 29171da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 29181da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 29191da177e4SLinus Torvalds c->sadb_comb_encrypt = ealg->desc.sadb_alg_id; 29201da177e4SLinus Torvalds c->sadb_comb_encrypt_minbits = ealg->desc.sadb_alg_minbits; 29211da177e4SLinus Torvalds c->sadb_comb_encrypt_maxbits = ealg->desc.sadb_alg_maxbits; 29221da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 29231da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 29241da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 29251da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 29261da177e4SLinus Torvalds } 29271da177e4SLinus Torvalds } 29281da177e4SLinus Torvalds } 29291da177e4SLinus Torvalds 2930214e005bSDavid S. Miller static int key_notify_policy_expire(struct xfrm_policy *xp, const struct km_event *c) 293126b15dadSJamal Hadi Salim { 293226b15dadSJamal Hadi Salim return 0; 293326b15dadSJamal Hadi Salim } 293426b15dadSJamal Hadi Salim 2935214e005bSDavid S. Miller static int key_notify_sa_expire(struct xfrm_state *x, const struct km_event *c) 29361da177e4SLinus Torvalds { 29371da177e4SLinus Torvalds struct sk_buff *out_skb; 29381da177e4SLinus Torvalds struct sadb_msg *out_hdr; 293926b15dadSJamal Hadi Salim int hard; 294026b15dadSJamal Hadi Salim int hsc; 294126b15dadSJamal Hadi Salim 2942bf08867fSHerbert Xu hard = c->data.hard; 294326b15dadSJamal Hadi Salim if (hard) 294426b15dadSJamal Hadi Salim hsc = 2; 294526b15dadSJamal Hadi Salim else 294626b15dadSJamal Hadi Salim hsc = 1; 29471da177e4SLinus Torvalds 2948050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg_expire(x, hsc); 29491da177e4SLinus Torvalds if (IS_ERR(out_skb)) 29501da177e4SLinus Torvalds return PTR_ERR(out_skb); 29511da177e4SLinus Torvalds 29521da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 29531da177e4SLinus Torvalds out_hdr->sadb_msg_version = PF_KEY_V2; 29541da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_EXPIRE; 29551da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 29561da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 29571da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 29581da177e4SLinus Torvalds out_hdr->sadb_msg_seq = 0; 29591da177e4SLinus Torvalds out_hdr->sadb_msg_pid = 0; 29601da177e4SLinus Torvalds 296107fb0f17SAlexey Dobriyan pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); 29621da177e4SLinus Torvalds return 0; 29631da177e4SLinus Torvalds } 29641da177e4SLinus Torvalds 2965214e005bSDavid S. Miller static int pfkey_send_notify(struct xfrm_state *x, const struct km_event *c) 296626b15dadSJamal Hadi Salim { 296707fb0f17SAlexey Dobriyan struct net *net = x ? xs_net(x) : c->net; 29683fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 29693fa87a32SAlexey Dobriyan 29703fa87a32SAlexey Dobriyan if (atomic_read(&net_pfkey->socks_nr) == 0) 297199c6f60eSJamal Hadi Salim return 0; 297299c6f60eSJamal Hadi Salim 297326b15dadSJamal Hadi Salim switch (c->event) { 2974f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 297526b15dadSJamal Hadi Salim return key_notify_sa_expire(x, c); 2976f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 2977f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 2978f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 297926b15dadSJamal Hadi Salim return key_notify_sa(x, c); 2980f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 298126b15dadSJamal Hadi Salim return key_notify_sa_flush(c); 2982d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: /* not yet supported */ 2983d51d081dSJamal Hadi Salim break; 298426b15dadSJamal Hadi Salim default: 2985207024b9Sstephen hemminger pr_err("pfkey: Unknown SA event %d\n", c->event); 298626b15dadSJamal Hadi Salim break; 298726b15dadSJamal Hadi Salim } 298826b15dadSJamal Hadi Salim 298926b15dadSJamal Hadi Salim return 0; 299026b15dadSJamal Hadi Salim } 299126b15dadSJamal Hadi Salim 2992214e005bSDavid S. Miller static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, const struct km_event *c) 299326b15dadSJamal Hadi Salim { 2994f7b6983fSMasahide NAKAMURA if (xp && xp->type != XFRM_POLICY_TYPE_MAIN) 2995f7b6983fSMasahide NAKAMURA return 0; 2996f7b6983fSMasahide NAKAMURA 299726b15dadSJamal Hadi Salim switch (c->event) { 2998f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 299926b15dadSJamal Hadi Salim return key_notify_policy_expire(xp, c); 3000f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 3001f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 3002f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 300326b15dadSJamal Hadi Salim return key_notify_policy(xp, dir, c); 3004f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 3005f7b6983fSMasahide NAKAMURA if (c->data.type != XFRM_POLICY_TYPE_MAIN) 3006f7b6983fSMasahide NAKAMURA break; 300726b15dadSJamal Hadi Salim return key_notify_policy_flush(c); 300826b15dadSJamal Hadi Salim default: 3009207024b9Sstephen hemminger pr_err("pfkey: Unknown policy event %d\n", c->event); 301026b15dadSJamal Hadi Salim break; 301126b15dadSJamal Hadi Salim } 301226b15dadSJamal Hadi Salim 301326b15dadSJamal Hadi Salim return 0; 301426b15dadSJamal Hadi Salim } 301526b15dadSJamal Hadi Salim 30161da177e4SLinus Torvalds static u32 get_acqseq(void) 30171da177e4SLinus Torvalds { 30181da177e4SLinus Torvalds u32 res; 301928aecb9dSEric Dumazet static atomic_t acqseq; 30201da177e4SLinus Torvalds 302128aecb9dSEric Dumazet do { 302228aecb9dSEric Dumazet res = atomic_inc_return(&acqseq); 302328aecb9dSEric Dumazet } while (!res); 30241da177e4SLinus Torvalds return res; 30251da177e4SLinus Torvalds } 30261da177e4SLinus Torvalds 30271da177e4SLinus Torvalds static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir) 30281da177e4SLinus Torvalds { 30291da177e4SLinus Torvalds struct sk_buff *skb; 30301da177e4SLinus Torvalds struct sadb_msg *hdr; 30311da177e4SLinus Torvalds struct sadb_address *addr; 30321da177e4SLinus Torvalds struct sadb_x_policy *pol; 30331da177e4SLinus Torvalds int sockaddr_size; 30341da177e4SLinus Torvalds int size; 30354e2ba18eSVenkat Yekkirala struct sadb_x_sec_ctx *sec_ctx; 30364e2ba18eSVenkat Yekkirala struct xfrm_sec_ctx *xfrm_ctx; 30374e2ba18eSVenkat Yekkirala int ctx_size = 0; 30381da177e4SLinus Torvalds 30391da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 30401da177e4SLinus Torvalds if (!sockaddr_size) 30411da177e4SLinus Torvalds return -EINVAL; 30421da177e4SLinus Torvalds 30431da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 30441da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 30451da177e4SLinus Torvalds (sockaddr_size * 2) + 30461da177e4SLinus Torvalds sizeof(struct sadb_x_policy); 30471da177e4SLinus Torvalds 30481da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 30491da177e4SLinus Torvalds size += count_ah_combs(t); 30501da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 30511da177e4SLinus Torvalds size += count_esp_combs(t); 30521da177e4SLinus Torvalds 30534e2ba18eSVenkat Yekkirala if ((xfrm_ctx = x->security)) { 30544e2ba18eSVenkat Yekkirala ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 30554e2ba18eSVenkat Yekkirala size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 30564e2ba18eSVenkat Yekkirala } 30574e2ba18eSVenkat Yekkirala 30581da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 30591da177e4SLinus Torvalds if (skb == NULL) 30601da177e4SLinus Torvalds return -ENOMEM; 30611da177e4SLinus Torvalds 30621da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 30631da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 30641da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_ACQUIRE; 30651da177e4SLinus Torvalds hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 30661da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 30671da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 30681da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 30691da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 30701da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds /* src address */ 30731da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30741da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30751da177e4SLinus Torvalds addr->sadb_address_len = 30761da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30771da177e4SLinus Torvalds sizeof(uint64_t); 30781da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 30791da177e4SLinus Torvalds addr->sadb_address_proto = 0; 30801da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 3081e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 3082e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->props.saddr, 0, 3083e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 3084e5b56652SYOSHIFUJI Hideaki x->props.family); 3085e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 30861da177e4SLinus Torvalds BUG(); 30871da177e4SLinus Torvalds 30881da177e4SLinus Torvalds /* dst address */ 30891da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30901da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30911da177e4SLinus Torvalds addr->sadb_address_len = 30921da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30931da177e4SLinus Torvalds sizeof(uint64_t); 30941da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 30951da177e4SLinus Torvalds addr->sadb_address_proto = 0; 30961da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 3097e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 3098e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->id.daddr, 0, 3099e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 3100e5b56652SYOSHIFUJI Hideaki x->props.family); 3101e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 31021da177e4SLinus Torvalds BUG(); 31031da177e4SLinus Torvalds 31041da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 31051da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 31061da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 31071da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 31081da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 31091da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 31101da177e4SLinus Torvalds 31111da177e4SLinus Torvalds /* Set sadb_comb's. */ 31121da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 31131da177e4SLinus Torvalds dump_ah_combs(skb, t); 31141da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 31151da177e4SLinus Torvalds dump_esp_combs(skb, t); 31161da177e4SLinus Torvalds 31174e2ba18eSVenkat Yekkirala /* security context */ 31184e2ba18eSVenkat Yekkirala if (xfrm_ctx) { 31194e2ba18eSVenkat Yekkirala sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, 31204e2ba18eSVenkat Yekkirala sizeof(struct sadb_x_sec_ctx) + ctx_size); 31214e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_len = 31224e2ba18eSVenkat Yekkirala (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); 31234e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 31244e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 31254e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 31264e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 31274e2ba18eSVenkat Yekkirala memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 31284e2ba18eSVenkat Yekkirala xfrm_ctx->ctx_len); 31294e2ba18eSVenkat Yekkirala } 31304e2ba18eSVenkat Yekkirala 313107fb0f17SAlexey Dobriyan return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); 31321da177e4SLinus Torvalds } 31331da177e4SLinus Torvalds 3134cb969f07SVenkat Yekkirala static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, 31351da177e4SLinus Torvalds u8 *data, int len, int *dir) 31361da177e4SLinus Torvalds { 313707fb0f17SAlexey Dobriyan struct net *net = sock_net(sk); 31381da177e4SLinus Torvalds struct xfrm_policy *xp; 31391da177e4SLinus Torvalds struct sadb_x_policy *pol = (struct sadb_x_policy*)data; 3140df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 31411da177e4SLinus Torvalds 3142cb969f07SVenkat Yekkirala switch (sk->sk_family) { 31431da177e4SLinus Torvalds case AF_INET: 31441da177e4SLinus Torvalds if (opt != IP_IPSEC_POLICY) { 31451da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31461da177e4SLinus Torvalds return NULL; 31471da177e4SLinus Torvalds } 31481da177e4SLinus Torvalds break; 31491da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 31501da177e4SLinus Torvalds case AF_INET6: 31511da177e4SLinus Torvalds if (opt != IPV6_IPSEC_POLICY) { 31521da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31531da177e4SLinus Torvalds return NULL; 31541da177e4SLinus Torvalds } 31551da177e4SLinus Torvalds break; 31561da177e4SLinus Torvalds #endif 31571da177e4SLinus Torvalds default: 31581da177e4SLinus Torvalds *dir = -EINVAL; 31591da177e4SLinus Torvalds return NULL; 31601da177e4SLinus Torvalds } 31611da177e4SLinus Torvalds 31621da177e4SLinus Torvalds *dir = -EINVAL; 31631da177e4SLinus Torvalds 31641da177e4SLinus Torvalds if (len < sizeof(struct sadb_x_policy) || 31651da177e4SLinus Torvalds pol->sadb_x_policy_len*8 > len || 31661da177e4SLinus Torvalds pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS || 31671da177e4SLinus Torvalds (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND)) 31681da177e4SLinus Torvalds return NULL; 31691da177e4SLinus Torvalds 317007fb0f17SAlexey Dobriyan xp = xfrm_policy_alloc(net, GFP_ATOMIC); 31711da177e4SLinus Torvalds if (xp == NULL) { 31721da177e4SLinus Torvalds *dir = -ENOBUFS; 31731da177e4SLinus Torvalds return NULL; 31741da177e4SLinus Torvalds } 31751da177e4SLinus Torvalds 31761da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 31771da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 31781da177e4SLinus Torvalds 31791da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 31801da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 31811da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 31821da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 3183cb969f07SVenkat Yekkirala xp->family = sk->sk_family; 31841da177e4SLinus Torvalds 31851da177e4SLinus Torvalds xp->xfrm_nr = 0; 31861da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 31871da177e4SLinus Torvalds (*dir = parse_ipsecrequests(xp, pol)) < 0) 31881da177e4SLinus Torvalds goto out; 31891da177e4SLinus Torvalds 3190df71837dSTrent Jaeger /* security context too */ 3191df71837dSTrent Jaeger if (len >= (pol->sadb_x_policy_len*8 + 3192df71837dSTrent Jaeger sizeof(struct sadb_x_sec_ctx))) { 3193df71837dSTrent Jaeger char *p = (char *)pol; 3194df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 3195df71837dSTrent Jaeger 3196df71837dSTrent Jaeger p += pol->sadb_x_policy_len*8; 3197df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *)p; 3198df71837dSTrent Jaeger if (len < pol->sadb_x_policy_len*8 + 3199cb969f07SVenkat Yekkirala sec_ctx->sadb_x_sec_len) { 3200cb969f07SVenkat Yekkirala *dir = -EINVAL; 3201df71837dSTrent Jaeger goto out; 3202cb969f07SVenkat Yekkirala } 3203df71837dSTrent Jaeger if ((*dir = verify_sec_ctx_len(p))) 3204df71837dSTrent Jaeger goto out; 3205df71837dSTrent Jaeger uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 320603e1ad7bSPaul Moore *dir = security_xfrm_policy_alloc(&xp->security, uctx); 3207df71837dSTrent Jaeger kfree(uctx); 3208df71837dSTrent Jaeger 3209df71837dSTrent Jaeger if (*dir) 3210df71837dSTrent Jaeger goto out; 3211df71837dSTrent Jaeger } 3212df71837dSTrent Jaeger 32131da177e4SLinus Torvalds *dir = pol->sadb_x_policy_dir-1; 32141da177e4SLinus Torvalds return xp; 32151da177e4SLinus Torvalds 32161da177e4SLinus Torvalds out: 321770e90679SAlexey Dobriyan xp->walk.dead = 1; 321864c31b3fSWANG Cong xfrm_policy_destroy(xp); 32191da177e4SLinus Torvalds return NULL; 32201da177e4SLinus Torvalds } 32211da177e4SLinus Torvalds 32225d36b180SAl Viro static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 32231da177e4SLinus Torvalds { 32241da177e4SLinus Torvalds struct sk_buff *skb; 32251da177e4SLinus Torvalds struct sadb_msg *hdr; 32261da177e4SLinus Torvalds struct sadb_sa *sa; 32271da177e4SLinus Torvalds struct sadb_address *addr; 32281da177e4SLinus Torvalds struct sadb_x_nat_t_port *n_port; 32291da177e4SLinus Torvalds int sockaddr_size; 32301da177e4SLinus Torvalds int size; 32311da177e4SLinus Torvalds __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0); 32321da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 32331da177e4SLinus Torvalds 32341da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 32351da177e4SLinus Torvalds if (!sockaddr_size) 32361da177e4SLinus Torvalds return -EINVAL; 32371da177e4SLinus Torvalds 32381da177e4SLinus Torvalds if (!satype) 32391da177e4SLinus Torvalds return -EINVAL; 32401da177e4SLinus Torvalds 32411da177e4SLinus Torvalds if (!x->encap) 32421da177e4SLinus Torvalds return -EINVAL; 32431da177e4SLinus Torvalds 32441da177e4SLinus Torvalds natt = x->encap; 32451da177e4SLinus Torvalds 32461da177e4SLinus Torvalds /* Build an SADB_X_NAT_T_NEW_MAPPING message: 32471da177e4SLinus Torvalds * 32481da177e4SLinus Torvalds * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) | 32491da177e4SLinus Torvalds * ADDRESS_DST (new addr) | NAT_T_DPORT (new port) 32501da177e4SLinus Torvalds */ 32511da177e4SLinus Torvalds 32521da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 32531da177e4SLinus Torvalds sizeof(struct sadb_sa) + 32541da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 32551da177e4SLinus Torvalds (sockaddr_size * 2) + 32561da177e4SLinus Torvalds (sizeof(struct sadb_x_nat_t_port) * 2); 32571da177e4SLinus Torvalds 32581da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 32591da177e4SLinus Torvalds if (skb == NULL) 32601da177e4SLinus Torvalds return -ENOMEM; 32611da177e4SLinus Torvalds 32621da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 32631da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 32641da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING; 32651da177e4SLinus Torvalds hdr->sadb_msg_satype = satype; 32661da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 32671da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 32681da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 32691da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 32701da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 32711da177e4SLinus Torvalds 32721da177e4SLinus Torvalds /* SA */ 32731da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 32741da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 32751da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 32761da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 32771da177e4SLinus Torvalds sa->sadb_sa_replay = 0; 32781da177e4SLinus Torvalds sa->sadb_sa_state = 0; 32791da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 32801da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 32811da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 32821da177e4SLinus Torvalds 32831da177e4SLinus Torvalds /* ADDRESS_SRC (old addr) */ 32841da177e4SLinus Torvalds addr = (struct sadb_address*) 32851da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 32861da177e4SLinus Torvalds addr->sadb_address_len = 32871da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 32881da177e4SLinus Torvalds sizeof(uint64_t); 32891da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 32901da177e4SLinus Torvalds addr->sadb_address_proto = 0; 32911da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 3292e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 3293e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&x->props.saddr, 0, 3294e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 3295e5b56652SYOSHIFUJI Hideaki x->props.family); 3296e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 32971da177e4SLinus Torvalds BUG(); 32981da177e4SLinus Torvalds 32991da177e4SLinus Torvalds /* NAT_T_SPORT (old port) */ 33001da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33011da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33021da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; 33031da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_sport; 33041da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33051da177e4SLinus Torvalds 33061da177e4SLinus Torvalds /* ADDRESS_DST (new addr) */ 33071da177e4SLinus Torvalds addr = (struct sadb_address*) 33081da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 33091da177e4SLinus Torvalds addr->sadb_address_len = 33101da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 33111da177e4SLinus Torvalds sizeof(uint64_t); 33121da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 33131da177e4SLinus Torvalds addr->sadb_address_proto = 0; 33141da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 3315e5b56652SYOSHIFUJI Hideaki addr->sadb_address_prefixlen = 3316e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(ipaddr, 0, 3317e5b56652SYOSHIFUJI Hideaki (struct sockaddr *) (addr + 1), 3318e5b56652SYOSHIFUJI Hideaki x->props.family); 3319e5b56652SYOSHIFUJI Hideaki if (!addr->sadb_address_prefixlen) 33201da177e4SLinus Torvalds BUG(); 33211da177e4SLinus Torvalds 33221da177e4SLinus Torvalds /* NAT_T_DPORT (new port) */ 33231da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33241da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33251da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; 33261da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = sport; 33271da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33281da177e4SLinus Torvalds 332907fb0f17SAlexey Dobriyan return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL, xs_net(x)); 33301da177e4SLinus Torvalds } 33311da177e4SLinus Torvalds 333208de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 333308de61beSShinta Sugimoto static int set_sadb_address(struct sk_buff *skb, int sasize, int type, 3334183cad12SDavid S. Miller const struct xfrm_selector *sel) 333508de61beSShinta Sugimoto { 333608de61beSShinta Sugimoto struct sadb_address *addr; 333708de61beSShinta Sugimoto addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); 333808de61beSShinta Sugimoto addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; 333908de61beSShinta Sugimoto addr->sadb_address_exttype = type; 334008de61beSShinta Sugimoto addr->sadb_address_proto = sel->proto; 334108de61beSShinta Sugimoto addr->sadb_address_reserved = 0; 334208de61beSShinta Sugimoto 334308de61beSShinta Sugimoto switch (type) { 334408de61beSShinta Sugimoto case SADB_EXT_ADDRESS_SRC: 334508de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_s; 3346e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&sel->saddr, 0, 3347e5b56652SYOSHIFUJI Hideaki (struct sockaddr *)(addr + 1), 3348e5b56652SYOSHIFUJI Hideaki sel->family); 334908de61beSShinta Sugimoto break; 335008de61beSShinta Sugimoto case SADB_EXT_ADDRESS_DST: 335108de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_d; 3352e5b56652SYOSHIFUJI Hideaki pfkey_sockaddr_fill(&sel->daddr, 0, 3353e5b56652SYOSHIFUJI Hideaki (struct sockaddr *)(addr + 1), 3354e5b56652SYOSHIFUJI Hideaki sel->family); 335508de61beSShinta Sugimoto break; 335608de61beSShinta Sugimoto default: 335708de61beSShinta Sugimoto return -EINVAL; 335808de61beSShinta Sugimoto } 335908de61beSShinta Sugimoto 336008de61beSShinta Sugimoto return 0; 336108de61beSShinta Sugimoto } 336208de61beSShinta Sugimoto 336313c1d189SArnaud Ebalard 3364183cad12SDavid S. Miller static int set_sadb_kmaddress(struct sk_buff *skb, const struct xfrm_kmaddress *k) 336513c1d189SArnaud Ebalard { 336613c1d189SArnaud Ebalard struct sadb_x_kmaddress *kma; 336713c1d189SArnaud Ebalard u8 *sa; 336813c1d189SArnaud Ebalard int family = k->family; 336913c1d189SArnaud Ebalard int socklen = pfkey_sockaddr_len(family); 337013c1d189SArnaud Ebalard int size_req; 337113c1d189SArnaud Ebalard 337213c1d189SArnaud Ebalard size_req = (sizeof(struct sadb_x_kmaddress) + 337313c1d189SArnaud Ebalard pfkey_sockaddr_pair_size(family)); 337413c1d189SArnaud Ebalard 337513c1d189SArnaud Ebalard kma = (struct sadb_x_kmaddress *)skb_put(skb, size_req); 337613c1d189SArnaud Ebalard memset(kma, 0, size_req); 337713c1d189SArnaud Ebalard kma->sadb_x_kmaddress_len = size_req / 8; 337813c1d189SArnaud Ebalard kma->sadb_x_kmaddress_exttype = SADB_X_EXT_KMADDRESS; 337913c1d189SArnaud Ebalard kma->sadb_x_kmaddress_reserved = k->reserved; 338013c1d189SArnaud Ebalard 338113c1d189SArnaud Ebalard sa = (u8 *)(kma + 1); 338213c1d189SArnaud Ebalard if (!pfkey_sockaddr_fill(&k->local, 0, (struct sockaddr *)sa, family) || 338313c1d189SArnaud Ebalard !pfkey_sockaddr_fill(&k->remote, 0, (struct sockaddr *)(sa+socklen), family)) 338413c1d189SArnaud Ebalard return -EINVAL; 338513c1d189SArnaud Ebalard 338613c1d189SArnaud Ebalard return 0; 338713c1d189SArnaud Ebalard } 338813c1d189SArnaud Ebalard 338908de61beSShinta Sugimoto static int set_ipsecrequest(struct sk_buff *skb, 339008de61beSShinta Sugimoto uint8_t proto, uint8_t mode, int level, 339108de61beSShinta Sugimoto uint32_t reqid, uint8_t family, 3392183cad12SDavid S. Miller const xfrm_address_t *src, const xfrm_address_t *dst) 339308de61beSShinta Sugimoto { 339408de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 3395e5b56652SYOSHIFUJI Hideaki u8 *sa; 3396e5b56652SYOSHIFUJI Hideaki int socklen = pfkey_sockaddr_len(family); 339708de61beSShinta Sugimoto int size_req; 339808de61beSShinta Sugimoto 339908de61beSShinta Sugimoto size_req = sizeof(struct sadb_x_ipsecrequest) + 340008de61beSShinta Sugimoto pfkey_sockaddr_pair_size(family); 340108de61beSShinta Sugimoto 340208de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req); 340308de61beSShinta Sugimoto memset(rq, 0, size_req); 340408de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_len = size_req; 340508de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_proto = proto; 340608de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_mode = mode; 340708de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_level = level; 340808de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_reqid = reqid; 340908de61beSShinta Sugimoto 3410e5b56652SYOSHIFUJI Hideaki sa = (u8 *) (rq + 1); 3411e5b56652SYOSHIFUJI Hideaki if (!pfkey_sockaddr_fill(src, 0, (struct sockaddr *)sa, family) || 3412e5b56652SYOSHIFUJI Hideaki !pfkey_sockaddr_fill(dst, 0, (struct sockaddr *)(sa + socklen), family)) 341308de61beSShinta Sugimoto return -EINVAL; 341408de61beSShinta Sugimoto 341508de61beSShinta Sugimoto return 0; 341608de61beSShinta Sugimoto } 341708de61beSShinta Sugimoto #endif 341808de61beSShinta Sugimoto 341908de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 3420183cad12SDavid S. Miller static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 3421183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_bundles, 3422183cad12SDavid S. Miller const struct xfrm_kmaddress *k) 342308de61beSShinta Sugimoto { 342408de61beSShinta Sugimoto int i; 342508de61beSShinta Sugimoto int sasize_sel; 342608de61beSShinta Sugimoto int size = 0; 342708de61beSShinta Sugimoto int size_pol = 0; 342808de61beSShinta Sugimoto struct sk_buff *skb; 342908de61beSShinta Sugimoto struct sadb_msg *hdr; 343008de61beSShinta Sugimoto struct sadb_x_policy *pol; 3431183cad12SDavid S. Miller const struct xfrm_migrate *mp; 343208de61beSShinta Sugimoto 343308de61beSShinta Sugimoto if (type != XFRM_POLICY_TYPE_MAIN) 343408de61beSShinta Sugimoto return 0; 343508de61beSShinta Sugimoto 343608de61beSShinta Sugimoto if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) 343708de61beSShinta Sugimoto return -EINVAL; 343808de61beSShinta Sugimoto 343913c1d189SArnaud Ebalard if (k != NULL) { 344013c1d189SArnaud Ebalard /* addresses for KM */ 344113c1d189SArnaud Ebalard size += PFKEY_ALIGN8(sizeof(struct sadb_x_kmaddress) + 344213c1d189SArnaud Ebalard pfkey_sockaddr_pair_size(k->family)); 344313c1d189SArnaud Ebalard } 344413c1d189SArnaud Ebalard 344508de61beSShinta Sugimoto /* selector */ 344608de61beSShinta Sugimoto sasize_sel = pfkey_sockaddr_size(sel->family); 344708de61beSShinta Sugimoto if (!sasize_sel) 344808de61beSShinta Sugimoto return -EINVAL; 344908de61beSShinta Sugimoto size += (sizeof(struct sadb_address) + sasize_sel) * 2; 345008de61beSShinta Sugimoto 345108de61beSShinta Sugimoto /* policy info */ 345208de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_policy); 345308de61beSShinta Sugimoto 345408de61beSShinta Sugimoto /* ipsecrequests */ 345508de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 345608de61beSShinta Sugimoto /* old locator pair */ 345708de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 345808de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->old_family); 345908de61beSShinta Sugimoto /* new locator pair */ 346008de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 346108de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->new_family); 346208de61beSShinta Sugimoto } 346308de61beSShinta Sugimoto 346408de61beSShinta Sugimoto size += sizeof(struct sadb_msg) + size_pol; 346508de61beSShinta Sugimoto 346608de61beSShinta Sugimoto /* alloc buffer */ 346708de61beSShinta Sugimoto skb = alloc_skb(size, GFP_ATOMIC); 346808de61beSShinta Sugimoto if (skb == NULL) 346908de61beSShinta Sugimoto return -ENOMEM; 347008de61beSShinta Sugimoto 347108de61beSShinta Sugimoto hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg)); 347208de61beSShinta Sugimoto hdr->sadb_msg_version = PF_KEY_V2; 347308de61beSShinta Sugimoto hdr->sadb_msg_type = SADB_X_MIGRATE; 347408de61beSShinta Sugimoto hdr->sadb_msg_satype = pfkey_proto2satype(m->proto); 347508de61beSShinta Sugimoto hdr->sadb_msg_len = size / 8; 347608de61beSShinta Sugimoto hdr->sadb_msg_errno = 0; 347708de61beSShinta Sugimoto hdr->sadb_msg_reserved = 0; 347808de61beSShinta Sugimoto hdr->sadb_msg_seq = 0; 347908de61beSShinta Sugimoto hdr->sadb_msg_pid = 0; 348008de61beSShinta Sugimoto 348113c1d189SArnaud Ebalard /* Addresses to be used by KM for negotiation, if ext is available */ 348213c1d189SArnaud Ebalard if (k != NULL && (set_sadb_kmaddress(skb, k) < 0)) 348313c1d189SArnaud Ebalard return -EINVAL; 348413c1d189SArnaud Ebalard 348508de61beSShinta Sugimoto /* selector src */ 348608de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); 348708de61beSShinta Sugimoto 348808de61beSShinta Sugimoto /* selector dst */ 348908de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel); 349008de61beSShinta Sugimoto 349108de61beSShinta Sugimoto /* policy information */ 349208de61beSShinta Sugimoto pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy)); 349308de61beSShinta Sugimoto pol->sadb_x_policy_len = size_pol / 8; 349408de61beSShinta Sugimoto pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 349508de61beSShinta Sugimoto pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 349608de61beSShinta Sugimoto pol->sadb_x_policy_dir = dir + 1; 349708de61beSShinta Sugimoto pol->sadb_x_policy_id = 0; 349808de61beSShinta Sugimoto pol->sadb_x_policy_priority = 0; 349908de61beSShinta Sugimoto 350008de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 350108de61beSShinta Sugimoto /* old ipsecrequest */ 350255569ce2SKazunori MIYAZAWA int mode = pfkey_mode_from_xfrm(mp->mode); 350355569ce2SKazunori MIYAZAWA if (mode < 0) 3504d4782c32SPatrick McHardy goto err; 350555569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 350608de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 350708de61beSShinta Sugimoto mp->reqid, mp->old_family, 3508d4782c32SPatrick McHardy &mp->old_saddr, &mp->old_daddr) < 0) 3509d4782c32SPatrick McHardy goto err; 351008de61beSShinta Sugimoto 351108de61beSShinta Sugimoto /* new ipsecrequest */ 351255569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 351308de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 351408de61beSShinta Sugimoto mp->reqid, mp->new_family, 3515d4782c32SPatrick McHardy &mp->new_saddr, &mp->new_daddr) < 0) 3516d4782c32SPatrick McHardy goto err; 351708de61beSShinta Sugimoto } 351808de61beSShinta Sugimoto 351908de61beSShinta Sugimoto /* broadcast migrate message to sockets */ 352007fb0f17SAlexey Dobriyan pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL, &init_net); 352108de61beSShinta Sugimoto 352208de61beSShinta Sugimoto return 0; 3523d4782c32SPatrick McHardy 3524d4782c32SPatrick McHardy err: 3525d4782c32SPatrick McHardy kfree_skb(skb); 3526d4782c32SPatrick McHardy return -EINVAL; 352708de61beSShinta Sugimoto } 352808de61beSShinta Sugimoto #else 3529183cad12SDavid S. Miller static int pfkey_send_migrate(const struct xfrm_selector *sel, u8 dir, u8 type, 3530183cad12SDavid S. Miller const struct xfrm_migrate *m, int num_bundles, 3531183cad12SDavid S. Miller const struct xfrm_kmaddress *k) 353208de61beSShinta Sugimoto { 353308de61beSShinta Sugimoto return -ENOPROTOOPT; 353408de61beSShinta Sugimoto } 353508de61beSShinta Sugimoto #endif 353608de61beSShinta Sugimoto 35371da177e4SLinus Torvalds static int pfkey_sendmsg(struct kiocb *kiocb, 35381da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len) 35391da177e4SLinus Torvalds { 35401da177e4SLinus Torvalds struct sock *sk = sock->sk; 35411da177e4SLinus Torvalds struct sk_buff *skb = NULL; 35421da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 35431da177e4SLinus Torvalds int err; 35441da177e4SLinus Torvalds 35451da177e4SLinus Torvalds err = -EOPNOTSUPP; 35461da177e4SLinus Torvalds if (msg->msg_flags & MSG_OOB) 35471da177e4SLinus Torvalds goto out; 35481da177e4SLinus Torvalds 35491da177e4SLinus Torvalds err = -EMSGSIZE; 35501da177e4SLinus Torvalds if ((unsigned)len > sk->sk_sndbuf - 32) 35511da177e4SLinus Torvalds goto out; 35521da177e4SLinus Torvalds 35531da177e4SLinus Torvalds err = -ENOBUFS; 35541da177e4SLinus Torvalds skb = alloc_skb(len, GFP_KERNEL); 35551da177e4SLinus Torvalds if (skb == NULL) 35561da177e4SLinus Torvalds goto out; 35571da177e4SLinus Torvalds 35581da177e4SLinus Torvalds err = -EFAULT; 35591da177e4SLinus Torvalds if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) 35601da177e4SLinus Torvalds goto out; 35611da177e4SLinus Torvalds 35621da177e4SLinus Torvalds hdr = pfkey_get_base_msg(skb, &err); 35631da177e4SLinus Torvalds if (!hdr) 35641da177e4SLinus Torvalds goto out; 35651da177e4SLinus Torvalds 35664a3e2f71SArjan van de Ven mutex_lock(&xfrm_cfg_mutex); 35671da177e4SLinus Torvalds err = pfkey_process(sk, skb, hdr); 35684a3e2f71SArjan van de Ven mutex_unlock(&xfrm_cfg_mutex); 35691da177e4SLinus Torvalds 35701da177e4SLinus Torvalds out: 35711da177e4SLinus Torvalds if (err && hdr && pfkey_error(hdr, err, sk) == 0) 35721da177e4SLinus Torvalds err = 0; 35731da177e4SLinus Torvalds kfree_skb(skb); 35741da177e4SLinus Torvalds 35751da177e4SLinus Torvalds return err ? : len; 35761da177e4SLinus Torvalds } 35771da177e4SLinus Torvalds 35781da177e4SLinus Torvalds static int pfkey_recvmsg(struct kiocb *kiocb, 35791da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len, 35801da177e4SLinus Torvalds int flags) 35811da177e4SLinus Torvalds { 35821da177e4SLinus Torvalds struct sock *sk = sock->sk; 358383321d6bSTimo Teras struct pfkey_sock *pfk = pfkey_sk(sk); 35841da177e4SLinus Torvalds struct sk_buff *skb; 35851da177e4SLinus Torvalds int copied, err; 35861da177e4SLinus Torvalds 35871da177e4SLinus Torvalds err = -EINVAL; 35881da177e4SLinus Torvalds if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) 35891da177e4SLinus Torvalds goto out; 35901da177e4SLinus Torvalds 35911da177e4SLinus Torvalds msg->msg_namelen = 0; 35921da177e4SLinus Torvalds skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); 35931da177e4SLinus Torvalds if (skb == NULL) 35941da177e4SLinus Torvalds goto out; 35951da177e4SLinus Torvalds 35961da177e4SLinus Torvalds copied = skb->len; 35971da177e4SLinus Torvalds if (copied > len) { 35981da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC; 35991da177e4SLinus Torvalds copied = len; 36001da177e4SLinus Torvalds } 36011da177e4SLinus Torvalds 3602badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb); 36031da177e4SLinus Torvalds err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 36041da177e4SLinus Torvalds if (err) 36051da177e4SLinus Torvalds goto out_free; 36061da177e4SLinus Torvalds 36073b885787SNeil Horman sock_recv_ts_and_drops(msg, sk, skb); 36081da177e4SLinus Torvalds 36091da177e4SLinus Torvalds err = (flags & MSG_TRUNC) ? skb->len : copied; 36101da177e4SLinus Torvalds 361183321d6bSTimo Teras if (pfk->dump.dump != NULL && 361283321d6bSTimo Teras 3 * atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) 361383321d6bSTimo Teras pfkey_do_dump(pfk); 361483321d6bSTimo Teras 36151da177e4SLinus Torvalds out_free: 36161da177e4SLinus Torvalds skb_free_datagram(sk, skb); 36171da177e4SLinus Torvalds out: 36181da177e4SLinus Torvalds return err; 36191da177e4SLinus Torvalds } 36201da177e4SLinus Torvalds 362190ddc4f0SEric Dumazet static const struct proto_ops pfkey_ops = { 36221da177e4SLinus Torvalds .family = PF_KEY, 36231da177e4SLinus Torvalds .owner = THIS_MODULE, 36241da177e4SLinus Torvalds /* Operations that make no sense on pfkey sockets. */ 36251da177e4SLinus Torvalds .bind = sock_no_bind, 36261da177e4SLinus Torvalds .connect = sock_no_connect, 36271da177e4SLinus Torvalds .socketpair = sock_no_socketpair, 36281da177e4SLinus Torvalds .accept = sock_no_accept, 36291da177e4SLinus Torvalds .getname = sock_no_getname, 36301da177e4SLinus Torvalds .ioctl = sock_no_ioctl, 36311da177e4SLinus Torvalds .listen = sock_no_listen, 36321da177e4SLinus Torvalds .shutdown = sock_no_shutdown, 36331da177e4SLinus Torvalds .setsockopt = sock_no_setsockopt, 36341da177e4SLinus Torvalds .getsockopt = sock_no_getsockopt, 36351da177e4SLinus Torvalds .mmap = sock_no_mmap, 36361da177e4SLinus Torvalds .sendpage = sock_no_sendpage, 36371da177e4SLinus Torvalds 36381da177e4SLinus Torvalds /* Now the operations that really occur. */ 36391da177e4SLinus Torvalds .release = pfkey_release, 36401da177e4SLinus Torvalds .poll = datagram_poll, 36411da177e4SLinus Torvalds .sendmsg = pfkey_sendmsg, 36421da177e4SLinus Torvalds .recvmsg = pfkey_recvmsg, 36431da177e4SLinus Torvalds }; 36441da177e4SLinus Torvalds 3645ec1b4cf7SStephen Hemminger static const struct net_proto_family pfkey_family_ops = { 36461da177e4SLinus Torvalds .family = PF_KEY, 36471da177e4SLinus Torvalds .create = pfkey_create, 36481da177e4SLinus Torvalds .owner = THIS_MODULE, 36491da177e4SLinus Torvalds }; 36501da177e4SLinus Torvalds 36511da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 3652bd2f7476SPavel Emelyanov static int pfkey_seq_show(struct seq_file *f, void *v) 36531da177e4SLinus Torvalds { 365427b5b865SLi Zefan struct sock *s = sk_entry(v); 36551da177e4SLinus Torvalds 3656bd2f7476SPavel Emelyanov if (v == SEQ_START_TOKEN) 3657bd2f7476SPavel Emelyanov seq_printf(f ,"sk RefCnt Rmem Wmem User Inode\n"); 3658bd2f7476SPavel Emelyanov else 3659bd2f7476SPavel Emelyanov seq_printf(f ,"%p %-6d %-6u %-6u %-6u %-6lu\n", 36601da177e4SLinus Torvalds s, 36611da177e4SLinus Torvalds atomic_read(&s->sk_refcnt), 366231e6d363SEric Dumazet sk_rmem_alloc_get(s), 366331e6d363SEric Dumazet sk_wmem_alloc_get(s), 36641da177e4SLinus Torvalds sock_i_uid(s), 36651da177e4SLinus Torvalds sock_i_ino(s) 36661da177e4SLinus Torvalds ); 3667bd2f7476SPavel Emelyanov return 0; 36681da177e4SLinus Torvalds } 36691da177e4SLinus Torvalds 3670bd2f7476SPavel Emelyanov static void *pfkey_seq_start(struct seq_file *f, loff_t *ppos) 3671ada440e3Sstephen hemminger __acquires(rcu) 3672bd2f7476SPavel Emelyanov { 36737013ec30SAlexey Dobriyan struct net *net = seq_file_net(f); 36743fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 3675bd2f7476SPavel Emelyanov 36767f6b9dbdSstephen hemminger rcu_read_lock(); 36777f6b9dbdSstephen hemminger return seq_hlist_start_head_rcu(&net_pfkey->table, *ppos); 3678bd2f7476SPavel Emelyanov } 3679bd2f7476SPavel Emelyanov 3680bd2f7476SPavel Emelyanov static void *pfkey_seq_next(struct seq_file *f, void *v, loff_t *ppos) 3681bd2f7476SPavel Emelyanov { 36827013ec30SAlexey Dobriyan struct net *net = seq_file_net(f); 36833fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 36843fa87a32SAlexey Dobriyan 36857f6b9dbdSstephen hemminger return seq_hlist_next_rcu(v, &net_pfkey->table, ppos); 3686bd2f7476SPavel Emelyanov } 3687bd2f7476SPavel Emelyanov 3688bd2f7476SPavel Emelyanov static void pfkey_seq_stop(struct seq_file *f, void *v) 3689ada440e3Sstephen hemminger __releases(rcu) 3690bd2f7476SPavel Emelyanov { 36917f6b9dbdSstephen hemminger rcu_read_unlock(); 36921da177e4SLinus Torvalds } 369361145aa1SPavel Emelyanov 369498147d52SStephen Hemminger static const struct seq_operations pfkey_seq_ops = { 3695bd2f7476SPavel Emelyanov .start = pfkey_seq_start, 3696bd2f7476SPavel Emelyanov .next = pfkey_seq_next, 3697bd2f7476SPavel Emelyanov .stop = pfkey_seq_stop, 3698bd2f7476SPavel Emelyanov .show = pfkey_seq_show, 3699bd2f7476SPavel Emelyanov }; 3700bd2f7476SPavel Emelyanov 3701bd2f7476SPavel Emelyanov static int pfkey_seq_open(struct inode *inode, struct file *file) 3702bd2f7476SPavel Emelyanov { 37037013ec30SAlexey Dobriyan return seq_open_net(inode, file, &pfkey_seq_ops, 37047013ec30SAlexey Dobriyan sizeof(struct seq_net_private)); 3705bd2f7476SPavel Emelyanov } 3706bd2f7476SPavel Emelyanov 37075ca1b998SStephen Hemminger static const struct file_operations pfkey_proc_ops = { 3708bd2f7476SPavel Emelyanov .open = pfkey_seq_open, 3709bd2f7476SPavel Emelyanov .read = seq_read, 3710bd2f7476SPavel Emelyanov .llseek = seq_lseek, 37117013ec30SAlexey Dobriyan .release = seq_release_net, 3712bd2f7476SPavel Emelyanov }; 3713bd2f7476SPavel Emelyanov 37147013ec30SAlexey Dobriyan static int __net_init pfkey_init_proc(struct net *net) 371561145aa1SPavel Emelyanov { 3716bd2f7476SPavel Emelyanov struct proc_dir_entry *e; 3717bd2f7476SPavel Emelyanov 37187013ec30SAlexey Dobriyan e = proc_net_fops_create(net, "pfkey", 0, &pfkey_proc_ops); 3719bd2f7476SPavel Emelyanov if (e == NULL) 372061145aa1SPavel Emelyanov return -ENOMEM; 3721bd2f7476SPavel Emelyanov 372261145aa1SPavel Emelyanov return 0; 372361145aa1SPavel Emelyanov } 372461145aa1SPavel Emelyanov 37252c8c1e72SAlexey Dobriyan static void __net_exit pfkey_exit_proc(struct net *net) 372661145aa1SPavel Emelyanov { 37277013ec30SAlexey Dobriyan proc_net_remove(net, "pfkey"); 372861145aa1SPavel Emelyanov } 372961145aa1SPavel Emelyanov #else 37302c8c1e72SAlexey Dobriyan static inline int pfkey_init_proc(struct net *net) 373161145aa1SPavel Emelyanov { 373261145aa1SPavel Emelyanov return 0; 373361145aa1SPavel Emelyanov } 373461145aa1SPavel Emelyanov 37352c8c1e72SAlexey Dobriyan static inline void pfkey_exit_proc(struct net *net) 373661145aa1SPavel Emelyanov { 373761145aa1SPavel Emelyanov } 37381da177e4SLinus Torvalds #endif 37391da177e4SLinus Torvalds 37401da177e4SLinus Torvalds static struct xfrm_mgr pfkeyv2_mgr = 37411da177e4SLinus Torvalds { 37421da177e4SLinus Torvalds .id = "pfkeyv2", 37431da177e4SLinus Torvalds .notify = pfkey_send_notify, 37441da177e4SLinus Torvalds .acquire = pfkey_send_acquire, 37451da177e4SLinus Torvalds .compile_policy = pfkey_compile_policy, 37461da177e4SLinus Torvalds .new_mapping = pfkey_send_new_mapping, 374726b15dadSJamal Hadi Salim .notify_policy = pfkey_send_policy_notify, 374808de61beSShinta Sugimoto .migrate = pfkey_send_migrate, 37491da177e4SLinus Torvalds }; 37501da177e4SLinus Torvalds 37513fa87a32SAlexey Dobriyan static int __net_init pfkey_net_init(struct net *net) 37523fa87a32SAlexey Dobriyan { 375323c049caSEric W. Biederman struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 37543fa87a32SAlexey Dobriyan int rv; 37553fa87a32SAlexey Dobriyan 37563fa87a32SAlexey Dobriyan INIT_HLIST_HEAD(&net_pfkey->table); 37573fa87a32SAlexey Dobriyan atomic_set(&net_pfkey->socks_nr, 0); 37583fa87a32SAlexey Dobriyan 375923c049caSEric W. Biederman rv = pfkey_init_proc(net); 376023c049caSEric W. Biederman 37613fa87a32SAlexey Dobriyan return rv; 37623fa87a32SAlexey Dobriyan } 37633fa87a32SAlexey Dobriyan 37643fa87a32SAlexey Dobriyan static void __net_exit pfkey_net_exit(struct net *net) 37653fa87a32SAlexey Dobriyan { 37663fa87a32SAlexey Dobriyan struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); 37673fa87a32SAlexey Dobriyan 37687013ec30SAlexey Dobriyan pfkey_exit_proc(net); 37693fa87a32SAlexey Dobriyan BUG_ON(!hlist_empty(&net_pfkey->table)); 37703fa87a32SAlexey Dobriyan } 37713fa87a32SAlexey Dobriyan 37723fa87a32SAlexey Dobriyan static struct pernet_operations pfkey_net_ops = { 37733fa87a32SAlexey Dobriyan .init = pfkey_net_init, 37743fa87a32SAlexey Dobriyan .exit = pfkey_net_exit, 377523c049caSEric W. Biederman .id = &pfkey_net_id, 377623c049caSEric W. Biederman .size = sizeof(struct netns_pfkey), 37773fa87a32SAlexey Dobriyan }; 37783fa87a32SAlexey Dobriyan 37791da177e4SLinus Torvalds static void __exit ipsec_pfkey_exit(void) 37801da177e4SLinus Torvalds { 37811da177e4SLinus Torvalds xfrm_unregister_km(&pfkeyv2_mgr); 37821da177e4SLinus Torvalds sock_unregister(PF_KEY); 3783180211b8SAlexey Dobriyan unregister_pernet_subsys(&pfkey_net_ops); 37841da177e4SLinus Torvalds proto_unregister(&key_proto); 37851da177e4SLinus Torvalds } 37861da177e4SLinus Torvalds 37871da177e4SLinus Torvalds static int __init ipsec_pfkey_init(void) 37881da177e4SLinus Torvalds { 37891da177e4SLinus Torvalds int err = proto_register(&key_proto, 0); 37901da177e4SLinus Torvalds 37911da177e4SLinus Torvalds if (err != 0) 37921da177e4SLinus Torvalds goto out; 37931da177e4SLinus Torvalds 3794180211b8SAlexey Dobriyan err = register_pernet_subsys(&pfkey_net_ops); 37951da177e4SLinus Torvalds if (err != 0) 37961da177e4SLinus Torvalds goto out_unregister_key_proto; 3797180211b8SAlexey Dobriyan err = sock_register(&pfkey_family_ops); 3798180211b8SAlexey Dobriyan if (err != 0) 3799180211b8SAlexey Dobriyan goto out_unregister_pernet; 38001da177e4SLinus Torvalds err = xfrm_register_km(&pfkeyv2_mgr); 38011da177e4SLinus Torvalds if (err != 0) 38027013ec30SAlexey Dobriyan goto out_sock_unregister; 38031da177e4SLinus Torvalds out: 38041da177e4SLinus Torvalds return err; 3805180211b8SAlexey Dobriyan 38061da177e4SLinus Torvalds out_sock_unregister: 38071da177e4SLinus Torvalds sock_unregister(PF_KEY); 3808180211b8SAlexey Dobriyan out_unregister_pernet: 3809180211b8SAlexey Dobriyan unregister_pernet_subsys(&pfkey_net_ops); 38101da177e4SLinus Torvalds out_unregister_key_proto: 38111da177e4SLinus Torvalds proto_unregister(&key_proto); 38121da177e4SLinus Torvalds goto out; 38131da177e4SLinus Torvalds } 38141da177e4SLinus Torvalds 38151da177e4SLinus Torvalds module_init(ipsec_pfkey_init); 38161da177e4SLinus Torvalds module_exit(ipsec_pfkey_exit); 38171da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 38181da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_KEY); 3819