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> 29457c4cbcSEric W. Biederman #include <net/net_namespace.h> 301da177e4SLinus Torvalds #include <net/xfrm.h> 311da177e4SLinus Torvalds 321da177e4SLinus Torvalds #include <net/sock.h> 331da177e4SLinus Torvalds 341da177e4SLinus Torvalds #define _X2KEY(x) ((x) == XFRM_INF ? 0 : (x)) 351da177e4SLinus Torvalds #define _KEY2X(x) ((x) == 0 ? XFRM_INF : (x)) 361da177e4SLinus Torvalds 371da177e4SLinus Torvalds 381da177e4SLinus Torvalds /* List of all pfkey sockets. */ 391da177e4SLinus Torvalds static HLIST_HEAD(pfkey_table); 401da177e4SLinus Torvalds static DECLARE_WAIT_QUEUE_HEAD(pfkey_table_wait); 411da177e4SLinus Torvalds static DEFINE_RWLOCK(pfkey_table_lock); 421da177e4SLinus Torvalds static atomic_t pfkey_table_users = ATOMIC_INIT(0); 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds static atomic_t pfkey_socks_nr = ATOMIC_INIT(0); 451da177e4SLinus Torvalds 461da177e4SLinus Torvalds struct pfkey_sock { 471da177e4SLinus Torvalds /* struct sock must be the first member of struct pfkey_sock */ 481da177e4SLinus Torvalds struct sock sk; 491da177e4SLinus Torvalds int registered; 501da177e4SLinus Torvalds int promisc; 511da177e4SLinus Torvalds }; 521da177e4SLinus Torvalds 531da177e4SLinus Torvalds static inline struct pfkey_sock *pfkey_sk(struct sock *sk) 541da177e4SLinus Torvalds { 551da177e4SLinus Torvalds return (struct pfkey_sock *)sk; 561da177e4SLinus Torvalds } 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds static void pfkey_sock_destruct(struct sock *sk) 591da177e4SLinus Torvalds { 601da177e4SLinus Torvalds skb_queue_purge(&sk->sk_receive_queue); 611da177e4SLinus Torvalds 621da177e4SLinus Torvalds if (!sock_flag(sk, SOCK_DEAD)) { 631da177e4SLinus Torvalds printk("Attempt to release alive pfkey socket: %p\n", sk); 641da177e4SLinus Torvalds return; 651da177e4SLinus Torvalds } 661da177e4SLinus Torvalds 671da177e4SLinus Torvalds BUG_TRAP(!atomic_read(&sk->sk_rmem_alloc)); 681da177e4SLinus Torvalds BUG_TRAP(!atomic_read(&sk->sk_wmem_alloc)); 691da177e4SLinus Torvalds 701da177e4SLinus Torvalds atomic_dec(&pfkey_socks_nr); 711da177e4SLinus Torvalds } 721da177e4SLinus Torvalds 731da177e4SLinus Torvalds static void pfkey_table_grab(void) 741da177e4SLinus Torvalds { 751da177e4SLinus Torvalds write_lock_bh(&pfkey_table_lock); 761da177e4SLinus Torvalds 771da177e4SLinus Torvalds if (atomic_read(&pfkey_table_users)) { 781da177e4SLinus Torvalds DECLARE_WAITQUEUE(wait, current); 791da177e4SLinus Torvalds 801da177e4SLinus Torvalds add_wait_queue_exclusive(&pfkey_table_wait, &wait); 811da177e4SLinus Torvalds for(;;) { 821da177e4SLinus Torvalds set_current_state(TASK_UNINTERRUPTIBLE); 831da177e4SLinus Torvalds if (atomic_read(&pfkey_table_users) == 0) 841da177e4SLinus Torvalds break; 851da177e4SLinus Torvalds write_unlock_bh(&pfkey_table_lock); 861da177e4SLinus Torvalds schedule(); 871da177e4SLinus Torvalds write_lock_bh(&pfkey_table_lock); 881da177e4SLinus Torvalds } 891da177e4SLinus Torvalds 901da177e4SLinus Torvalds __set_current_state(TASK_RUNNING); 911da177e4SLinus Torvalds remove_wait_queue(&pfkey_table_wait, &wait); 921da177e4SLinus Torvalds } 931da177e4SLinus Torvalds } 941da177e4SLinus Torvalds 951da177e4SLinus Torvalds static __inline__ void pfkey_table_ungrab(void) 961da177e4SLinus Torvalds { 971da177e4SLinus Torvalds write_unlock_bh(&pfkey_table_lock); 981da177e4SLinus Torvalds wake_up(&pfkey_table_wait); 991da177e4SLinus Torvalds } 1001da177e4SLinus Torvalds 1011da177e4SLinus Torvalds static __inline__ void pfkey_lock_table(void) 1021da177e4SLinus Torvalds { 1031da177e4SLinus Torvalds /* read_lock() synchronizes us to pfkey_table_grab */ 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds read_lock(&pfkey_table_lock); 1061da177e4SLinus Torvalds atomic_inc(&pfkey_table_users); 1071da177e4SLinus Torvalds read_unlock(&pfkey_table_lock); 1081da177e4SLinus Torvalds } 1091da177e4SLinus Torvalds 1101da177e4SLinus Torvalds static __inline__ void pfkey_unlock_table(void) 1111da177e4SLinus Torvalds { 1121da177e4SLinus Torvalds if (atomic_dec_and_test(&pfkey_table_users)) 1131da177e4SLinus Torvalds wake_up(&pfkey_table_wait); 1141da177e4SLinus Torvalds } 1151da177e4SLinus Torvalds 1161da177e4SLinus Torvalds 11790ddc4f0SEric Dumazet static const struct proto_ops pfkey_ops; 1181da177e4SLinus Torvalds 1191da177e4SLinus Torvalds static void pfkey_insert(struct sock *sk) 1201da177e4SLinus Torvalds { 1211da177e4SLinus Torvalds pfkey_table_grab(); 1221da177e4SLinus Torvalds sk_add_node(sk, &pfkey_table); 1231da177e4SLinus Torvalds pfkey_table_ungrab(); 1241da177e4SLinus Torvalds } 1251da177e4SLinus Torvalds 1261da177e4SLinus Torvalds static void pfkey_remove(struct sock *sk) 1271da177e4SLinus Torvalds { 1281da177e4SLinus Torvalds pfkey_table_grab(); 1291da177e4SLinus Torvalds sk_del_node_init(sk); 1301da177e4SLinus Torvalds pfkey_table_ungrab(); 1311da177e4SLinus Torvalds } 1321da177e4SLinus Torvalds 1331da177e4SLinus Torvalds static struct proto key_proto = { 1341da177e4SLinus Torvalds .name = "KEY", 1351da177e4SLinus Torvalds .owner = THIS_MODULE, 1361da177e4SLinus Torvalds .obj_size = sizeof(struct pfkey_sock), 1371da177e4SLinus Torvalds }; 1381da177e4SLinus Torvalds 1391b8d7ae4SEric W. Biederman static int pfkey_create(struct net *net, struct socket *sock, int protocol) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds struct sock *sk; 1421da177e4SLinus Torvalds int err; 1431da177e4SLinus Torvalds 1441b8d7ae4SEric W. Biederman if (net != &init_net) 1451b8d7ae4SEric W. Biederman return -EAFNOSUPPORT; 1461b8d7ae4SEric W. Biederman 1471da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 1481da177e4SLinus Torvalds return -EPERM; 1491da177e4SLinus Torvalds if (sock->type != SOCK_RAW) 1501da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 1511da177e4SLinus Torvalds if (protocol != PF_KEY_V2) 1521da177e4SLinus Torvalds return -EPROTONOSUPPORT; 1531da177e4SLinus Torvalds 1541da177e4SLinus Torvalds err = -ENOMEM; 1556257ff21SPavel Emelyanov sk = sk_alloc(net, PF_KEY, GFP_KERNEL, &key_proto); 1561da177e4SLinus Torvalds if (sk == NULL) 1571da177e4SLinus Torvalds goto out; 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds sock->ops = &pfkey_ops; 1601da177e4SLinus Torvalds sock_init_data(sock, sk); 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds sk->sk_family = PF_KEY; 1631da177e4SLinus Torvalds sk->sk_destruct = pfkey_sock_destruct; 1641da177e4SLinus Torvalds 1651da177e4SLinus Torvalds atomic_inc(&pfkey_socks_nr); 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds pfkey_insert(sk); 1681da177e4SLinus Torvalds 1691da177e4SLinus Torvalds return 0; 1701da177e4SLinus Torvalds out: 1711da177e4SLinus Torvalds return err; 1721da177e4SLinus Torvalds } 1731da177e4SLinus Torvalds 1741da177e4SLinus Torvalds static int pfkey_release(struct socket *sock) 1751da177e4SLinus Torvalds { 1761da177e4SLinus Torvalds struct sock *sk = sock->sk; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds if (!sk) 1791da177e4SLinus Torvalds return 0; 1801da177e4SLinus Torvalds 1811da177e4SLinus Torvalds pfkey_remove(sk); 1821da177e4SLinus Torvalds 1831da177e4SLinus Torvalds sock_orphan(sk); 1841da177e4SLinus Torvalds sock->sk = NULL; 1851da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue); 1861da177e4SLinus Torvalds sock_put(sk); 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds return 0; 1891da177e4SLinus Torvalds } 1901da177e4SLinus Torvalds 1911da177e4SLinus Torvalds static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, 192dd0fc66fSAl Viro gfp_t allocation, struct sock *sk) 1931da177e4SLinus Torvalds { 1941da177e4SLinus Torvalds int err = -ENOBUFS; 1951da177e4SLinus Torvalds 1961da177e4SLinus Torvalds sock_hold(sk); 1971da177e4SLinus Torvalds if (*skb2 == NULL) { 1981da177e4SLinus Torvalds if (atomic_read(&skb->users) != 1) { 1991da177e4SLinus Torvalds *skb2 = skb_clone(skb, allocation); 2001da177e4SLinus Torvalds } else { 2011da177e4SLinus Torvalds *skb2 = skb; 2021da177e4SLinus Torvalds atomic_inc(&skb->users); 2031da177e4SLinus Torvalds } 2041da177e4SLinus Torvalds } 2051da177e4SLinus Torvalds if (*skb2 != NULL) { 2061da177e4SLinus Torvalds if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { 2071da177e4SLinus Torvalds skb_orphan(*skb2); 2081da177e4SLinus Torvalds skb_set_owner_r(*skb2, sk); 2091da177e4SLinus Torvalds skb_queue_tail(&sk->sk_receive_queue, *skb2); 2101da177e4SLinus Torvalds sk->sk_data_ready(sk, (*skb2)->len); 2111da177e4SLinus Torvalds *skb2 = NULL; 2121da177e4SLinus Torvalds err = 0; 2131da177e4SLinus Torvalds } 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds sock_put(sk); 2161da177e4SLinus Torvalds return err; 2171da177e4SLinus Torvalds } 2181da177e4SLinus Torvalds 2191da177e4SLinus Torvalds /* Send SKB to all pfkey sockets matching selected criteria. */ 2201da177e4SLinus Torvalds #define BROADCAST_ALL 0 2211da177e4SLinus Torvalds #define BROADCAST_ONE 1 2221da177e4SLinus Torvalds #define BROADCAST_REGISTERED 2 2231da177e4SLinus Torvalds #define BROADCAST_PROMISC_ONLY 4 224dd0fc66fSAl Viro static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, 2251da177e4SLinus Torvalds int broadcast_flags, struct sock *one_sk) 2261da177e4SLinus Torvalds { 2271da177e4SLinus Torvalds struct sock *sk; 2281da177e4SLinus Torvalds struct hlist_node *node; 2291da177e4SLinus Torvalds struct sk_buff *skb2 = NULL; 2301da177e4SLinus Torvalds int err = -ESRCH; 2311da177e4SLinus Torvalds 2321da177e4SLinus Torvalds /* XXX Do we need something like netlink_overrun? I think 2331da177e4SLinus Torvalds * XXX PF_KEY socket apps will not mind current behavior. 2341da177e4SLinus Torvalds */ 2351da177e4SLinus Torvalds if (!skb) 2361da177e4SLinus Torvalds return -ENOMEM; 2371da177e4SLinus Torvalds 2381da177e4SLinus Torvalds pfkey_lock_table(); 2391da177e4SLinus Torvalds sk_for_each(sk, node, &pfkey_table) { 2401da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 2411da177e4SLinus Torvalds int err2; 2421da177e4SLinus Torvalds 2431da177e4SLinus Torvalds /* Yes, it means that if you are meant to receive this 2441da177e4SLinus Torvalds * pfkey message you receive it twice as promiscuous 2451da177e4SLinus Torvalds * socket. 2461da177e4SLinus Torvalds */ 2471da177e4SLinus Torvalds if (pfk->promisc) 2481da177e4SLinus Torvalds pfkey_broadcast_one(skb, &skb2, allocation, sk); 2491da177e4SLinus Torvalds 2501da177e4SLinus Torvalds /* the exact target will be processed later */ 2511da177e4SLinus Torvalds if (sk == one_sk) 2521da177e4SLinus Torvalds continue; 2531da177e4SLinus Torvalds if (broadcast_flags != BROADCAST_ALL) { 2541da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_PROMISC_ONLY) 2551da177e4SLinus Torvalds continue; 2561da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && 2571da177e4SLinus Torvalds !pfk->registered) 2581da177e4SLinus Torvalds continue; 2591da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_ONE) 2601da177e4SLinus Torvalds continue; 2611da177e4SLinus Torvalds } 2621da177e4SLinus Torvalds 2631da177e4SLinus Torvalds err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk); 2641da177e4SLinus Torvalds 2651da177e4SLinus Torvalds /* Error is cleare after succecful sending to at least one 2661da177e4SLinus Torvalds * registered KM */ 2671da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && err) 2681da177e4SLinus Torvalds err = err2; 2691da177e4SLinus Torvalds } 2701da177e4SLinus Torvalds pfkey_unlock_table(); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds if (one_sk != NULL) 2731da177e4SLinus Torvalds err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); 2741da177e4SLinus Torvalds 2751da177e4SLinus Torvalds if (skb2) 2761da177e4SLinus Torvalds kfree_skb(skb2); 2771da177e4SLinus Torvalds kfree_skb(skb); 2781da177e4SLinus Torvalds return err; 2791da177e4SLinus Torvalds } 2801da177e4SLinus Torvalds 2811da177e4SLinus Torvalds static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig) 2821da177e4SLinus Torvalds { 2831da177e4SLinus Torvalds *new = *orig; 2841da177e4SLinus Torvalds } 2851da177e4SLinus Torvalds 2861da177e4SLinus Torvalds static int pfkey_error(struct sadb_msg *orig, int err, struct sock *sk) 2871da177e4SLinus Torvalds { 2881da177e4SLinus Torvalds struct sk_buff *skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); 2891da177e4SLinus Torvalds struct sadb_msg *hdr; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds if (!skb) 2921da177e4SLinus Torvalds return -ENOBUFS; 2931da177e4SLinus Torvalds 2941da177e4SLinus Torvalds /* Woe be to the platform trying to support PFKEY yet 2951da177e4SLinus Torvalds * having normal errnos outside the 1-255 range, inclusive. 2961da177e4SLinus Torvalds */ 2971da177e4SLinus Torvalds err = -err; 2981da177e4SLinus Torvalds if (err == ERESTARTSYS || 2991da177e4SLinus Torvalds err == ERESTARTNOHAND || 3001da177e4SLinus Torvalds err == ERESTARTNOINTR) 3011da177e4SLinus Torvalds err = EINTR; 3021da177e4SLinus Torvalds if (err >= 512) 3031da177e4SLinus Torvalds err = EINVAL; 30409a62660SKris Katterjohn BUG_ON(err <= 0 || err >= 256); 3051da177e4SLinus Torvalds 3061da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 3071da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 3081da177e4SLinus Torvalds hdr->sadb_msg_errno = (uint8_t) err; 3091da177e4SLinus Torvalds hdr->sadb_msg_len = (sizeof(struct sadb_msg) / 3101da177e4SLinus Torvalds sizeof(uint64_t)); 3111da177e4SLinus Torvalds 3121da177e4SLinus Torvalds pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk); 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds return 0; 3151da177e4SLinus Torvalds } 3161da177e4SLinus Torvalds 3171da177e4SLinus Torvalds static u8 sadb_ext_min_len[] = { 3181da177e4SLinus Torvalds [SADB_EXT_RESERVED] = (u8) 0, 3191da177e4SLinus Torvalds [SADB_EXT_SA] = (u8) sizeof(struct sadb_sa), 3201da177e4SLinus Torvalds [SADB_EXT_LIFETIME_CURRENT] = (u8) sizeof(struct sadb_lifetime), 3211da177e4SLinus Torvalds [SADB_EXT_LIFETIME_HARD] = (u8) sizeof(struct sadb_lifetime), 3221da177e4SLinus Torvalds [SADB_EXT_LIFETIME_SOFT] = (u8) sizeof(struct sadb_lifetime), 3231da177e4SLinus Torvalds [SADB_EXT_ADDRESS_SRC] = (u8) sizeof(struct sadb_address), 3241da177e4SLinus Torvalds [SADB_EXT_ADDRESS_DST] = (u8) sizeof(struct sadb_address), 3251da177e4SLinus Torvalds [SADB_EXT_ADDRESS_PROXY] = (u8) sizeof(struct sadb_address), 3261da177e4SLinus Torvalds [SADB_EXT_KEY_AUTH] = (u8) sizeof(struct sadb_key), 3271da177e4SLinus Torvalds [SADB_EXT_KEY_ENCRYPT] = (u8) sizeof(struct sadb_key), 3281da177e4SLinus Torvalds [SADB_EXT_IDENTITY_SRC] = (u8) sizeof(struct sadb_ident), 3291da177e4SLinus Torvalds [SADB_EXT_IDENTITY_DST] = (u8) sizeof(struct sadb_ident), 3301da177e4SLinus Torvalds [SADB_EXT_SENSITIVITY] = (u8) sizeof(struct sadb_sens), 3311da177e4SLinus Torvalds [SADB_EXT_PROPOSAL] = (u8) sizeof(struct sadb_prop), 3321da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_AUTH] = (u8) sizeof(struct sadb_supported), 3331da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_ENCRYPT] = (u8) sizeof(struct sadb_supported), 3341da177e4SLinus Torvalds [SADB_EXT_SPIRANGE] = (u8) sizeof(struct sadb_spirange), 3351da177e4SLinus Torvalds [SADB_X_EXT_KMPRIVATE] = (u8) sizeof(struct sadb_x_kmprivate), 3361da177e4SLinus Torvalds [SADB_X_EXT_POLICY] = (u8) sizeof(struct sadb_x_policy), 3371da177e4SLinus Torvalds [SADB_X_EXT_SA2] = (u8) sizeof(struct sadb_x_sa2), 3381da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_TYPE] = (u8) sizeof(struct sadb_x_nat_t_type), 3391da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_SPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3401da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3411da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), 342df71837dSTrent Jaeger [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), 3431da177e4SLinus Torvalds }; 3441da177e4SLinus Torvalds 3451da177e4SLinus Torvalds /* Verify sadb_address_{len,prefixlen} against sa_family. */ 3461da177e4SLinus Torvalds static int verify_address_len(void *p) 3471da177e4SLinus Torvalds { 3481da177e4SLinus Torvalds struct sadb_address *sp = p; 3491da177e4SLinus Torvalds struct sockaddr *addr = (struct sockaddr *)(sp + 1); 3501da177e4SLinus Torvalds struct sockaddr_in *sin; 3511da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3521da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 3531da177e4SLinus Torvalds #endif 3541da177e4SLinus Torvalds int len; 3551da177e4SLinus Torvalds 3561da177e4SLinus Torvalds switch (addr->sa_family) { 3571da177e4SLinus Torvalds case AF_INET: 358356f89e1SIlpo Järvinen len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin), sizeof(uint64_t)); 3591da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3601da177e4SLinus Torvalds sp->sadb_address_prefixlen > 32) 3611da177e4SLinus Torvalds return -EINVAL; 3621da177e4SLinus Torvalds break; 3631da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3641da177e4SLinus Torvalds case AF_INET6: 365356f89e1SIlpo Järvinen len = DIV_ROUND_UP(sizeof(*sp) + sizeof(*sin6), sizeof(uint64_t)); 3661da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3671da177e4SLinus Torvalds sp->sadb_address_prefixlen > 128) 3681da177e4SLinus Torvalds return -EINVAL; 3691da177e4SLinus Torvalds break; 3701da177e4SLinus Torvalds #endif 3711da177e4SLinus Torvalds default: 3721da177e4SLinus Torvalds /* It is user using kernel to keep track of security 3731da177e4SLinus Torvalds * associations for another protocol, such as 3741da177e4SLinus Torvalds * OSPF/RSVP/RIPV2/MIP. It is user's job to verify 3751da177e4SLinus Torvalds * lengths. 3761da177e4SLinus Torvalds * 3771da177e4SLinus Torvalds * XXX Actually, association/policy database is not yet 3781da177e4SLinus Torvalds * XXX able to cope with arbitrary sockaddr families. 3791da177e4SLinus Torvalds * XXX When it can, remove this -EINVAL. -DaveM 3801da177e4SLinus Torvalds */ 3811da177e4SLinus Torvalds return -EINVAL; 3821da177e4SLinus Torvalds break; 3833ff50b79SStephen Hemminger } 3841da177e4SLinus Torvalds 3851da177e4SLinus Torvalds return 0; 3861da177e4SLinus Torvalds } 3871da177e4SLinus Torvalds 388df71837dSTrent Jaeger static inline int pfkey_sec_ctx_len(struct sadb_x_sec_ctx *sec_ctx) 389df71837dSTrent Jaeger { 390356f89e1SIlpo Järvinen return DIV_ROUND_UP(sizeof(struct sadb_x_sec_ctx) + 391356f89e1SIlpo Järvinen sec_ctx->sadb_x_ctx_len, 392356f89e1SIlpo Järvinen sizeof(uint64_t)); 393df71837dSTrent Jaeger } 394df71837dSTrent Jaeger 395df71837dSTrent Jaeger static inline int verify_sec_ctx_len(void *p) 396df71837dSTrent Jaeger { 397df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx = (struct sadb_x_sec_ctx *)p; 398298bb621SStephen Rothwell int len = sec_ctx->sadb_x_ctx_len; 399df71837dSTrent Jaeger 400298bb621SStephen Rothwell if (len > PAGE_SIZE) 401df71837dSTrent Jaeger return -EINVAL; 402df71837dSTrent Jaeger 403df71837dSTrent Jaeger len = pfkey_sec_ctx_len(sec_ctx); 404df71837dSTrent Jaeger 405df71837dSTrent Jaeger if (sec_ctx->sadb_x_sec_len != len) 406df71837dSTrent Jaeger return -EINVAL; 407df71837dSTrent Jaeger 408df71837dSTrent Jaeger return 0; 409df71837dSTrent Jaeger } 410df71837dSTrent Jaeger 411df71837dSTrent Jaeger static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(struct sadb_x_sec_ctx *sec_ctx) 412df71837dSTrent Jaeger { 413df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = NULL; 414df71837dSTrent Jaeger int ctx_size = sec_ctx->sadb_x_ctx_len; 415df71837dSTrent Jaeger 416df71837dSTrent Jaeger uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL); 417df71837dSTrent Jaeger 418df71837dSTrent Jaeger if (!uctx) 419df71837dSTrent Jaeger return NULL; 420df71837dSTrent Jaeger 421df71837dSTrent Jaeger uctx->len = pfkey_sec_ctx_len(sec_ctx); 422df71837dSTrent Jaeger uctx->exttype = sec_ctx->sadb_x_sec_exttype; 423df71837dSTrent Jaeger uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi; 424df71837dSTrent Jaeger uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg; 425df71837dSTrent Jaeger uctx->ctx_len = sec_ctx->sadb_x_ctx_len; 426df71837dSTrent Jaeger memcpy(uctx + 1, sec_ctx + 1, 427df71837dSTrent Jaeger uctx->ctx_len); 428df71837dSTrent Jaeger 429df71837dSTrent Jaeger return uctx; 430df71837dSTrent Jaeger } 431df71837dSTrent Jaeger 4321da177e4SLinus Torvalds static int present_and_same_family(struct sadb_address *src, 4331da177e4SLinus Torvalds struct sadb_address *dst) 4341da177e4SLinus Torvalds { 4351da177e4SLinus Torvalds struct sockaddr *s_addr, *d_addr; 4361da177e4SLinus Torvalds 4371da177e4SLinus Torvalds if (!src || !dst) 4381da177e4SLinus Torvalds return 0; 4391da177e4SLinus Torvalds 4401da177e4SLinus Torvalds s_addr = (struct sockaddr *)(src + 1); 4411da177e4SLinus Torvalds d_addr = (struct sockaddr *)(dst + 1); 4421da177e4SLinus Torvalds if (s_addr->sa_family != d_addr->sa_family) 4431da177e4SLinus Torvalds return 0; 4441da177e4SLinus Torvalds if (s_addr->sa_family != AF_INET 4451da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4461da177e4SLinus Torvalds && s_addr->sa_family != AF_INET6 4471da177e4SLinus Torvalds #endif 4481da177e4SLinus Torvalds ) 4491da177e4SLinus Torvalds return 0; 4501da177e4SLinus Torvalds 4511da177e4SLinus Torvalds return 1; 4521da177e4SLinus Torvalds } 4531da177e4SLinus Torvalds 4541da177e4SLinus Torvalds static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 4551da177e4SLinus Torvalds { 4561da177e4SLinus Torvalds char *p = (char *) hdr; 4571da177e4SLinus Torvalds int len = skb->len; 4581da177e4SLinus Torvalds 4591da177e4SLinus Torvalds len -= sizeof(*hdr); 4601da177e4SLinus Torvalds p += sizeof(*hdr); 4611da177e4SLinus Torvalds while (len > 0) { 4621da177e4SLinus Torvalds struct sadb_ext *ehdr = (struct sadb_ext *) p; 4631da177e4SLinus Torvalds uint16_t ext_type; 4641da177e4SLinus Torvalds int ext_len; 4651da177e4SLinus Torvalds 4661da177e4SLinus Torvalds ext_len = ehdr->sadb_ext_len; 4671da177e4SLinus Torvalds ext_len *= sizeof(uint64_t); 4681da177e4SLinus Torvalds ext_type = ehdr->sadb_ext_type; 4691da177e4SLinus Torvalds if (ext_len < sizeof(uint64_t) || 4701da177e4SLinus Torvalds ext_len > len || 4711da177e4SLinus Torvalds ext_type == SADB_EXT_RESERVED) 4721da177e4SLinus Torvalds return -EINVAL; 4731da177e4SLinus Torvalds 4741da177e4SLinus Torvalds if (ext_type <= SADB_EXT_MAX) { 4751da177e4SLinus Torvalds int min = (int) sadb_ext_min_len[ext_type]; 4761da177e4SLinus Torvalds if (ext_len < min) 4771da177e4SLinus Torvalds return -EINVAL; 4781da177e4SLinus Torvalds if (ext_hdrs[ext_type-1] != NULL) 4791da177e4SLinus Torvalds return -EINVAL; 4801da177e4SLinus Torvalds if (ext_type == SADB_EXT_ADDRESS_SRC || 4811da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_DST || 4821da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_PROXY || 4831da177e4SLinus Torvalds ext_type == SADB_X_EXT_NAT_T_OA) { 4841da177e4SLinus Torvalds if (verify_address_len(p)) 4851da177e4SLinus Torvalds return -EINVAL; 4861da177e4SLinus Torvalds } 487df71837dSTrent Jaeger if (ext_type == SADB_X_EXT_SEC_CTX) { 488df71837dSTrent Jaeger if (verify_sec_ctx_len(p)) 489df71837dSTrent Jaeger return -EINVAL; 490df71837dSTrent Jaeger } 4911da177e4SLinus Torvalds ext_hdrs[ext_type-1] = p; 4921da177e4SLinus Torvalds } 4931da177e4SLinus Torvalds p += ext_len; 4941da177e4SLinus Torvalds len -= ext_len; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 4971da177e4SLinus Torvalds return 0; 4981da177e4SLinus Torvalds } 4991da177e4SLinus Torvalds 5001da177e4SLinus Torvalds static uint16_t 5011da177e4SLinus Torvalds pfkey_satype2proto(uint8_t satype) 5021da177e4SLinus Torvalds { 5031da177e4SLinus Torvalds switch (satype) { 5041da177e4SLinus Torvalds case SADB_SATYPE_UNSPEC: 5051da177e4SLinus Torvalds return IPSEC_PROTO_ANY; 5061da177e4SLinus Torvalds case SADB_SATYPE_AH: 5071da177e4SLinus Torvalds return IPPROTO_AH; 5081da177e4SLinus Torvalds case SADB_SATYPE_ESP: 5091da177e4SLinus Torvalds return IPPROTO_ESP; 5101da177e4SLinus Torvalds case SADB_X_SATYPE_IPCOMP: 5111da177e4SLinus Torvalds return IPPROTO_COMP; 5121da177e4SLinus Torvalds break; 5131da177e4SLinus Torvalds default: 5141da177e4SLinus Torvalds return 0; 5151da177e4SLinus Torvalds } 5161da177e4SLinus Torvalds /* NOTREACHED */ 5171da177e4SLinus Torvalds } 5181da177e4SLinus Torvalds 5191da177e4SLinus Torvalds static uint8_t 5201da177e4SLinus Torvalds pfkey_proto2satype(uint16_t proto) 5211da177e4SLinus Torvalds { 5221da177e4SLinus Torvalds switch (proto) { 5231da177e4SLinus Torvalds case IPPROTO_AH: 5241da177e4SLinus Torvalds return SADB_SATYPE_AH; 5251da177e4SLinus Torvalds case IPPROTO_ESP: 5261da177e4SLinus Torvalds return SADB_SATYPE_ESP; 5271da177e4SLinus Torvalds case IPPROTO_COMP: 5281da177e4SLinus Torvalds return SADB_X_SATYPE_IPCOMP; 5291da177e4SLinus Torvalds break; 5301da177e4SLinus Torvalds default: 5311da177e4SLinus Torvalds return 0; 5321da177e4SLinus Torvalds } 5331da177e4SLinus Torvalds /* NOTREACHED */ 5341da177e4SLinus Torvalds } 5351da177e4SLinus Torvalds 5361da177e4SLinus Torvalds /* BTW, this scheme means that there is no way with PFKEY2 sockets to 5371da177e4SLinus Torvalds * say specifically 'just raw sockets' as we encode them as 255. 5381da177e4SLinus Torvalds */ 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds static uint8_t pfkey_proto_to_xfrm(uint8_t proto) 5411da177e4SLinus Torvalds { 5421da177e4SLinus Torvalds return (proto == IPSEC_PROTO_ANY ? 0 : proto); 5431da177e4SLinus Torvalds } 5441da177e4SLinus Torvalds 5451da177e4SLinus Torvalds static uint8_t pfkey_proto_from_xfrm(uint8_t proto) 5461da177e4SLinus Torvalds { 5471da177e4SLinus Torvalds return (proto ? proto : IPSEC_PROTO_ANY); 5481da177e4SLinus Torvalds } 5491da177e4SLinus Torvalds 5501da177e4SLinus Torvalds static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, 5511da177e4SLinus Torvalds xfrm_address_t *xaddr) 5521da177e4SLinus Torvalds { 5531da177e4SLinus Torvalds switch (((struct sockaddr*)(addr + 1))->sa_family) { 5541da177e4SLinus Torvalds case AF_INET: 5551da177e4SLinus Torvalds xaddr->a4 = 5561da177e4SLinus Torvalds ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr; 5571da177e4SLinus Torvalds return AF_INET; 5581da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5591da177e4SLinus Torvalds case AF_INET6: 5601da177e4SLinus Torvalds memcpy(xaddr->a6, 5611da177e4SLinus Torvalds &((struct sockaddr_in6 *)(addr + 1))->sin6_addr, 5621da177e4SLinus Torvalds sizeof(struct in6_addr)); 5631da177e4SLinus Torvalds return AF_INET6; 5641da177e4SLinus Torvalds #endif 5651da177e4SLinus Torvalds default: 5661da177e4SLinus Torvalds return 0; 5671da177e4SLinus Torvalds } 5681da177e4SLinus Torvalds /* NOTREACHED */ 5691da177e4SLinus Torvalds } 5701da177e4SLinus Torvalds 5711da177e4SLinus Torvalds static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs) 5721da177e4SLinus Torvalds { 5731da177e4SLinus Torvalds struct sadb_sa *sa; 5741da177e4SLinus Torvalds struct sadb_address *addr; 5751da177e4SLinus Torvalds uint16_t proto; 5761da177e4SLinus Torvalds unsigned short family; 5771da177e4SLinus Torvalds xfrm_address_t *xaddr; 5781da177e4SLinus Torvalds 5791da177e4SLinus Torvalds sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 5801da177e4SLinus Torvalds if (sa == NULL) 5811da177e4SLinus Torvalds return NULL; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 5841da177e4SLinus Torvalds if (proto == 0) 5851da177e4SLinus Torvalds return NULL; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds /* sadb_address_len should be checked by caller */ 5881da177e4SLinus Torvalds addr = (struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 5891da177e4SLinus Torvalds if (addr == NULL) 5901da177e4SLinus Torvalds return NULL; 5911da177e4SLinus Torvalds 5921da177e4SLinus Torvalds family = ((struct sockaddr *)(addr + 1))->sa_family; 5931da177e4SLinus Torvalds switch (family) { 5941da177e4SLinus Torvalds case AF_INET: 5951da177e4SLinus Torvalds xaddr = (xfrm_address_t *)&((struct sockaddr_in *)(addr + 1))->sin_addr; 5961da177e4SLinus Torvalds break; 5971da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5981da177e4SLinus Torvalds case AF_INET6: 5991da177e4SLinus Torvalds xaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(addr + 1))->sin6_addr; 6001da177e4SLinus Torvalds break; 6011da177e4SLinus Torvalds #endif 6021da177e4SLinus Torvalds default: 6031da177e4SLinus Torvalds xaddr = NULL; 6041da177e4SLinus Torvalds } 6051da177e4SLinus Torvalds 6061da177e4SLinus Torvalds if (!xaddr) 6071da177e4SLinus Torvalds return NULL; 6081da177e4SLinus Torvalds 6091da177e4SLinus Torvalds return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family); 6101da177e4SLinus Torvalds } 6111da177e4SLinus Torvalds 6121da177e4SLinus Torvalds #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) 6131da177e4SLinus Torvalds static int 6141da177e4SLinus Torvalds pfkey_sockaddr_size(sa_family_t family) 6151da177e4SLinus Torvalds { 6161da177e4SLinus Torvalds switch (family) { 6171da177e4SLinus Torvalds case AF_INET: 6181da177e4SLinus Torvalds return PFKEY_ALIGN8(sizeof(struct sockaddr_in)); 6191da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6201da177e4SLinus Torvalds case AF_INET6: 6211da177e4SLinus Torvalds return PFKEY_ALIGN8(sizeof(struct sockaddr_in6)); 6221da177e4SLinus Torvalds #endif 6231da177e4SLinus Torvalds default: 6241da177e4SLinus Torvalds return 0; 6251da177e4SLinus Torvalds } 6261da177e4SLinus Torvalds /* NOTREACHED */ 6271da177e4SLinus Torvalds } 6281da177e4SLinus Torvalds 62955569ce2SKazunori MIYAZAWA static inline int pfkey_mode_from_xfrm(int mode) 63055569ce2SKazunori MIYAZAWA { 63155569ce2SKazunori MIYAZAWA switch(mode) { 63255569ce2SKazunori MIYAZAWA case XFRM_MODE_TRANSPORT: 63355569ce2SKazunori MIYAZAWA return IPSEC_MODE_TRANSPORT; 63455569ce2SKazunori MIYAZAWA case XFRM_MODE_TUNNEL: 63555569ce2SKazunori MIYAZAWA return IPSEC_MODE_TUNNEL; 63655569ce2SKazunori MIYAZAWA case XFRM_MODE_BEET: 63755569ce2SKazunori MIYAZAWA return IPSEC_MODE_BEET; 63855569ce2SKazunori MIYAZAWA default: 63955569ce2SKazunori MIYAZAWA return -1; 64055569ce2SKazunori MIYAZAWA } 64155569ce2SKazunori MIYAZAWA } 64255569ce2SKazunori MIYAZAWA 64355569ce2SKazunori MIYAZAWA static inline int pfkey_mode_to_xfrm(int mode) 64455569ce2SKazunori MIYAZAWA { 64555569ce2SKazunori MIYAZAWA switch(mode) { 64655569ce2SKazunori MIYAZAWA case IPSEC_MODE_ANY: /*XXX*/ 64755569ce2SKazunori MIYAZAWA case IPSEC_MODE_TRANSPORT: 64855569ce2SKazunori MIYAZAWA return XFRM_MODE_TRANSPORT; 64955569ce2SKazunori MIYAZAWA case IPSEC_MODE_TUNNEL: 65055569ce2SKazunori MIYAZAWA return XFRM_MODE_TUNNEL; 65155569ce2SKazunori MIYAZAWA case IPSEC_MODE_BEET: 65255569ce2SKazunori MIYAZAWA return XFRM_MODE_BEET; 65355569ce2SKazunori MIYAZAWA default: 65455569ce2SKazunori MIYAZAWA return -1; 65555569ce2SKazunori MIYAZAWA } 65655569ce2SKazunori MIYAZAWA } 65755569ce2SKazunori MIYAZAWA 658050f009eSHerbert Xu static struct sk_buff *__pfkey_xfrm_state2msg(struct xfrm_state *x, 659050f009eSHerbert Xu int add_keys, int hsc) 6601da177e4SLinus Torvalds { 6611da177e4SLinus Torvalds struct sk_buff *skb; 6621da177e4SLinus Torvalds struct sadb_msg *hdr; 6631da177e4SLinus Torvalds struct sadb_sa *sa; 6641da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 6651da177e4SLinus Torvalds struct sadb_address *addr; 6661da177e4SLinus Torvalds struct sadb_key *key; 6671da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 6681da177e4SLinus Torvalds struct sockaddr_in *sin; 669df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 670df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 671df71837dSTrent Jaeger int ctx_size = 0; 6721da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6731da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 6741da177e4SLinus Torvalds #endif 6751da177e4SLinus Torvalds int size; 6761da177e4SLinus Torvalds int auth_key_size = 0; 6771da177e4SLinus Torvalds int encrypt_key_size = 0; 6781da177e4SLinus Torvalds int sockaddr_size; 6791da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 68055569ce2SKazunori MIYAZAWA int mode; 6811da177e4SLinus Torvalds 6821da177e4SLinus Torvalds /* address family check */ 6831da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 6841da177e4SLinus Torvalds if (!sockaddr_size) 6851da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 6861da177e4SLinus Torvalds 6871da177e4SLinus Torvalds /* base, SA, (lifetime (HSC),) address(SD), (address(P),) 6881da177e4SLinus Torvalds key(AE), (identity(SD),) (sensitivity)> */ 6891da177e4SLinus Torvalds size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) + 6901da177e4SLinus Torvalds sizeof(struct sadb_lifetime) + 6911da177e4SLinus Torvalds ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) + 6921da177e4SLinus Torvalds ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) + 6931da177e4SLinus Torvalds sizeof(struct sadb_address)*2 + 6941da177e4SLinus Torvalds sockaddr_size*2 + 6951da177e4SLinus Torvalds sizeof(struct sadb_x_sa2); 696df71837dSTrent Jaeger 697df71837dSTrent Jaeger if ((xfrm_ctx = x->security)) { 698df71837dSTrent Jaeger ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 699df71837dSTrent Jaeger size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 700df71837dSTrent Jaeger } 701df71837dSTrent Jaeger 7021da177e4SLinus Torvalds /* identity & sensitivity */ 7031da177e4SLinus Torvalds 7041da177e4SLinus Torvalds if ((x->props.family == AF_INET && 7051da177e4SLinus Torvalds x->sel.saddr.a4 != x->props.saddr.a4) 7061da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 7071da177e4SLinus Torvalds || (x->props.family == AF_INET6 && 7081da177e4SLinus Torvalds memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr))) 7091da177e4SLinus Torvalds #endif 7101da177e4SLinus Torvalds ) 7111da177e4SLinus Torvalds size += sizeof(struct sadb_address) + sockaddr_size; 7121da177e4SLinus Torvalds 7131da177e4SLinus Torvalds if (add_keys) { 7141da177e4SLinus Torvalds if (x->aalg && x->aalg->alg_key_len) { 7151da177e4SLinus Torvalds auth_key_size = 7161da177e4SLinus Torvalds PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8); 7171da177e4SLinus Torvalds size += sizeof(struct sadb_key) + auth_key_size; 7181da177e4SLinus Torvalds } 7191da177e4SLinus Torvalds if (x->ealg && x->ealg->alg_key_len) { 7201da177e4SLinus Torvalds encrypt_key_size = 7211da177e4SLinus Torvalds PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8); 7221da177e4SLinus Torvalds size += sizeof(struct sadb_key) + encrypt_key_size; 7231da177e4SLinus Torvalds } 7241da177e4SLinus Torvalds } 7251da177e4SLinus Torvalds if (x->encap) 7261da177e4SLinus Torvalds natt = x->encap; 7271da177e4SLinus Torvalds 7281da177e4SLinus Torvalds if (natt && natt->encap_type) { 7291da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_type); 7301da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7311da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7321da177e4SLinus Torvalds } 7331da177e4SLinus Torvalds 7341da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 7351da177e4SLinus Torvalds if (skb == NULL) 7361da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 7371da177e4SLinus Torvalds 7381da177e4SLinus Torvalds /* call should fill header later */ 7391da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 7401da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 7411da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 7421da177e4SLinus Torvalds 7431da177e4SLinus Torvalds /* sa */ 7441da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 7451da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 7461da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 7471da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 7481da177e4SLinus Torvalds sa->sadb_sa_replay = x->props.replay_window; 7494f09f0bbSHerbert Xu switch (x->km.state) { 7504f09f0bbSHerbert Xu case XFRM_STATE_VALID: 7514f09f0bbSHerbert Xu sa->sadb_sa_state = x->km.dying ? 7524f09f0bbSHerbert Xu SADB_SASTATE_DYING : SADB_SASTATE_MATURE; 7534f09f0bbSHerbert Xu break; 7544f09f0bbSHerbert Xu case XFRM_STATE_ACQ: 7551da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_LARVAL; 7564f09f0bbSHerbert Xu break; 7574f09f0bbSHerbert Xu default: 7581da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_DEAD; 7594f09f0bbSHerbert Xu break; 7604f09f0bbSHerbert Xu } 7611da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 7621da177e4SLinus Torvalds if (x->aalg) { 7631da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 7641da177e4SLinus Torvalds sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0; 7651da177e4SLinus Torvalds } 7661da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 7671da177e4SLinus Torvalds BUG_ON(x->ealg && x->calg); 7681da177e4SLinus Torvalds if (x->ealg) { 7691da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0); 7701da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 7711da177e4SLinus Torvalds } 7721da177e4SLinus Torvalds /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */ 7731da177e4SLinus Torvalds if (x->calg) { 7741da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0); 7751da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 7761da177e4SLinus Torvalds } 7771da177e4SLinus Torvalds 7781da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 7791da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_NOECN) 7801da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; 7811da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_DECAP_DSCP) 7821da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; 783dd87147eSHerbert Xu if (x->props.flags & XFRM_STATE_NOPMTUDISC) 784dd87147eSHerbert Xu sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; 7851da177e4SLinus Torvalds 7861da177e4SLinus Torvalds /* hard time */ 7871da177e4SLinus Torvalds if (hsc & 2) { 7881da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 7891da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 7901da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 7911da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 7921da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 7931da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.hard_packet_limit); 7941da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit); 7951da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds; 7961da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds; 7971da177e4SLinus Torvalds } 7981da177e4SLinus Torvalds /* soft time */ 7991da177e4SLinus Torvalds if (hsc & 1) { 8001da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8011da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8021da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8031da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8041da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 8051da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.soft_packet_limit); 8061da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit); 8071da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds; 8081da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds; 8091da177e4SLinus Torvalds } 8101da177e4SLinus Torvalds /* current time */ 8111da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8121da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8131da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8141da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8151da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 8161da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = x->curlft.packets; 8171da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = x->curlft.bytes; 8181da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->curlft.add_time; 8191da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->curlft.use_time; 8201da177e4SLinus Torvalds /* src address */ 8211da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8221da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8231da177e4SLinus Torvalds addr->sadb_address_len = 8241da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8251da177e4SLinus Torvalds sizeof(uint64_t); 8261da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 8271da177e4SLinus Torvalds /* "if the ports are non-zero, then the sadb_address_proto field, 8281da177e4SLinus Torvalds normally zero, MUST be filled in with the transport 8291da177e4SLinus Torvalds protocol's number." - RFC2367 */ 8301da177e4SLinus Torvalds addr->sadb_address_proto = 0; 8311da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8321da177e4SLinus Torvalds if (x->props.family == AF_INET) { 8331da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 8341da177e4SLinus Torvalds 8351da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8361da177e4SLinus Torvalds sin->sin_family = AF_INET; 8371da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 8381da177e4SLinus Torvalds sin->sin_port = 0; 8391da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8401da177e4SLinus Torvalds } 8411da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 8421da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 8431da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 8441da177e4SLinus Torvalds 8451da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 8461da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 8471da177e4SLinus Torvalds sin6->sin6_port = 0; 8481da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 8491da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->props.saddr.a6, 8501da177e4SLinus Torvalds sizeof(struct in6_addr)); 8511da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 8521da177e4SLinus Torvalds } 8531da177e4SLinus Torvalds #endif 8541da177e4SLinus Torvalds else 8551da177e4SLinus Torvalds BUG(); 8561da177e4SLinus Torvalds 8571da177e4SLinus Torvalds /* dst address */ 8581da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8591da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8601da177e4SLinus Torvalds addr->sadb_address_len = 8611da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8621da177e4SLinus Torvalds sizeof(uint64_t); 8631da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 8641da177e4SLinus Torvalds addr->sadb_address_proto = 0; 8651da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; /* XXX */ 8661da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8671da177e4SLinus Torvalds if (x->props.family == AF_INET) { 8681da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8691da177e4SLinus Torvalds sin->sin_family = AF_INET; 8701da177e4SLinus Torvalds sin->sin_addr.s_addr = x->id.daddr.a4; 8711da177e4SLinus Torvalds sin->sin_port = 0; 8721da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8731da177e4SLinus Torvalds 8741da177e4SLinus Torvalds if (x->sel.saddr.a4 != x->props.saddr.a4) { 8751da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8761da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8771da177e4SLinus Torvalds addr->sadb_address_len = 8781da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8791da177e4SLinus Torvalds sizeof(uint64_t); 8801da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 8811da177e4SLinus Torvalds addr->sadb_address_proto = 8821da177e4SLinus Torvalds pfkey_proto_from_xfrm(x->sel.proto); 8831da177e4SLinus Torvalds addr->sadb_address_prefixlen = x->sel.prefixlen_s; 8841da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8851da177e4SLinus Torvalds 8861da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8871da177e4SLinus Torvalds sin->sin_family = AF_INET; 8881da177e4SLinus Torvalds sin->sin_addr.s_addr = x->sel.saddr.a4; 8891da177e4SLinus Torvalds sin->sin_port = x->sel.sport; 8901da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8911da177e4SLinus Torvalds } 8921da177e4SLinus Torvalds } 8931da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 8941da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 8951da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 8981da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 8991da177e4SLinus Torvalds sin6->sin6_port = 0; 9001da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 9011da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr)); 9021da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 9031da177e4SLinus Torvalds 9041da177e4SLinus Torvalds if (memcmp (x->sel.saddr.a6, x->props.saddr.a6, 9051da177e4SLinus Torvalds sizeof(struct in6_addr))) { 9061da177e4SLinus Torvalds addr = (struct sadb_address *) skb_put(skb, 9071da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 9081da177e4SLinus Torvalds addr->sadb_address_len = 9091da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 9101da177e4SLinus Torvalds sizeof(uint64_t); 9111da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 9121da177e4SLinus Torvalds addr->sadb_address_proto = 9131da177e4SLinus Torvalds pfkey_proto_from_xfrm(x->sel.proto); 9141da177e4SLinus Torvalds addr->sadb_address_prefixlen = x->sel.prefixlen_s; 9151da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 9161da177e4SLinus Torvalds 9171da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 9181da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 9191da177e4SLinus Torvalds sin6->sin6_port = x->sel.sport; 9201da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 9211da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->sel.saddr.a6, 9221da177e4SLinus Torvalds sizeof(struct in6_addr)); 9231da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 9241da177e4SLinus Torvalds } 9251da177e4SLinus Torvalds } 9261da177e4SLinus Torvalds #endif 9271da177e4SLinus Torvalds else 9281da177e4SLinus Torvalds BUG(); 9291da177e4SLinus Torvalds 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 1014050f009eSHerbert Xu static inline struct sk_buff *pfkey_xfrm_state2msg(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 1023050f009eSHerbert Xu static inline struct sk_buff *pfkey_xfrm_state2msg_expire(struct xfrm_state *x, 1024050f009eSHerbert Xu int hsc) 1025050f009eSHerbert Xu { 1026050f009eSHerbert Xu return __pfkey_xfrm_state2msg(x, 0, hsc); 1027050f009eSHerbert Xu } 1028050f009eSHerbert Xu 10291da177e4SLinus Torvalds static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, 10301da177e4SLinus Torvalds void **ext_hdrs) 10311da177e4SLinus Torvalds { 10321da177e4SLinus Torvalds struct xfrm_state *x; 10331da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 10341da177e4SLinus Torvalds struct sadb_sa *sa; 10351da177e4SLinus Torvalds struct sadb_key *key; 1036df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 10371da177e4SLinus Torvalds uint16_t proto; 10381da177e4SLinus Torvalds int err; 10391da177e4SLinus Torvalds 10401da177e4SLinus Torvalds 10411da177e4SLinus Torvalds sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 10421da177e4SLinus Torvalds if (!sa || 10431da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 10441da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 10451da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10461da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_ESP && 10471da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]) 10481da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10491da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_AH && 10501da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_AUTH-1]) 10511da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10521da177e4SLinus Torvalds if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] != 10531da177e4SLinus Torvalds !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) 10541da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10551da177e4SLinus Torvalds 10561da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 10571da177e4SLinus Torvalds if (proto == 0) 10581da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10591da177e4SLinus Torvalds 10601da177e4SLinus Torvalds /* default error is no buffer space */ 10611da177e4SLinus Torvalds err = -ENOBUFS; 10621da177e4SLinus Torvalds 10631da177e4SLinus Torvalds /* RFC2367: 10641da177e4SLinus Torvalds 10651da177e4SLinus Torvalds Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message. 10661da177e4SLinus Torvalds SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not 10671da177e4SLinus Torvalds sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state. 10681da177e4SLinus Torvalds Therefore, the sadb_sa_state field of all submitted SAs MUST be 10691da177e4SLinus Torvalds SADB_SASTATE_MATURE and the kernel MUST return an error if this is 10701da177e4SLinus Torvalds not true. 10711da177e4SLinus Torvalds 10721da177e4SLinus Torvalds However, KAME setkey always uses SADB_SASTATE_LARVAL. 10731da177e4SLinus Torvalds Hence, we have to _ignore_ sadb_sa_state, which is also reasonable. 10741da177e4SLinus Torvalds */ 10751da177e4SLinus Torvalds if (sa->sadb_sa_auth > SADB_AALG_MAX || 10761da177e4SLinus Torvalds (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP && 10771da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_X_CALG_MAX) || 10781da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_EALG_MAX) 10791da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10801da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 10811da177e4SLinus Torvalds if (key != NULL && 10821da177e4SLinus Torvalds sa->sadb_sa_auth != SADB_X_AALG_NULL && 10831da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10841da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10851da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10861da177e4SLinus Torvalds key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 10871da177e4SLinus Torvalds if (key != NULL && 10881da177e4SLinus Torvalds sa->sadb_sa_encrypt != SADB_EALG_NULL && 10891da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10901da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10911da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10921da177e4SLinus Torvalds 10931da177e4SLinus Torvalds x = xfrm_state_alloc(); 10941da177e4SLinus Torvalds if (x == NULL) 10951da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 10961da177e4SLinus Torvalds 10971da177e4SLinus Torvalds x->id.proto = proto; 10981da177e4SLinus Torvalds x->id.spi = sa->sadb_sa_spi; 10991da177e4SLinus Torvalds x->props.replay_window = sa->sadb_sa_replay; 11001da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN) 11011da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_NOECN; 11021da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) 11031da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_DECAP_DSCP; 1104dd87147eSHerbert Xu if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC) 1105dd87147eSHerbert Xu x->props.flags |= XFRM_STATE_NOPMTUDISC; 11061da177e4SLinus Torvalds 11071da177e4SLinus Torvalds lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; 11081da177e4SLinus Torvalds if (lifetime != NULL) { 11091da177e4SLinus Torvalds x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 11101da177e4SLinus Torvalds x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 11111da177e4SLinus Torvalds x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 11121da177e4SLinus Torvalds x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11131da177e4SLinus Torvalds } 11141da177e4SLinus Torvalds lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]; 11151da177e4SLinus Torvalds if (lifetime != NULL) { 11161da177e4SLinus Torvalds x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 11171da177e4SLinus Torvalds x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 11181da177e4SLinus Torvalds x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 11191da177e4SLinus Torvalds x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11201da177e4SLinus Torvalds } 1121df71837dSTrent Jaeger 1122df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 1123df71837dSTrent Jaeger if (sec_ctx != NULL) { 1124df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 1125df71837dSTrent Jaeger 1126df71837dSTrent Jaeger if (!uctx) 1127df71837dSTrent Jaeger goto out; 1128df71837dSTrent Jaeger 1129df71837dSTrent Jaeger err = security_xfrm_state_alloc(x, uctx); 1130df71837dSTrent Jaeger kfree(uctx); 1131df71837dSTrent Jaeger 1132df71837dSTrent Jaeger if (err) 1133df71837dSTrent Jaeger goto out; 1134df71837dSTrent Jaeger } 1135df71837dSTrent Jaeger 11361da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 11371da177e4SLinus Torvalds if (sa->sadb_sa_auth) { 11381da177e4SLinus Torvalds int keysize = 0; 11391da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth); 11401da177e4SLinus Torvalds if (!a) { 11411da177e4SLinus Torvalds err = -ENOSYS; 11421da177e4SLinus Torvalds goto out; 11431da177e4SLinus Torvalds } 11441da177e4SLinus Torvalds if (key) 11451da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11461da177e4SLinus Torvalds x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); 11471da177e4SLinus Torvalds if (!x->aalg) 11481da177e4SLinus Torvalds goto out; 11491da177e4SLinus Torvalds strcpy(x->aalg->alg_name, a->name); 11501da177e4SLinus Torvalds x->aalg->alg_key_len = 0; 11511da177e4SLinus Torvalds if (key) { 11521da177e4SLinus Torvalds x->aalg->alg_key_len = key->sadb_key_bits; 11531da177e4SLinus Torvalds memcpy(x->aalg->alg_key, key+1, keysize); 11541da177e4SLinus Torvalds } 11551da177e4SLinus Torvalds x->props.aalgo = sa->sadb_sa_auth; 11561da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11571da177e4SLinus Torvalds } 11581da177e4SLinus Torvalds if (sa->sadb_sa_encrypt) { 11591da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { 11601da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt); 11611da177e4SLinus Torvalds if (!a) { 11621da177e4SLinus Torvalds err = -ENOSYS; 11631da177e4SLinus Torvalds goto out; 11641da177e4SLinus Torvalds } 11651da177e4SLinus Torvalds x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL); 11661da177e4SLinus Torvalds if (!x->calg) 11671da177e4SLinus Torvalds goto out; 11681da177e4SLinus Torvalds strcpy(x->calg->alg_name, a->name); 11691da177e4SLinus Torvalds x->props.calgo = sa->sadb_sa_encrypt; 11701da177e4SLinus Torvalds } else { 11711da177e4SLinus Torvalds int keysize = 0; 11721da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt); 11731da177e4SLinus Torvalds if (!a) { 11741da177e4SLinus Torvalds err = -ENOSYS; 11751da177e4SLinus Torvalds goto out; 11761da177e4SLinus Torvalds } 11771da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 11781da177e4SLinus Torvalds if (key) 11791da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11801da177e4SLinus Torvalds x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); 11811da177e4SLinus Torvalds if (!x->ealg) 11821da177e4SLinus Torvalds goto out; 11831da177e4SLinus Torvalds strcpy(x->ealg->alg_name, a->name); 11841da177e4SLinus Torvalds x->ealg->alg_key_len = 0; 11851da177e4SLinus Torvalds if (key) { 11861da177e4SLinus Torvalds x->ealg->alg_key_len = key->sadb_key_bits; 11871da177e4SLinus Torvalds memcpy(x->ealg->alg_key, key+1, keysize); 11881da177e4SLinus Torvalds } 11891da177e4SLinus Torvalds x->props.ealgo = sa->sadb_sa_encrypt; 11901da177e4SLinus Torvalds } 11911da177e4SLinus Torvalds } 11921da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11931da177e4SLinus Torvalds 11941da177e4SLinus Torvalds x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 11951da177e4SLinus Torvalds &x->props.saddr); 11961da177e4SLinus Torvalds if (!x->props.family) { 11971da177e4SLinus Torvalds err = -EAFNOSUPPORT; 11981da177e4SLinus Torvalds goto out; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 12011da177e4SLinus Torvalds &x->id.daddr); 12021da177e4SLinus Torvalds 12031da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_SA2-1]) { 12041da177e4SLinus Torvalds struct sadb_x_sa2 *sa2 = (void*)ext_hdrs[SADB_X_EXT_SA2-1]; 120555569ce2SKazunori MIYAZAWA int mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 120655569ce2SKazunori MIYAZAWA if (mode < 0) { 120755569ce2SKazunori MIYAZAWA err = -EINVAL; 120855569ce2SKazunori MIYAZAWA goto out; 120955569ce2SKazunori MIYAZAWA } 121055569ce2SKazunori MIYAZAWA x->props.mode = mode; 12111da177e4SLinus Torvalds x->props.reqid = sa2->sadb_x_sa2_reqid; 12121da177e4SLinus Torvalds } 12131da177e4SLinus Torvalds 12141da177e4SLinus Torvalds if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) { 12151da177e4SLinus Torvalds struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds /* Nobody uses this, but we try. */ 12181da177e4SLinus Torvalds x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr); 12191da177e4SLinus Torvalds x->sel.prefixlen_s = addr->sadb_address_prefixlen; 12201da177e4SLinus Torvalds } 12211da177e4SLinus Torvalds 12224a4b6271SJoy Latten if (!x->sel.family) 12234a4b6271SJoy Latten x->sel.family = x->props.family; 12244a4b6271SJoy Latten 12251da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { 12261da177e4SLinus Torvalds struct sadb_x_nat_t_type* n_type; 12271da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt; 12281da177e4SLinus Torvalds 12291da177e4SLinus Torvalds x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL); 12301da177e4SLinus Torvalds if (!x->encap) 12311da177e4SLinus Torvalds goto out; 12321da177e4SLinus Torvalds 12331da177e4SLinus Torvalds natt = x->encap; 12341da177e4SLinus Torvalds n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; 12351da177e4SLinus Torvalds natt->encap_type = n_type->sadb_x_nat_t_type_type; 12361da177e4SLinus Torvalds 12371da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) { 12381da177e4SLinus Torvalds struct sadb_x_nat_t_port* n_port = 12391da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]; 12401da177e4SLinus Torvalds natt->encap_sport = n_port->sadb_x_nat_t_port_port; 12411da177e4SLinus Torvalds } 12421da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) { 12431da177e4SLinus Torvalds struct sadb_x_nat_t_port* n_port = 12441da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]; 12451da177e4SLinus Torvalds natt->encap_dport = n_port->sadb_x_nat_t_port_port; 12461da177e4SLinus Torvalds } 12471da177e4SLinus Torvalds } 12481da177e4SLinus Torvalds 124972cb6962SHerbert Xu err = xfrm_init_state(x); 125072cb6962SHerbert Xu if (err) 12511da177e4SLinus Torvalds goto out; 125272cb6962SHerbert Xu 12531da177e4SLinus Torvalds x->km.seq = hdr->sadb_msg_seq; 12541da177e4SLinus Torvalds return x; 12551da177e4SLinus Torvalds 12561da177e4SLinus Torvalds out: 12571da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 12581da177e4SLinus Torvalds xfrm_state_put(x); 12591da177e4SLinus Torvalds return ERR_PTR(err); 12601da177e4SLinus Torvalds } 12611da177e4SLinus Torvalds 12621da177e4SLinus Torvalds static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 12631da177e4SLinus Torvalds { 12641da177e4SLinus Torvalds return -EOPNOTSUPP; 12651da177e4SLinus Torvalds } 12661da177e4SLinus Torvalds 12671da177e4SLinus Torvalds static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 12681da177e4SLinus Torvalds { 12691da177e4SLinus Torvalds struct sk_buff *resp_skb; 12701da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 12711da177e4SLinus Torvalds struct sadb_address *saddr, *daddr; 12721da177e4SLinus Torvalds struct sadb_msg *out_hdr; 1273658b219eSHerbert Xu struct sadb_spirange *range; 12741da177e4SLinus Torvalds struct xfrm_state *x = NULL; 127555569ce2SKazunori MIYAZAWA int mode; 1276658b219eSHerbert Xu int err; 1277658b219eSHerbert Xu u32 min_spi, max_spi; 12781da177e4SLinus Torvalds u32 reqid; 12791da177e4SLinus Torvalds u8 proto; 12801da177e4SLinus Torvalds unsigned short family; 12811da177e4SLinus Torvalds xfrm_address_t *xsaddr = NULL, *xdaddr = NULL; 12821da177e4SLinus Torvalds 12831da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 12841da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 12851da177e4SLinus Torvalds return -EINVAL; 12861da177e4SLinus Torvalds 12871da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 12881da177e4SLinus Torvalds if (proto == 0) 12891da177e4SLinus Torvalds return -EINVAL; 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) { 129255569ce2SKazunori MIYAZAWA mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 129355569ce2SKazunori MIYAZAWA if (mode < 0) 129455569ce2SKazunori MIYAZAWA return -EINVAL; 12951da177e4SLinus Torvalds reqid = sa2->sadb_x_sa2_reqid; 12961da177e4SLinus Torvalds } else { 12971da177e4SLinus Torvalds mode = 0; 12981da177e4SLinus Torvalds reqid = 0; 12991da177e4SLinus Torvalds } 13001da177e4SLinus Torvalds 13011da177e4SLinus Torvalds saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1]; 13021da177e4SLinus Torvalds daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 13031da177e4SLinus Torvalds 13041da177e4SLinus Torvalds family = ((struct sockaddr *)(saddr + 1))->sa_family; 13051da177e4SLinus Torvalds switch (family) { 13061da177e4SLinus Torvalds case AF_INET: 13071da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr; 13081da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr; 13091da177e4SLinus Torvalds break; 13101da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 13111da177e4SLinus Torvalds case AF_INET6: 13121da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6_addr; 13131da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6_addr; 13141da177e4SLinus Torvalds break; 13151da177e4SLinus Torvalds #endif 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds 13181da177e4SLinus Torvalds if (hdr->sadb_msg_seq) { 13191da177e4SLinus Torvalds x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); 13201da177e4SLinus Torvalds if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) { 13211da177e4SLinus Torvalds xfrm_state_put(x); 13221da177e4SLinus Torvalds x = NULL; 13231da177e4SLinus Torvalds } 13241da177e4SLinus Torvalds } 13251da177e4SLinus Torvalds 13261da177e4SLinus Torvalds if (!x) 13271da177e4SLinus Torvalds x = xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family); 13281da177e4SLinus Torvalds 13291da177e4SLinus Torvalds if (x == NULL) 13301da177e4SLinus Torvalds return -ENOENT; 13311da177e4SLinus Torvalds 13321da177e4SLinus Torvalds min_spi = 0x100; 13331da177e4SLinus Torvalds max_spi = 0x0fffffff; 1334658b219eSHerbert Xu 1335658b219eSHerbert Xu range = ext_hdrs[SADB_EXT_SPIRANGE-1]; 1336658b219eSHerbert Xu if (range) { 1337658b219eSHerbert Xu min_spi = range->sadb_spirange_min; 1338658b219eSHerbert Xu max_spi = range->sadb_spirange_max; 13391da177e4SLinus Torvalds } 1340658b219eSHerbert Xu 1341658b219eSHerbert Xu err = xfrm_alloc_spi(x, min_spi, max_spi); 1342050f009eSHerbert Xu resp_skb = err ? ERR_PTR(err) : pfkey_xfrm_state2msg(x); 13431da177e4SLinus Torvalds 13441da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 13451da177e4SLinus Torvalds xfrm_state_put(x); 13461da177e4SLinus Torvalds return PTR_ERR(resp_skb); 13471da177e4SLinus Torvalds } 13481da177e4SLinus Torvalds 13491da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) resp_skb->data; 13501da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 13511da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_GETSPI; 13521da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 13531da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 13541da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 13551da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 13561da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds xfrm_state_put(x); 13591da177e4SLinus Torvalds 13601da177e4SLinus Torvalds pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk); 13611da177e4SLinus Torvalds 13621da177e4SLinus Torvalds return 0; 13631da177e4SLinus Torvalds } 13641da177e4SLinus Torvalds 13651da177e4SLinus Torvalds static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 13661da177e4SLinus Torvalds { 13671da177e4SLinus Torvalds struct xfrm_state *x; 13681da177e4SLinus Torvalds 13691da177e4SLinus Torvalds if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8) 13701da177e4SLinus Torvalds return -EOPNOTSUPP; 13711da177e4SLinus Torvalds 13721da177e4SLinus Torvalds if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0) 13731da177e4SLinus Torvalds return 0; 13741da177e4SLinus Torvalds 13751da177e4SLinus Torvalds x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); 13761da177e4SLinus Torvalds if (x == NULL) 13771da177e4SLinus Torvalds return 0; 13781da177e4SLinus Torvalds 13791da177e4SLinus Torvalds spin_lock_bh(&x->lock); 13801da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ) { 13811da177e4SLinus Torvalds x->km.state = XFRM_STATE_ERROR; 13821da177e4SLinus Torvalds wake_up(&km_waitq); 13831da177e4SLinus Torvalds } 13841da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 13851da177e4SLinus Torvalds xfrm_state_put(x); 13861da177e4SLinus Torvalds return 0; 13871da177e4SLinus Torvalds } 13881da177e4SLinus Torvalds 138926b15dadSJamal Hadi Salim static inline int event2poltype(int event) 139026b15dadSJamal Hadi Salim { 139126b15dadSJamal Hadi Salim switch (event) { 1392f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 139326b15dadSJamal Hadi Salim return SADB_X_SPDDELETE; 1394f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 139526b15dadSJamal Hadi Salim return SADB_X_SPDADD; 1396f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 139726b15dadSJamal Hadi Salim return SADB_X_SPDUPDATE; 1398f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 139926b15dadSJamal Hadi Salim // return SADB_X_SPDEXPIRE; 140026b15dadSJamal Hadi Salim default: 140126b15dadSJamal Hadi Salim printk("pfkey: Unknown policy event %d\n", event); 140226b15dadSJamal Hadi Salim break; 140326b15dadSJamal Hadi Salim } 140426b15dadSJamal Hadi Salim 140526b15dadSJamal Hadi Salim return 0; 140626b15dadSJamal Hadi Salim } 140726b15dadSJamal Hadi Salim 140826b15dadSJamal Hadi Salim static inline int event2keytype(int event) 140926b15dadSJamal Hadi Salim { 141026b15dadSJamal Hadi Salim switch (event) { 1411f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 141226b15dadSJamal Hadi Salim return SADB_DELETE; 1413f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 141426b15dadSJamal Hadi Salim return SADB_ADD; 1415f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 141626b15dadSJamal Hadi Salim return SADB_UPDATE; 1417f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 141826b15dadSJamal Hadi Salim return SADB_EXPIRE; 141926b15dadSJamal Hadi Salim default: 142026b15dadSJamal Hadi Salim printk("pfkey: Unknown SA event %d\n", event); 142126b15dadSJamal Hadi Salim break; 142226b15dadSJamal Hadi Salim } 142326b15dadSJamal Hadi Salim 142426b15dadSJamal Hadi Salim return 0; 142526b15dadSJamal Hadi Salim } 142626b15dadSJamal Hadi Salim 142726b15dadSJamal Hadi Salim /* ADD/UPD/DEL */ 142826b15dadSJamal Hadi Salim static int key_notify_sa(struct xfrm_state *x, struct km_event *c) 142926b15dadSJamal Hadi Salim { 143026b15dadSJamal Hadi Salim struct sk_buff *skb; 143126b15dadSJamal Hadi Salim struct sadb_msg *hdr; 143226b15dadSJamal Hadi Salim 1433050f009eSHerbert Xu skb = pfkey_xfrm_state2msg(x); 143426b15dadSJamal Hadi Salim 143526b15dadSJamal Hadi Salim if (IS_ERR(skb)) 143626b15dadSJamal Hadi Salim return PTR_ERR(skb); 143726b15dadSJamal Hadi Salim 143826b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb->data; 143926b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 144026b15dadSJamal Hadi Salim hdr->sadb_msg_type = event2keytype(c->event); 144126b15dadSJamal Hadi Salim hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 144226b15dadSJamal Hadi Salim hdr->sadb_msg_errno = 0; 144326b15dadSJamal Hadi Salim hdr->sadb_msg_reserved = 0; 144426b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 144526b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 144626b15dadSJamal Hadi Salim 144726b15dadSJamal Hadi Salim pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 144826b15dadSJamal Hadi Salim 144926b15dadSJamal Hadi Salim return 0; 145026b15dadSJamal Hadi Salim } 14511da177e4SLinus Torvalds 14521da177e4SLinus Torvalds static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 14531da177e4SLinus Torvalds { 14541da177e4SLinus Torvalds struct xfrm_state *x; 14551da177e4SLinus Torvalds int err; 145626b15dadSJamal Hadi Salim struct km_event c; 14571da177e4SLinus Torvalds 14581da177e4SLinus Torvalds x = pfkey_msg2xfrm_state(hdr, ext_hdrs); 14591da177e4SLinus Torvalds if (IS_ERR(x)) 14601da177e4SLinus Torvalds return PTR_ERR(x); 14611da177e4SLinus Torvalds 146226b15dadSJamal Hadi Salim xfrm_state_hold(x); 14631da177e4SLinus Torvalds if (hdr->sadb_msg_type == SADB_ADD) 14641da177e4SLinus Torvalds err = xfrm_state_add(x); 14651da177e4SLinus Torvalds else 14661da177e4SLinus Torvalds err = xfrm_state_update(x); 14671da177e4SLinus Torvalds 1468ab5f5e8bSJoy Latten xfrm_audit_state_add(x, err ? 0 : 1, 1469*0c11b942SAl Viro audit_get_loginuid(current), 0); 1470161a09e7SJoy Latten 14711da177e4SLinus Torvalds if (err < 0) { 14721da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 147321380b81SHerbert Xu __xfrm_state_put(x); 14747d6dfe1fSPatrick McHardy goto out; 14751da177e4SLinus Torvalds } 14761da177e4SLinus Torvalds 147726b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_ADD) 1478f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWSA; 147926b15dadSJamal Hadi Salim else 1480f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDSA; 148126b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 148226b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 148326b15dadSJamal Hadi Salim km_state_notify(x, &c); 14847d6dfe1fSPatrick McHardy out: 148526b15dadSJamal Hadi Salim xfrm_state_put(x); 148626b15dadSJamal Hadi Salim return err; 14871da177e4SLinus Torvalds } 14881da177e4SLinus Torvalds 14891da177e4SLinus Torvalds static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 14901da177e4SLinus Torvalds { 14911da177e4SLinus Torvalds struct xfrm_state *x; 149226b15dadSJamal Hadi Salim struct km_event c; 149326b15dadSJamal Hadi Salim int err; 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 14961da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 14971da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 14981da177e4SLinus Torvalds return -EINVAL; 14991da177e4SLinus Torvalds 15001da177e4SLinus Torvalds x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); 15011da177e4SLinus Torvalds if (x == NULL) 15021da177e4SLinus Torvalds return -ESRCH; 15031da177e4SLinus Torvalds 1504c8c05a8eSCatherine Zhang if ((err = security_xfrm_state_delete(x))) 1505c8c05a8eSCatherine Zhang goto out; 1506c8c05a8eSCatherine Zhang 15071da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 1508c8c05a8eSCatherine Zhang err = -EPERM; 1509c8c05a8eSCatherine Zhang goto out; 15101da177e4SLinus Torvalds } 15111da177e4SLinus Torvalds 151226b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 1513161a09e7SJoy Latten 1514c8c05a8eSCatherine Zhang if (err < 0) 1515c8c05a8eSCatherine Zhang goto out; 151626b15dadSJamal Hadi Salim 151726b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 151826b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1519f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELSA; 152026b15dadSJamal Hadi Salim km_state_notify(x, &c); 1521c8c05a8eSCatherine Zhang out: 1522ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, 1523*0c11b942SAl Viro audit_get_loginuid(current), 0); 15241da177e4SLinus Torvalds xfrm_state_put(x); 15251da177e4SLinus Torvalds 152626b15dadSJamal Hadi Salim return err; 15271da177e4SLinus Torvalds } 15281da177e4SLinus Torvalds 15291da177e4SLinus Torvalds static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 15301da177e4SLinus Torvalds { 15311da177e4SLinus Torvalds __u8 proto; 15321da177e4SLinus Torvalds struct sk_buff *out_skb; 15331da177e4SLinus Torvalds struct sadb_msg *out_hdr; 15341da177e4SLinus Torvalds struct xfrm_state *x; 15351da177e4SLinus Torvalds 15361da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 15371da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 15381da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 15391da177e4SLinus Torvalds return -EINVAL; 15401da177e4SLinus Torvalds 15411da177e4SLinus Torvalds x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); 15421da177e4SLinus Torvalds if (x == NULL) 15431da177e4SLinus Torvalds return -ESRCH; 15441da177e4SLinus Torvalds 1545050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg(x); 15461da177e4SLinus Torvalds proto = x->id.proto; 15471da177e4SLinus Torvalds xfrm_state_put(x); 15481da177e4SLinus Torvalds if (IS_ERR(out_skb)) 15491da177e4SLinus Torvalds return PTR_ERR(out_skb); 15501da177e4SLinus Torvalds 15511da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 15521da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 1553435000beSCharles Hardin out_hdr->sadb_msg_type = SADB_GET; 15541da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 15551da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 15561da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 15571da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 15581da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 15591da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); 15601da177e4SLinus Torvalds 15611da177e4SLinus Torvalds return 0; 15621da177e4SLinus Torvalds } 15631da177e4SLinus Torvalds 156400fa0233SRandy Dunlap static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, 1565dd0fc66fSAl Viro gfp_t allocation) 15661da177e4SLinus Torvalds { 15671da177e4SLinus Torvalds struct sk_buff *skb; 15681da177e4SLinus Torvalds struct sadb_msg *hdr; 15691da177e4SLinus Torvalds int len, auth_len, enc_len, i; 15701da177e4SLinus Torvalds 15711da177e4SLinus Torvalds auth_len = xfrm_count_auth_supported(); 15721da177e4SLinus Torvalds if (auth_len) { 15731da177e4SLinus Torvalds auth_len *= sizeof(struct sadb_alg); 15741da177e4SLinus Torvalds auth_len += sizeof(struct sadb_supported); 15751da177e4SLinus Torvalds } 15761da177e4SLinus Torvalds 15771da177e4SLinus Torvalds enc_len = xfrm_count_enc_supported(); 15781da177e4SLinus Torvalds if (enc_len) { 15791da177e4SLinus Torvalds enc_len *= sizeof(struct sadb_alg); 15801da177e4SLinus Torvalds enc_len += sizeof(struct sadb_supported); 15811da177e4SLinus Torvalds } 15821da177e4SLinus Torvalds 15831da177e4SLinus Torvalds len = enc_len + auth_len + sizeof(struct sadb_msg); 15841da177e4SLinus Torvalds 15851da177e4SLinus Torvalds skb = alloc_skb(len + 16, allocation); 15861da177e4SLinus Torvalds if (!skb) 15871da177e4SLinus Torvalds goto out_put_algs; 15881da177e4SLinus Torvalds 15891da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr)); 15901da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 15911da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 15921da177e4SLinus Torvalds hdr->sadb_msg_len = len / sizeof(uint64_t); 15931da177e4SLinus Torvalds 15941da177e4SLinus Torvalds if (auth_len) { 15951da177e4SLinus Torvalds struct sadb_supported *sp; 15961da177e4SLinus Torvalds struct sadb_alg *ap; 15971da177e4SLinus Torvalds 15981da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, auth_len); 15991da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 16001da177e4SLinus Torvalds 16011da177e4SLinus Torvalds sp->sadb_supported_len = auth_len / sizeof(uint64_t); 16021da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 16031da177e4SLinus Torvalds 16041da177e4SLinus Torvalds for (i = 0; ; i++) { 16051da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 16061da177e4SLinus Torvalds if (!aalg) 16071da177e4SLinus Torvalds break; 16081da177e4SLinus Torvalds if (aalg->available) 16091da177e4SLinus Torvalds *ap++ = aalg->desc; 16101da177e4SLinus Torvalds } 16111da177e4SLinus Torvalds } 16121da177e4SLinus Torvalds 16131da177e4SLinus Torvalds if (enc_len) { 16141da177e4SLinus Torvalds struct sadb_supported *sp; 16151da177e4SLinus Torvalds struct sadb_alg *ap; 16161da177e4SLinus Torvalds 16171da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, enc_len); 16181da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 16191da177e4SLinus Torvalds 16201da177e4SLinus Torvalds sp->sadb_supported_len = enc_len / sizeof(uint64_t); 16211da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; 16221da177e4SLinus Torvalds 16231da177e4SLinus Torvalds for (i = 0; ; i++) { 16241da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 16251da177e4SLinus Torvalds if (!ealg) 16261da177e4SLinus Torvalds break; 16271da177e4SLinus Torvalds if (ealg->available) 16281da177e4SLinus Torvalds *ap++ = ealg->desc; 16291da177e4SLinus Torvalds } 16301da177e4SLinus Torvalds } 16311da177e4SLinus Torvalds 16321da177e4SLinus Torvalds out_put_algs: 16331da177e4SLinus Torvalds return skb; 16341da177e4SLinus Torvalds } 16351da177e4SLinus Torvalds 16361da177e4SLinus Torvalds static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 16371da177e4SLinus Torvalds { 16381da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 16391da177e4SLinus Torvalds struct sk_buff *supp_skb; 16401da177e4SLinus Torvalds 16411da177e4SLinus Torvalds if (hdr->sadb_msg_satype > SADB_SATYPE_MAX) 16421da177e4SLinus Torvalds return -EINVAL; 16431da177e4SLinus Torvalds 16441da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) { 16451da177e4SLinus Torvalds if (pfk->registered&(1<<hdr->sadb_msg_satype)) 16461da177e4SLinus Torvalds return -EEXIST; 16471da177e4SLinus Torvalds pfk->registered |= (1<<hdr->sadb_msg_satype); 16481da177e4SLinus Torvalds } 16491da177e4SLinus Torvalds 16501da177e4SLinus Torvalds xfrm_probe_algs(); 16511da177e4SLinus Torvalds 16521da177e4SLinus Torvalds supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); 16531da177e4SLinus Torvalds if (!supp_skb) { 16541da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) 16551da177e4SLinus Torvalds pfk->registered &= ~(1<<hdr->sadb_msg_satype); 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds return -ENOBUFS; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds 16601da177e4SLinus Torvalds pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk); 16611da177e4SLinus Torvalds 16621da177e4SLinus Torvalds return 0; 16631da177e4SLinus Torvalds } 16641da177e4SLinus Torvalds 166526b15dadSJamal Hadi Salim static int key_notify_sa_flush(struct km_event *c) 166626b15dadSJamal Hadi Salim { 166726b15dadSJamal Hadi Salim struct sk_buff *skb; 166826b15dadSJamal Hadi Salim struct sadb_msg *hdr; 166926b15dadSJamal Hadi Salim 167026b15dadSJamal Hadi Salim skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 167126b15dadSJamal Hadi Salim if (!skb) 167226b15dadSJamal Hadi Salim return -ENOBUFS; 167326b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 1674bf08867fSHerbert Xu hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto); 1675151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_FLUSH; 167626b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 167726b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 167826b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 167926b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 168026b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 168126b15dadSJamal Hadi Salim 168226b15dadSJamal Hadi Salim pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 168326b15dadSJamal Hadi Salim 168426b15dadSJamal Hadi Salim return 0; 168526b15dadSJamal Hadi Salim } 168626b15dadSJamal Hadi Salim 16871da177e4SLinus Torvalds static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 16881da177e4SLinus Torvalds { 16891da177e4SLinus Torvalds unsigned proto; 169026b15dadSJamal Hadi Salim struct km_event c; 1691161a09e7SJoy Latten struct xfrm_audit audit_info; 16924aa2e62cSJoy Latten int err; 16931da177e4SLinus Torvalds 16941da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 16951da177e4SLinus Torvalds if (proto == 0) 16961da177e4SLinus Torvalds return -EINVAL; 16971da177e4SLinus Torvalds 1698*0c11b942SAl Viro audit_info.loginuid = audit_get_loginuid(current); 1699161a09e7SJoy Latten audit_info.secid = 0; 17004aa2e62cSJoy Latten err = xfrm_state_flush(proto, &audit_info); 17014aa2e62cSJoy Latten if (err) 17024aa2e62cSJoy Latten return err; 1703bf08867fSHerbert Xu c.data.proto = proto; 170426b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 170526b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1706f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHSA; 170726b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 17081da177e4SLinus Torvalds 17091da177e4SLinus Torvalds return 0; 17101da177e4SLinus Torvalds } 17111da177e4SLinus Torvalds 17121da177e4SLinus Torvalds struct pfkey_dump_data 17131da177e4SLinus Torvalds { 17141da177e4SLinus Torvalds struct sk_buff *skb; 17151da177e4SLinus Torvalds struct sadb_msg *hdr; 17161da177e4SLinus Torvalds struct sock *sk; 17171da177e4SLinus Torvalds }; 17181da177e4SLinus Torvalds 17191da177e4SLinus Torvalds static int dump_sa(struct xfrm_state *x, int count, void *ptr) 17201da177e4SLinus Torvalds { 17211da177e4SLinus Torvalds struct pfkey_dump_data *data = ptr; 17221da177e4SLinus Torvalds struct sk_buff *out_skb; 17231da177e4SLinus Torvalds struct sadb_msg *out_hdr; 17241da177e4SLinus Torvalds 1725050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg(x); 17261da177e4SLinus Torvalds if (IS_ERR(out_skb)) 17271da177e4SLinus Torvalds return PTR_ERR(out_skb); 17281da177e4SLinus Torvalds 17291da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 17301da177e4SLinus Torvalds out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; 17311da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_DUMP; 17321da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 17331da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 17341da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 17351da177e4SLinus Torvalds out_hdr->sadb_msg_seq = count; 17361da177e4SLinus Torvalds out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; 17371da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); 17381da177e4SLinus Torvalds return 0; 17391da177e4SLinus Torvalds } 17401da177e4SLinus Torvalds 17411da177e4SLinus Torvalds static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 17421da177e4SLinus Torvalds { 17431da177e4SLinus Torvalds u8 proto; 17441da177e4SLinus Torvalds struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 17451da177e4SLinus Torvalds 17461da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 17471da177e4SLinus Torvalds if (proto == 0) 17481da177e4SLinus Torvalds return -EINVAL; 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds return xfrm_state_walk(proto, dump_sa, &data); 17511da177e4SLinus Torvalds } 17521da177e4SLinus Torvalds 17531da177e4SLinus Torvalds static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 17541da177e4SLinus Torvalds { 17551da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 17561da177e4SLinus Torvalds int satype = hdr->sadb_msg_satype; 17571da177e4SLinus Torvalds 17581da177e4SLinus Torvalds if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) { 17591da177e4SLinus Torvalds /* XXX we mangle packet... */ 17601da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 17611da177e4SLinus Torvalds if (satype != 0 && satype != 1) 17621da177e4SLinus Torvalds return -EINVAL; 17631da177e4SLinus Torvalds pfk->promisc = satype; 17641da177e4SLinus Torvalds } 17651da177e4SLinus Torvalds pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL); 17661da177e4SLinus Torvalds return 0; 17671da177e4SLinus Torvalds } 17681da177e4SLinus Torvalds 17691da177e4SLinus Torvalds static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) 17701da177e4SLinus Torvalds { 17711da177e4SLinus Torvalds int i; 17721da177e4SLinus Torvalds u32 reqid = *(u32*)ptr; 17731da177e4SLinus Torvalds 17741da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 17751da177e4SLinus Torvalds if (xp->xfrm_vec[i].reqid == reqid) 17761da177e4SLinus Torvalds return -EEXIST; 17771da177e4SLinus Torvalds } 17781da177e4SLinus Torvalds return 0; 17791da177e4SLinus Torvalds } 17801da177e4SLinus Torvalds 17811da177e4SLinus Torvalds static u32 gen_reqid(void) 17821da177e4SLinus Torvalds { 17831da177e4SLinus Torvalds u32 start; 17841da177e4SLinus Torvalds static u32 reqid = IPSEC_MANUAL_REQID_MAX; 17851da177e4SLinus Torvalds 17861da177e4SLinus Torvalds start = reqid; 17871da177e4SLinus Torvalds do { 17881da177e4SLinus Torvalds ++reqid; 17891da177e4SLinus Torvalds if (reqid == 0) 17901da177e4SLinus Torvalds reqid = IPSEC_MANUAL_REQID_MAX+1; 1791f7b6983fSMasahide NAKAMURA if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, 1792f7b6983fSMasahide NAKAMURA (void*)&reqid) != -EEXIST) 17931da177e4SLinus Torvalds return reqid; 17941da177e4SLinus Torvalds } while (reqid != start); 17951da177e4SLinus Torvalds return 0; 17961da177e4SLinus Torvalds } 17971da177e4SLinus Torvalds 17981da177e4SLinus Torvalds static int 17991da177e4SLinus Torvalds parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) 18001da177e4SLinus Torvalds { 18011da177e4SLinus Torvalds struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr; 18021da177e4SLinus Torvalds struct sockaddr_in *sin; 18031da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 18041da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 18051da177e4SLinus Torvalds #endif 180655569ce2SKazunori MIYAZAWA int mode; 18071da177e4SLinus Torvalds 18081da177e4SLinus Torvalds if (xp->xfrm_nr >= XFRM_MAX_DEPTH) 18091da177e4SLinus Torvalds return -ELOOP; 18101da177e4SLinus Torvalds 18111da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_mode == 0) 18121da177e4SLinus Torvalds return -EINVAL; 18131da177e4SLinus Torvalds 18141da177e4SLinus Torvalds t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */ 181555569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0) 181655569ce2SKazunori MIYAZAWA return -EINVAL; 181755569ce2SKazunori MIYAZAWA t->mode = mode; 18181da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) 18191da177e4SLinus Torvalds t->optional = 1; 18201da177e4SLinus Torvalds else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) { 18211da177e4SLinus Torvalds t->reqid = rq->sadb_x_ipsecrequest_reqid; 18221da177e4SLinus Torvalds if (t->reqid > IPSEC_MANUAL_REQID_MAX) 18231da177e4SLinus Torvalds t->reqid = 0; 18241da177e4SLinus Torvalds if (!t->reqid && !(t->reqid = gen_reqid())) 18251da177e4SLinus Torvalds return -ENOBUFS; 18261da177e4SLinus Torvalds } 18271da177e4SLinus Torvalds 18281da177e4SLinus Torvalds /* addresses present only in tunnel mode */ 18297e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) { 18302718aa7cSMiika Komu struct sockaddr *sa; 18312718aa7cSMiika Komu sa = (struct sockaddr *)(rq+1); 18322718aa7cSMiika Komu switch(sa->sa_family) { 18331da177e4SLinus Torvalds case AF_INET: 18342718aa7cSMiika Komu sin = (struct sockaddr_in*)sa; 18351da177e4SLinus Torvalds t->saddr.a4 = sin->sin_addr.s_addr; 18361da177e4SLinus Torvalds sin++; 18371da177e4SLinus Torvalds if (sin->sin_family != AF_INET) 18381da177e4SLinus Torvalds return -EINVAL; 18391da177e4SLinus Torvalds t->id.daddr.a4 = sin->sin_addr.s_addr; 18401da177e4SLinus Torvalds break; 18411da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 18421da177e4SLinus Torvalds case AF_INET6: 18432718aa7cSMiika Komu sin6 = (struct sockaddr_in6*)sa; 18441da177e4SLinus Torvalds memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); 18451da177e4SLinus Torvalds sin6++; 18461da177e4SLinus Torvalds if (sin6->sin6_family != AF_INET6) 18471da177e4SLinus Torvalds return -EINVAL; 18481da177e4SLinus Torvalds memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); 18491da177e4SLinus Torvalds break; 18501da177e4SLinus Torvalds #endif 18511da177e4SLinus Torvalds default: 18521da177e4SLinus Torvalds return -EINVAL; 18531da177e4SLinus Torvalds } 18542718aa7cSMiika Komu t->encap_family = sa->sa_family; 18552718aa7cSMiika Komu } else 18562718aa7cSMiika Komu t->encap_family = xp->family; 18572718aa7cSMiika Komu 18581da177e4SLinus Torvalds /* No way to set this via kame pfkey */ 18591da177e4SLinus Torvalds t->aalgos = t->ealgos = t->calgos = ~0; 18601da177e4SLinus Torvalds xp->xfrm_nr++; 18611da177e4SLinus Torvalds return 0; 18621da177e4SLinus Torvalds } 18631da177e4SLinus Torvalds 18641da177e4SLinus Torvalds static int 18651da177e4SLinus Torvalds parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) 18661da177e4SLinus Torvalds { 18671da177e4SLinus Torvalds int err; 18681da177e4SLinus Torvalds int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy); 18691da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq = (void*)(pol+1); 18701da177e4SLinus Torvalds 18711da177e4SLinus Torvalds while (len >= sizeof(struct sadb_x_ipsecrequest)) { 18721da177e4SLinus Torvalds if ((err = parse_ipsecrequest(xp, rq)) < 0) 18731da177e4SLinus Torvalds return err; 18741da177e4SLinus Torvalds len -= rq->sadb_x_ipsecrequest_len; 18751da177e4SLinus Torvalds rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len); 18761da177e4SLinus Torvalds } 18771da177e4SLinus Torvalds return 0; 18781da177e4SLinus Torvalds } 18791da177e4SLinus Torvalds 1880df71837dSTrent Jaeger static inline int pfkey_xfrm_policy2sec_ctx_size(struct xfrm_policy *xp) 1881df71837dSTrent Jaeger { 1882df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx = xp->security; 1883df71837dSTrent Jaeger 1884df71837dSTrent Jaeger if (xfrm_ctx) { 1885df71837dSTrent Jaeger int len = sizeof(struct sadb_x_sec_ctx); 1886df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 1887df71837dSTrent Jaeger return PFKEY_ALIGN8(len); 1888df71837dSTrent Jaeger } 1889df71837dSTrent Jaeger return 0; 1890df71837dSTrent Jaeger } 1891df71837dSTrent Jaeger 18921da177e4SLinus Torvalds static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) 18931da177e4SLinus Torvalds { 18942718aa7cSMiika Komu struct xfrm_tmpl *t; 18951da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 18962718aa7cSMiika Komu int socklen = 0; 18972718aa7cSMiika Komu int i; 18982718aa7cSMiika Komu 18992718aa7cSMiika Komu for (i=0; i<xp->xfrm_nr; i++) { 19002718aa7cSMiika Komu t = xp->xfrm_vec + i; 19012718aa7cSMiika Komu socklen += (t->encap_family == AF_INET ? 19021da177e4SLinus Torvalds sizeof(struct sockaddr_in) : 19031da177e4SLinus Torvalds sizeof(struct sockaddr_in6)); 19042718aa7cSMiika Komu } 19051da177e4SLinus Torvalds 19061da177e4SLinus Torvalds return sizeof(struct sadb_msg) + 19071da177e4SLinus Torvalds (sizeof(struct sadb_lifetime) * 3) + 19081da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 19091da177e4SLinus Torvalds (sockaddr_size * 2) + 19101da177e4SLinus Torvalds sizeof(struct sadb_x_policy) + 19112718aa7cSMiika Komu (xp->xfrm_nr * sizeof(struct sadb_x_ipsecrequest)) + 19122718aa7cSMiika Komu (socklen * 2) + 1913df71837dSTrent Jaeger pfkey_xfrm_policy2sec_ctx_size(xp); 19141da177e4SLinus Torvalds } 19151da177e4SLinus Torvalds 19161da177e4SLinus Torvalds static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp) 19171da177e4SLinus Torvalds { 19181da177e4SLinus Torvalds struct sk_buff *skb; 19191da177e4SLinus Torvalds int size; 19201da177e4SLinus Torvalds 19211da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19221da177e4SLinus Torvalds 19231da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 19241da177e4SLinus Torvalds if (skb == NULL) 19251da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 19261da177e4SLinus Torvalds 19271da177e4SLinus Torvalds return skb; 19281da177e4SLinus Torvalds } 19291da177e4SLinus Torvalds 193055569ce2SKazunori MIYAZAWA static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, int dir) 19311da177e4SLinus Torvalds { 19321da177e4SLinus Torvalds struct sadb_msg *hdr; 19331da177e4SLinus Torvalds struct sadb_address *addr; 19341da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 19351da177e4SLinus Torvalds struct sadb_x_policy *pol; 19361da177e4SLinus Torvalds struct sockaddr_in *sin; 1937df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 1938df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 19391da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19401da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 19411da177e4SLinus Torvalds #endif 19421da177e4SLinus Torvalds int i; 19431da177e4SLinus Torvalds int size; 19441da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 19451da177e4SLinus Torvalds int socklen = (xp->family == AF_INET ? 19461da177e4SLinus Torvalds sizeof(struct sockaddr_in) : 19471da177e4SLinus Torvalds sizeof(struct sockaddr_in6)); 19481da177e4SLinus Torvalds 19491da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19501da177e4SLinus Torvalds 19511da177e4SLinus Torvalds /* call should fill header later */ 19521da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 19531da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 19541da177e4SLinus Torvalds 19551da177e4SLinus Torvalds /* src address */ 19561da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 19571da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 19581da177e4SLinus Torvalds addr->sadb_address_len = 19591da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 19601da177e4SLinus Torvalds sizeof(uint64_t); 19611da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 19621da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 19631da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_s; 19641da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 19651da177e4SLinus Torvalds /* src address */ 19661da177e4SLinus Torvalds if (xp->family == AF_INET) { 19671da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 19681da177e4SLinus Torvalds sin->sin_family = AF_INET; 19691da177e4SLinus Torvalds sin->sin_addr.s_addr = xp->selector.saddr.a4; 19701da177e4SLinus Torvalds sin->sin_port = xp->selector.sport; 19711da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 19721da177e4SLinus Torvalds } 19731da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19741da177e4SLinus Torvalds else if (xp->family == AF_INET6) { 19751da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 19761da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 19771da177e4SLinus Torvalds sin6->sin6_port = xp->selector.sport; 19781da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 19791da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, xp->selector.saddr.a6, 19801da177e4SLinus Torvalds sizeof(struct in6_addr)); 19811da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 19821da177e4SLinus Torvalds } 19831da177e4SLinus Torvalds #endif 19841da177e4SLinus Torvalds else 19851da177e4SLinus Torvalds BUG(); 19861da177e4SLinus Torvalds 19871da177e4SLinus Torvalds /* dst address */ 19881da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 19891da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 19901da177e4SLinus Torvalds addr->sadb_address_len = 19911da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 19921da177e4SLinus Torvalds sizeof(uint64_t); 19931da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 19941da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 19951da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_d; 19961da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 19971da177e4SLinus Torvalds if (xp->family == AF_INET) { 19981da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 19991da177e4SLinus Torvalds sin->sin_family = AF_INET; 20001da177e4SLinus Torvalds sin->sin_addr.s_addr = xp->selector.daddr.a4; 20011da177e4SLinus Torvalds sin->sin_port = xp->selector.dport; 20021da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 20031da177e4SLinus Torvalds } 20041da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 20051da177e4SLinus Torvalds else if (xp->family == AF_INET6) { 20061da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 20071da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 20081da177e4SLinus Torvalds sin6->sin6_port = xp->selector.dport; 20091da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 20101da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, xp->selector.daddr.a6, 20111da177e4SLinus Torvalds sizeof(struct in6_addr)); 20121da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 20131da177e4SLinus Torvalds } 20141da177e4SLinus Torvalds #endif 20151da177e4SLinus Torvalds else 20161da177e4SLinus Torvalds BUG(); 20171da177e4SLinus Torvalds 20181da177e4SLinus Torvalds /* hard time */ 20191da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20201da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20211da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20221da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20231da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 20241da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.hard_packet_limit); 20251da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.hard_byte_limit); 20261da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds; 20271da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds; 20281da177e4SLinus Torvalds /* soft time */ 20291da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20301da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20311da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20321da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20331da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 20341da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.soft_packet_limit); 20351da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.soft_byte_limit); 20361da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds; 20371da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds; 20381da177e4SLinus Torvalds /* current time */ 20391da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20401da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20411da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20421da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20431da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 20441da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = xp->curlft.packets; 20451da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = xp->curlft.bytes; 20461da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->curlft.add_time; 20471da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->curlft.use_time; 20481da177e4SLinus Torvalds 20491da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 20501da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 20511da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 20521da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD; 20531da177e4SLinus Torvalds if (xp->action == XFRM_POLICY_ALLOW) { 20541da177e4SLinus Torvalds if (xp->xfrm_nr) 20551da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 20561da177e4SLinus Torvalds else 20571da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_NONE; 20581da177e4SLinus Torvalds } 20591da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 20601da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 20611da177e4SLinus Torvalds pol->sadb_x_policy_priority = xp->priority; 20621da177e4SLinus Torvalds 20631da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 20641da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq; 20651da177e4SLinus Torvalds struct xfrm_tmpl *t = xp->xfrm_vec + i; 20661da177e4SLinus Torvalds int req_size; 206755569ce2SKazunori MIYAZAWA int mode; 20681da177e4SLinus Torvalds 20691da177e4SLinus Torvalds req_size = sizeof(struct sadb_x_ipsecrequest); 20707e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) 20712718aa7cSMiika Komu req_size += ((t->encap_family == AF_INET ? 20722718aa7cSMiika Komu sizeof(struct sockaddr_in) : 20732718aa7cSMiika Komu sizeof(struct sockaddr_in6)) * 2); 20741da177e4SLinus Torvalds else 20751da177e4SLinus Torvalds size -= 2*socklen; 20761da177e4SLinus Torvalds rq = (void*)skb_put(skb, req_size); 20771da177e4SLinus Torvalds pol->sadb_x_policy_len += req_size/8; 20781da177e4SLinus Torvalds memset(rq, 0, sizeof(*rq)); 20791da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_len = req_size; 20801da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_proto = t->id.proto; 208155569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_from_xfrm(t->mode)) < 0) 208255569ce2SKazunori MIYAZAWA return -EINVAL; 2083fefaa75eSDavid S. Miller rq->sadb_x_ipsecrequest_mode = mode; 20841da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; 20851da177e4SLinus Torvalds if (t->reqid) 20861da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; 20871da177e4SLinus Torvalds if (t->optional) 20881da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; 20891da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_reqid = t->reqid; 20907e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) { 20912718aa7cSMiika Komu switch (t->encap_family) { 20921da177e4SLinus Torvalds case AF_INET: 20931da177e4SLinus Torvalds sin = (void*)(rq+1); 20941da177e4SLinus Torvalds sin->sin_family = AF_INET; 20951da177e4SLinus Torvalds sin->sin_addr.s_addr = t->saddr.a4; 20961da177e4SLinus Torvalds sin->sin_port = 0; 20971da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 20981da177e4SLinus Torvalds sin++; 20991da177e4SLinus Torvalds sin->sin_family = AF_INET; 21001da177e4SLinus Torvalds sin->sin_addr.s_addr = t->id.daddr.a4; 21011da177e4SLinus Torvalds sin->sin_port = 0; 21021da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 21031da177e4SLinus Torvalds break; 21041da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 21051da177e4SLinus Torvalds case AF_INET6: 21061da177e4SLinus Torvalds sin6 = (void*)(rq+1); 21071da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 21081da177e4SLinus Torvalds sin6->sin6_port = 0; 21091da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 21101da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, t->saddr.a6, 21111da177e4SLinus Torvalds sizeof(struct in6_addr)); 21121da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 21131da177e4SLinus Torvalds 21141da177e4SLinus Torvalds sin6++; 21151da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 21161da177e4SLinus Torvalds sin6->sin6_port = 0; 21171da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 21181da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, t->id.daddr.a6, 21191da177e4SLinus Torvalds sizeof(struct in6_addr)); 21201da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 21211da177e4SLinus Torvalds break; 21221da177e4SLinus Torvalds #endif 21231da177e4SLinus Torvalds default: 21241da177e4SLinus Torvalds break; 21251da177e4SLinus Torvalds } 21261da177e4SLinus Torvalds } 21271da177e4SLinus Torvalds } 2128df71837dSTrent Jaeger 2129df71837dSTrent Jaeger /* security context */ 2130df71837dSTrent Jaeger if ((xfrm_ctx = xp->security)) { 2131df71837dSTrent Jaeger int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp); 2132df71837dSTrent Jaeger 2133df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size); 2134df71837dSTrent Jaeger sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t); 2135df71837dSTrent Jaeger sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 2136df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 2137df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 2138df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 2139df71837dSTrent Jaeger memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 2140df71837dSTrent Jaeger xfrm_ctx->ctx_len); 2141df71837dSTrent Jaeger } 2142df71837dSTrent Jaeger 21431da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 21441da177e4SLinus Torvalds hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); 214555569ce2SKazunori MIYAZAWA 214655569ce2SKazunori MIYAZAWA return 0; 21471da177e4SLinus Torvalds } 21481da177e4SLinus Torvalds 214926b15dadSJamal Hadi Salim static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) 215026b15dadSJamal Hadi Salim { 215126b15dadSJamal Hadi Salim struct sk_buff *out_skb; 215226b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 215326b15dadSJamal Hadi Salim int err; 215426b15dadSJamal Hadi Salim 215526b15dadSJamal Hadi Salim out_skb = pfkey_xfrm_policy2msg_prep(xp); 215626b15dadSJamal Hadi Salim if (IS_ERR(out_skb)) { 215726b15dadSJamal Hadi Salim err = PTR_ERR(out_skb); 215826b15dadSJamal Hadi Salim goto out; 215926b15dadSJamal Hadi Salim } 216055569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 216155569ce2SKazunori MIYAZAWA if (err < 0) 216255569ce2SKazunori MIYAZAWA return err; 216326b15dadSJamal Hadi Salim 216426b15dadSJamal Hadi Salim out_hdr = (struct sadb_msg *) out_skb->data; 216526b15dadSJamal Hadi Salim out_hdr->sadb_msg_version = PF_KEY_V2; 216626b15dadSJamal Hadi Salim 2167f60f6b8fSHerbert Xu if (c->data.byid && c->event == XFRM_MSG_DELPOLICY) 216826b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; 216926b15dadSJamal Hadi Salim else 217026b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = event2poltype(c->event); 217126b15dadSJamal Hadi Salim out_hdr->sadb_msg_errno = 0; 217226b15dadSJamal Hadi Salim out_hdr->sadb_msg_seq = c->seq; 217326b15dadSJamal Hadi Salim out_hdr->sadb_msg_pid = c->pid; 217426b15dadSJamal Hadi Salim pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 217526b15dadSJamal Hadi Salim out: 217626b15dadSJamal Hadi Salim return 0; 217726b15dadSJamal Hadi Salim 217826b15dadSJamal Hadi Salim } 217926b15dadSJamal Hadi Salim 21801da177e4SLinus Torvalds static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 21811da177e4SLinus Torvalds { 2182df71837dSTrent Jaeger int err = 0; 21831da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 21841da177e4SLinus Torvalds struct sadb_address *sa; 21851da177e4SLinus Torvalds struct sadb_x_policy *pol; 21861da177e4SLinus Torvalds struct xfrm_policy *xp; 218726b15dadSJamal Hadi Salim struct km_event c; 2188df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 21891da177e4SLinus Torvalds 21901da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 21911da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 21921da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 21931da177e4SLinus Torvalds return -EINVAL; 21941da177e4SLinus Torvalds 21951da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 21961da177e4SLinus Torvalds if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC) 21971da177e4SLinus Torvalds return -EINVAL; 21981da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 21991da177e4SLinus Torvalds return -EINVAL; 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_KERNEL); 22021da177e4SLinus Torvalds if (xp == NULL) 22031da177e4SLinus Torvalds return -ENOBUFS; 22041da177e4SLinus Torvalds 22051da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 22061da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 22071da177e4SLinus Torvalds xp->priority = pol->sadb_x_policy_priority; 22081da177e4SLinus Torvalds 22091da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 22101da177e4SLinus Torvalds xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr); 22111da177e4SLinus Torvalds if (!xp->family) { 22121da177e4SLinus Torvalds err = -EINVAL; 22131da177e4SLinus Torvalds goto out; 22141da177e4SLinus Torvalds } 22151da177e4SLinus Torvalds xp->selector.family = xp->family; 22161da177e4SLinus Torvalds xp->selector.prefixlen_s = sa->sadb_address_prefixlen; 22171da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22181da177e4SLinus Torvalds xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 22191da177e4SLinus Torvalds if (xp->selector.sport) 22208f83f23eSAl Viro xp->selector.sport_mask = htons(0xffff); 22211da177e4SLinus Torvalds 22221da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 22231da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); 22241da177e4SLinus Torvalds xp->selector.prefixlen_d = sa->sadb_address_prefixlen; 22251da177e4SLinus Torvalds 22261da177e4SLinus Torvalds /* Amusing, we set this twice. KAME apps appear to set same value 22271da177e4SLinus Torvalds * in both addresses. 22281da177e4SLinus Torvalds */ 22291da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22301da177e4SLinus Torvalds 22311da177e4SLinus Torvalds xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 22321da177e4SLinus Torvalds if (xp->selector.dport) 22338f83f23eSAl Viro xp->selector.dport_mask = htons(0xffff); 22341da177e4SLinus Torvalds 2235df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2236df71837dSTrent Jaeger if (sec_ctx != NULL) { 2237df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2238df71837dSTrent Jaeger 2239df71837dSTrent Jaeger if (!uctx) { 2240df71837dSTrent Jaeger err = -ENOBUFS; 2241df71837dSTrent Jaeger goto out; 2242df71837dSTrent Jaeger } 2243df71837dSTrent Jaeger 2244df71837dSTrent Jaeger err = security_xfrm_policy_alloc(xp, uctx); 2245df71837dSTrent Jaeger kfree(uctx); 2246df71837dSTrent Jaeger 2247df71837dSTrent Jaeger if (err) 2248df71837dSTrent Jaeger goto out; 2249df71837dSTrent Jaeger } 2250df71837dSTrent Jaeger 22511da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 22521da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 22531da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 22541da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 22551da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) { 22561da177e4SLinus Torvalds xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22571da177e4SLinus Torvalds xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22581da177e4SLinus Torvalds xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22591da177e4SLinus Torvalds xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22601da177e4SLinus Torvalds } 22611da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) { 22621da177e4SLinus Torvalds xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22631da177e4SLinus Torvalds xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22641da177e4SLinus Torvalds xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22651da177e4SLinus Torvalds xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22661da177e4SLinus Torvalds } 22671da177e4SLinus Torvalds xp->xfrm_nr = 0; 22681da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 22691da177e4SLinus Torvalds (err = parse_ipsecrequests(xp, pol)) < 0) 22701da177e4SLinus Torvalds goto out; 22711da177e4SLinus Torvalds 22721da177e4SLinus Torvalds err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, 22731da177e4SLinus Torvalds hdr->sadb_msg_type != SADB_X_SPDUPDATE); 2274df71837dSTrent Jaeger 2275ab5f5e8bSJoy Latten xfrm_audit_policy_add(xp, err ? 0 : 1, 2276*0c11b942SAl Viro audit_get_loginuid(current), 0); 2277161a09e7SJoy Latten 2278df71837dSTrent Jaeger if (err) 2279df71837dSTrent Jaeger goto out; 22801da177e4SLinus Torvalds 228126b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) 2282f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDPOLICY; 228326b15dadSJamal Hadi Salim else 2284f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWPOLICY; 22851da177e4SLinus Torvalds 228626b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 228726b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 228826b15dadSJamal Hadi Salim 228926b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 22901da177e4SLinus Torvalds xfrm_pol_put(xp); 22911da177e4SLinus Torvalds return 0; 22921da177e4SLinus Torvalds 22931da177e4SLinus Torvalds out: 229464c31b3fSWANG Cong xfrm_policy_destroy(xp); 22951da177e4SLinus Torvalds return err; 22961da177e4SLinus Torvalds } 22971da177e4SLinus Torvalds 22981da177e4SLinus Torvalds static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 22991da177e4SLinus Torvalds { 23001da177e4SLinus Torvalds int err; 23011da177e4SLinus Torvalds struct sadb_address *sa; 23021da177e4SLinus Torvalds struct sadb_x_policy *pol; 2303df71837dSTrent Jaeger struct xfrm_policy *xp, tmp; 23041da177e4SLinus Torvalds struct xfrm_selector sel; 230526b15dadSJamal Hadi Salim struct km_event c; 2306df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 23071da177e4SLinus Torvalds 23081da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23091da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 23101da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 23111da177e4SLinus Torvalds return -EINVAL; 23121da177e4SLinus Torvalds 23131da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 23141da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 23151da177e4SLinus Torvalds return -EINVAL; 23161da177e4SLinus Torvalds 23171da177e4SLinus Torvalds memset(&sel, 0, sizeof(sel)); 23181da177e4SLinus Torvalds 23191da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23201da177e4SLinus Torvalds sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 23211da177e4SLinus Torvalds sel.prefixlen_s = sa->sadb_address_prefixlen; 23221da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23231da177e4SLinus Torvalds sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 23241da177e4SLinus Torvalds if (sel.sport) 23258f83f23eSAl Viro sel.sport_mask = htons(0xffff); 23261da177e4SLinus Torvalds 23271da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 23281da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 23291da177e4SLinus Torvalds sel.prefixlen_d = sa->sadb_address_prefixlen; 23301da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23311da177e4SLinus Torvalds sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 23321da177e4SLinus Torvalds if (sel.dport) 23338f83f23eSAl Viro sel.dport_mask = htons(0xffff); 23341da177e4SLinus Torvalds 2335df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2336df71837dSTrent Jaeger memset(&tmp, 0, sizeof(struct xfrm_policy)); 2337df71837dSTrent Jaeger 2338df71837dSTrent Jaeger if (sec_ctx != NULL) { 2339df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2340df71837dSTrent Jaeger 2341df71837dSTrent Jaeger if (!uctx) 2342df71837dSTrent Jaeger return -ENOMEM; 2343df71837dSTrent Jaeger 2344df71837dSTrent Jaeger err = security_xfrm_policy_alloc(&tmp, uctx); 2345df71837dSTrent Jaeger kfree(uctx); 2346df71837dSTrent Jaeger 2347df71837dSTrent Jaeger if (err) 2348df71837dSTrent Jaeger return err; 2349df71837dSTrent Jaeger } 2350df71837dSTrent Jaeger 2351f7b6983fSMasahide NAKAMURA xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, 2352ef41aaa0SEric Paris &sel, tmp.security, 1, &err); 2353df71837dSTrent Jaeger security_xfrm_policy_free(&tmp); 2354161a09e7SJoy Latten 23551da177e4SLinus Torvalds if (xp == NULL) 23561da177e4SLinus Torvalds return -ENOENT; 23571da177e4SLinus Torvalds 2358ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, err ? 0 : 1, 2359*0c11b942SAl Viro audit_get_loginuid(current), 0); 236013fcfbb0SDavid S. Miller 236113fcfbb0SDavid S. Miller if (err) 2362c8c05a8eSCatherine Zhang goto out; 236313fcfbb0SDavid S. Miller 236426b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 236526b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 2366f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 236726b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 236826b15dadSJamal Hadi Salim 2369c8c05a8eSCatherine Zhang out: 237026b15dadSJamal Hadi Salim xfrm_pol_put(xp); 237126b15dadSJamal Hadi Salim return err; 237226b15dadSJamal Hadi Salim } 237326b15dadSJamal Hadi Salim 237426b15dadSJamal Hadi Salim static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir) 237526b15dadSJamal Hadi Salim { 237626b15dadSJamal Hadi Salim int err; 237726b15dadSJamal Hadi Salim struct sk_buff *out_skb; 237826b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 237926b15dadSJamal Hadi Salim err = 0; 238026b15dadSJamal Hadi Salim 23811da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 23821da177e4SLinus Torvalds if (IS_ERR(out_skb)) { 23831da177e4SLinus Torvalds err = PTR_ERR(out_skb); 23841da177e4SLinus Torvalds goto out; 23851da177e4SLinus Torvalds } 238655569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 238755569ce2SKazunori MIYAZAWA if (err < 0) 238855569ce2SKazunori MIYAZAWA goto out; 23891da177e4SLinus Torvalds 23901da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 23911da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 239226b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = hdr->sadb_msg_type; 23931da177e4SLinus Torvalds out_hdr->sadb_msg_satype = 0; 23941da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 23951da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 23961da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 239726b15dadSJamal Hadi Salim pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); 23981da177e4SLinus Torvalds err = 0; 23991da177e4SLinus Torvalds 24001da177e4SLinus Torvalds out: 24011da177e4SLinus Torvalds return err; 24021da177e4SLinus Torvalds } 24031da177e4SLinus Torvalds 240408de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 240508de61beSShinta Sugimoto static int pfkey_sockaddr_pair_size(sa_family_t family) 240608de61beSShinta Sugimoto { 240708de61beSShinta Sugimoto switch (family) { 240808de61beSShinta Sugimoto case AF_INET: 240908de61beSShinta Sugimoto return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2); 241008de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 241108de61beSShinta Sugimoto case AF_INET6: 241208de61beSShinta Sugimoto return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2); 241308de61beSShinta Sugimoto #endif 241408de61beSShinta Sugimoto default: 241508de61beSShinta Sugimoto return 0; 241608de61beSShinta Sugimoto } 241708de61beSShinta Sugimoto /* NOTREACHED */ 241808de61beSShinta Sugimoto } 241908de61beSShinta Sugimoto 242008de61beSShinta Sugimoto static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, 242108de61beSShinta Sugimoto xfrm_address_t *saddr, xfrm_address_t *daddr, 242208de61beSShinta Sugimoto u16 *family) 242308de61beSShinta Sugimoto { 242408de61beSShinta Sugimoto struct sockaddr *sa = (struct sockaddr *)(rq + 1); 242508de61beSShinta Sugimoto if (rq->sadb_x_ipsecrequest_len < 242608de61beSShinta Sugimoto pfkey_sockaddr_pair_size(sa->sa_family)) 242708de61beSShinta Sugimoto return -EINVAL; 242808de61beSShinta Sugimoto 242908de61beSShinta Sugimoto switch (sa->sa_family) { 243008de61beSShinta Sugimoto case AF_INET: 243108de61beSShinta Sugimoto { 243208de61beSShinta Sugimoto struct sockaddr_in *sin; 243308de61beSShinta Sugimoto sin = (struct sockaddr_in *)sa; 243408de61beSShinta Sugimoto if ((sin+1)->sin_family != AF_INET) 243508de61beSShinta Sugimoto return -EINVAL; 243608de61beSShinta Sugimoto memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4)); 243708de61beSShinta Sugimoto sin++; 243808de61beSShinta Sugimoto memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4)); 243908de61beSShinta Sugimoto *family = AF_INET; 244008de61beSShinta Sugimoto break; 244108de61beSShinta Sugimoto } 244208de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 244308de61beSShinta Sugimoto case AF_INET6: 244408de61beSShinta Sugimoto { 244508de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 244608de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)sa; 244708de61beSShinta Sugimoto if ((sin6+1)->sin6_family != AF_INET6) 244808de61beSShinta Sugimoto return -EINVAL; 244908de61beSShinta Sugimoto memcpy(&saddr->a6, &sin6->sin6_addr, 245008de61beSShinta Sugimoto sizeof(saddr->a6)); 245108de61beSShinta Sugimoto sin6++; 245208de61beSShinta Sugimoto memcpy(&daddr->a6, &sin6->sin6_addr, 245308de61beSShinta Sugimoto sizeof(daddr->a6)); 245408de61beSShinta Sugimoto *family = AF_INET6; 245508de61beSShinta Sugimoto break; 245608de61beSShinta Sugimoto } 245708de61beSShinta Sugimoto #endif 245808de61beSShinta Sugimoto default: 245908de61beSShinta Sugimoto return -EINVAL; 246008de61beSShinta Sugimoto } 246108de61beSShinta Sugimoto 246208de61beSShinta Sugimoto return 0; 246308de61beSShinta Sugimoto } 246408de61beSShinta Sugimoto 246508de61beSShinta Sugimoto static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, 246608de61beSShinta Sugimoto struct xfrm_migrate *m) 246708de61beSShinta Sugimoto { 246808de61beSShinta Sugimoto int err; 246908de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq2; 247055569ce2SKazunori MIYAZAWA int mode; 247108de61beSShinta Sugimoto 247208de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 247308de61beSShinta Sugimoto len < rq1->sadb_x_ipsecrequest_len) 247408de61beSShinta Sugimoto return -EINVAL; 247508de61beSShinta Sugimoto 247608de61beSShinta Sugimoto /* old endoints */ 247708de61beSShinta Sugimoto err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, 247808de61beSShinta Sugimoto &m->old_family); 247908de61beSShinta Sugimoto if (err) 248008de61beSShinta Sugimoto return err; 248108de61beSShinta Sugimoto 248208de61beSShinta Sugimoto rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); 248308de61beSShinta Sugimoto len -= rq1->sadb_x_ipsecrequest_len; 248408de61beSShinta Sugimoto 248508de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 248608de61beSShinta Sugimoto len < rq2->sadb_x_ipsecrequest_len) 248708de61beSShinta Sugimoto return -EINVAL; 248808de61beSShinta Sugimoto 248908de61beSShinta Sugimoto /* new endpoints */ 249008de61beSShinta Sugimoto err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, 249108de61beSShinta Sugimoto &m->new_family); 249208de61beSShinta Sugimoto if (err) 249308de61beSShinta Sugimoto return err; 249408de61beSShinta Sugimoto 249508de61beSShinta Sugimoto if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto || 249608de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode || 249708de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid) 249808de61beSShinta Sugimoto return -EINVAL; 249908de61beSShinta Sugimoto 250008de61beSShinta Sugimoto m->proto = rq1->sadb_x_ipsecrequest_proto; 250155569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq1->sadb_x_ipsecrequest_mode)) < 0) 250255569ce2SKazunori MIYAZAWA return -EINVAL; 250355569ce2SKazunori MIYAZAWA m->mode = mode; 250408de61beSShinta Sugimoto m->reqid = rq1->sadb_x_ipsecrequest_reqid; 250508de61beSShinta Sugimoto 250608de61beSShinta Sugimoto return ((int)(rq1->sadb_x_ipsecrequest_len + 250708de61beSShinta Sugimoto rq2->sadb_x_ipsecrequest_len)); 250808de61beSShinta Sugimoto } 250908de61beSShinta Sugimoto 251008de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 251108de61beSShinta Sugimoto struct sadb_msg *hdr, void **ext_hdrs) 251208de61beSShinta Sugimoto { 251308de61beSShinta Sugimoto int i, len, ret, err = -EINVAL; 251408de61beSShinta Sugimoto u8 dir; 251508de61beSShinta Sugimoto struct sadb_address *sa; 251608de61beSShinta Sugimoto struct sadb_x_policy *pol; 251708de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 251808de61beSShinta Sugimoto struct xfrm_selector sel; 251908de61beSShinta Sugimoto struct xfrm_migrate m[XFRM_MAX_DEPTH]; 252008de61beSShinta Sugimoto 252108de61beSShinta Sugimoto if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], 252208de61beSShinta Sugimoto ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || 252308de61beSShinta Sugimoto !ext_hdrs[SADB_X_EXT_POLICY - 1]) { 252408de61beSShinta Sugimoto err = -EINVAL; 252508de61beSShinta Sugimoto goto out; 252608de61beSShinta Sugimoto } 252708de61beSShinta Sugimoto 252808de61beSShinta Sugimoto pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; 252908de61beSShinta Sugimoto if (!pol) { 253008de61beSShinta Sugimoto err = -EINVAL; 253108de61beSShinta Sugimoto goto out; 253208de61beSShinta Sugimoto } 253308de61beSShinta Sugimoto 253408de61beSShinta Sugimoto if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { 253508de61beSShinta Sugimoto err = -EINVAL; 253608de61beSShinta Sugimoto goto out; 253708de61beSShinta Sugimoto } 253808de61beSShinta Sugimoto 253908de61beSShinta Sugimoto dir = pol->sadb_x_policy_dir - 1; 254008de61beSShinta Sugimoto memset(&sel, 0, sizeof(sel)); 254108de61beSShinta Sugimoto 254208de61beSShinta Sugimoto /* set source address info of selector */ 254308de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1]; 254408de61beSShinta Sugimoto sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 254508de61beSShinta Sugimoto sel.prefixlen_s = sa->sadb_address_prefixlen; 254608de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 254708de61beSShinta Sugimoto sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port; 254808de61beSShinta Sugimoto if (sel.sport) 2549582ee43dSAl Viro sel.sport_mask = htons(0xffff); 255008de61beSShinta Sugimoto 255108de61beSShinta Sugimoto /* set destination address info of selector */ 255208de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1], 255308de61beSShinta Sugimoto pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 255408de61beSShinta Sugimoto sel.prefixlen_d = sa->sadb_address_prefixlen; 255508de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 255608de61beSShinta Sugimoto sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port; 255708de61beSShinta Sugimoto if (sel.dport) 2558582ee43dSAl Viro sel.dport_mask = htons(0xffff); 255908de61beSShinta Sugimoto 256008de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)(pol + 1); 256108de61beSShinta Sugimoto 256208de61beSShinta Sugimoto /* extract ipsecrequests */ 256308de61beSShinta Sugimoto i = 0; 256408de61beSShinta Sugimoto len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy); 256508de61beSShinta Sugimoto 256608de61beSShinta Sugimoto while (len > 0 && i < XFRM_MAX_DEPTH) { 256708de61beSShinta Sugimoto ret = ipsecrequests_to_migrate(rq, len, &m[i]); 256808de61beSShinta Sugimoto if (ret < 0) { 256908de61beSShinta Sugimoto err = ret; 257008de61beSShinta Sugimoto goto out; 257108de61beSShinta Sugimoto } else { 257208de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret); 257308de61beSShinta Sugimoto len -= ret; 257408de61beSShinta Sugimoto i++; 257508de61beSShinta Sugimoto } 257608de61beSShinta Sugimoto } 257708de61beSShinta Sugimoto 257808de61beSShinta Sugimoto if (!i || len > 0) { 257908de61beSShinta Sugimoto err = -EINVAL; 258008de61beSShinta Sugimoto goto out; 258108de61beSShinta Sugimoto } 258208de61beSShinta Sugimoto 258308de61beSShinta Sugimoto return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); 258408de61beSShinta Sugimoto 258508de61beSShinta Sugimoto out: 258608de61beSShinta Sugimoto return err; 258708de61beSShinta Sugimoto } 258808de61beSShinta Sugimoto #else 258908de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 259008de61beSShinta Sugimoto struct sadb_msg *hdr, void **ext_hdrs) 259108de61beSShinta Sugimoto { 259208de61beSShinta Sugimoto return -ENOPROTOOPT; 259308de61beSShinta Sugimoto } 259408de61beSShinta Sugimoto #endif 259508de61beSShinta Sugimoto 259608de61beSShinta Sugimoto 25971da177e4SLinus Torvalds static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 25981da177e4SLinus Torvalds { 259977d8d7a6SHerbert Xu unsigned int dir; 2600215a2dd3SEric Paris int err = 0, delete; 26011da177e4SLinus Torvalds struct sadb_x_policy *pol; 26021da177e4SLinus Torvalds struct xfrm_policy *xp; 260326b15dadSJamal Hadi Salim struct km_event c; 26041da177e4SLinus Torvalds 26051da177e4SLinus Torvalds if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) 26061da177e4SLinus Torvalds return -EINVAL; 26071da177e4SLinus Torvalds 260877d8d7a6SHerbert Xu dir = xfrm_policy_id2dir(pol->sadb_x_policy_id); 260977d8d7a6SHerbert Xu if (dir >= XFRM_POLICY_MAX) 261077d8d7a6SHerbert Xu return -EINVAL; 261177d8d7a6SHerbert Xu 2612215a2dd3SEric Paris delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); 2613f7b6983fSMasahide NAKAMURA xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id, 2614215a2dd3SEric Paris delete, &err); 26151da177e4SLinus Torvalds if (xp == NULL) 26161da177e4SLinus Torvalds return -ENOENT; 26171da177e4SLinus Torvalds 2618215a2dd3SEric Paris if (delete) { 2619ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, err ? 0 : 1, 2620*0c11b942SAl Viro audit_get_loginuid(current), 0); 26211da177e4SLinus Torvalds 2622215a2dd3SEric Paris if (err) 2623215a2dd3SEric Paris goto out; 262426b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 262526b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 2626bf08867fSHerbert Xu c.data.byid = 1; 2627f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 262877d8d7a6SHerbert Xu km_policy_notify(xp, dir, &c); 262926b15dadSJamal Hadi Salim } else { 263077d8d7a6SHerbert Xu err = key_pol_get_resp(sk, xp, hdr, dir); 26311da177e4SLinus Torvalds } 26321da177e4SLinus Torvalds 2633215a2dd3SEric Paris out: 26341da177e4SLinus Torvalds xfrm_pol_put(xp); 26351da177e4SLinus Torvalds return err; 26361da177e4SLinus Torvalds } 26371da177e4SLinus Torvalds 26381da177e4SLinus Torvalds static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) 26391da177e4SLinus Torvalds { 26401da177e4SLinus Torvalds struct pfkey_dump_data *data = ptr; 26411da177e4SLinus Torvalds struct sk_buff *out_skb; 26421da177e4SLinus Torvalds struct sadb_msg *out_hdr; 264355569ce2SKazunori MIYAZAWA int err; 26441da177e4SLinus Torvalds 26451da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 26461da177e4SLinus Torvalds if (IS_ERR(out_skb)) 26471da177e4SLinus Torvalds return PTR_ERR(out_skb); 26481da177e4SLinus Torvalds 264955569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 265055569ce2SKazunori MIYAZAWA if (err < 0) 265155569ce2SKazunori MIYAZAWA return err; 26521da177e4SLinus Torvalds 26531da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 26541da177e4SLinus Torvalds out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; 26551da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_X_SPDDUMP; 26561da177e4SLinus Torvalds out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; 26571da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 26581da177e4SLinus Torvalds out_hdr->sadb_msg_seq = count; 26591da177e4SLinus Torvalds out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; 26601da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); 26611da177e4SLinus Torvalds return 0; 26621da177e4SLinus Torvalds } 26631da177e4SLinus Torvalds 26641da177e4SLinus Torvalds static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 26651da177e4SLinus Torvalds { 26661da177e4SLinus Torvalds struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 26671da177e4SLinus Torvalds 2668f7b6983fSMasahide NAKAMURA return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); 26691da177e4SLinus Torvalds } 26701da177e4SLinus Torvalds 267126b15dadSJamal Hadi Salim static int key_notify_policy_flush(struct km_event *c) 26721da177e4SLinus Torvalds { 26731da177e4SLinus Torvalds struct sk_buff *skb_out; 267426b15dadSJamal Hadi Salim struct sadb_msg *hdr; 26751da177e4SLinus Torvalds 267626b15dadSJamal Hadi Salim skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 26771da177e4SLinus Torvalds if (!skb_out) 26781da177e4SLinus Torvalds return -ENOBUFS; 267926b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); 2680151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_X_SPDFLUSH; 268126b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 268226b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 268326b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 268426b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 268526b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 268626b15dadSJamal Hadi Salim pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL); 268726b15dadSJamal Hadi Salim return 0; 268826b15dadSJamal Hadi Salim 268926b15dadSJamal Hadi Salim } 269026b15dadSJamal Hadi Salim 269126b15dadSJamal Hadi Salim static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 269226b15dadSJamal Hadi Salim { 269326b15dadSJamal Hadi Salim struct km_event c; 2694161a09e7SJoy Latten struct xfrm_audit audit_info; 26954aa2e62cSJoy Latten int err; 26961da177e4SLinus Torvalds 2697*0c11b942SAl Viro audit_info.loginuid = audit_get_loginuid(current); 2698161a09e7SJoy Latten audit_info.secid = 0; 26994aa2e62cSJoy Latten err = xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); 27004aa2e62cSJoy Latten if (err) 27014aa2e62cSJoy Latten return err; 2702f7b6983fSMasahide NAKAMURA c.data.type = XFRM_POLICY_TYPE_MAIN; 2703f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHPOLICY; 270426b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 270526b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 270626b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 27071da177e4SLinus Torvalds 27081da177e4SLinus Torvalds return 0; 27091da177e4SLinus Torvalds } 27101da177e4SLinus Torvalds 27111da177e4SLinus Torvalds typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb, 27121da177e4SLinus Torvalds struct sadb_msg *hdr, void **ext_hdrs); 27131da177e4SLinus Torvalds static pfkey_handler pfkey_funcs[SADB_MAX + 1] = { 27141da177e4SLinus Torvalds [SADB_RESERVED] = pfkey_reserved, 27151da177e4SLinus Torvalds [SADB_GETSPI] = pfkey_getspi, 27161da177e4SLinus Torvalds [SADB_UPDATE] = pfkey_add, 27171da177e4SLinus Torvalds [SADB_ADD] = pfkey_add, 27181da177e4SLinus Torvalds [SADB_DELETE] = pfkey_delete, 27191da177e4SLinus Torvalds [SADB_GET] = pfkey_get, 27201da177e4SLinus Torvalds [SADB_ACQUIRE] = pfkey_acquire, 27211da177e4SLinus Torvalds [SADB_REGISTER] = pfkey_register, 27221da177e4SLinus Torvalds [SADB_EXPIRE] = NULL, 27231da177e4SLinus Torvalds [SADB_FLUSH] = pfkey_flush, 27241da177e4SLinus Torvalds [SADB_DUMP] = pfkey_dump, 27251da177e4SLinus Torvalds [SADB_X_PROMISC] = pfkey_promisc, 27261da177e4SLinus Torvalds [SADB_X_PCHANGE] = NULL, 27271da177e4SLinus Torvalds [SADB_X_SPDUPDATE] = pfkey_spdadd, 27281da177e4SLinus Torvalds [SADB_X_SPDADD] = pfkey_spdadd, 27291da177e4SLinus Torvalds [SADB_X_SPDDELETE] = pfkey_spddelete, 27301da177e4SLinus Torvalds [SADB_X_SPDGET] = pfkey_spdget, 27311da177e4SLinus Torvalds [SADB_X_SPDACQUIRE] = NULL, 27321da177e4SLinus Torvalds [SADB_X_SPDDUMP] = pfkey_spddump, 27331da177e4SLinus Torvalds [SADB_X_SPDFLUSH] = pfkey_spdflush, 27341da177e4SLinus Torvalds [SADB_X_SPDSETIDX] = pfkey_spdadd, 27351da177e4SLinus Torvalds [SADB_X_SPDDELETE2] = pfkey_spdget, 273608de61beSShinta Sugimoto [SADB_X_MIGRATE] = pfkey_migrate, 27371da177e4SLinus Torvalds }; 27381da177e4SLinus Torvalds 27391da177e4SLinus Torvalds static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) 27401da177e4SLinus Torvalds { 27411da177e4SLinus Torvalds void *ext_hdrs[SADB_EXT_MAX]; 27421da177e4SLinus Torvalds int err; 27431da177e4SLinus Torvalds 27441da177e4SLinus Torvalds pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, 27451da177e4SLinus Torvalds BROADCAST_PROMISC_ONLY, NULL); 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds memset(ext_hdrs, 0, sizeof(ext_hdrs)); 27481da177e4SLinus Torvalds err = parse_exthdrs(skb, hdr, ext_hdrs); 27491da177e4SLinus Torvalds if (!err) { 27501da177e4SLinus Torvalds err = -EOPNOTSUPP; 27511da177e4SLinus Torvalds if (pfkey_funcs[hdr->sadb_msg_type]) 27521da177e4SLinus Torvalds err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs); 27531da177e4SLinus Torvalds } 27541da177e4SLinus Torvalds return err; 27551da177e4SLinus Torvalds } 27561da177e4SLinus Torvalds 27571da177e4SLinus Torvalds static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp) 27581da177e4SLinus Torvalds { 27591da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 27601da177e4SLinus Torvalds 27611da177e4SLinus Torvalds if (skb->len < sizeof(*hdr)) { 27621da177e4SLinus Torvalds *errp = -EMSGSIZE; 27631da177e4SLinus Torvalds } else { 27641da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb->data; 27651da177e4SLinus Torvalds if (hdr->sadb_msg_version != PF_KEY_V2 || 27661da177e4SLinus Torvalds hdr->sadb_msg_reserved != 0 || 27671da177e4SLinus Torvalds (hdr->sadb_msg_type <= SADB_RESERVED || 27681da177e4SLinus Torvalds hdr->sadb_msg_type > SADB_MAX)) { 27691da177e4SLinus Torvalds hdr = NULL; 27701da177e4SLinus Torvalds *errp = -EINVAL; 27711da177e4SLinus Torvalds } else if (hdr->sadb_msg_len != (skb->len / 27721da177e4SLinus Torvalds sizeof(uint64_t)) || 27731da177e4SLinus Torvalds hdr->sadb_msg_len < (sizeof(struct sadb_msg) / 27741da177e4SLinus Torvalds sizeof(uint64_t))) { 27751da177e4SLinus Torvalds hdr = NULL; 27761da177e4SLinus Torvalds *errp = -EMSGSIZE; 27771da177e4SLinus Torvalds } else { 27781da177e4SLinus Torvalds *errp = 0; 27791da177e4SLinus Torvalds } 27801da177e4SLinus Torvalds } 27811da177e4SLinus Torvalds return hdr; 27821da177e4SLinus Torvalds } 27831da177e4SLinus Torvalds 27841da177e4SLinus Torvalds static inline int aalg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) 27851da177e4SLinus Torvalds { 2786f398035fSHerbert Xu unsigned int id = d->desc.sadb_alg_id; 2787f398035fSHerbert Xu 2788f398035fSHerbert Xu if (id >= sizeof(t->aalgos) * 8) 2789f398035fSHerbert Xu return 0; 2790f398035fSHerbert Xu 2791f398035fSHerbert Xu return (t->aalgos >> id) & 1; 27921da177e4SLinus Torvalds } 27931da177e4SLinus Torvalds 27941da177e4SLinus Torvalds static inline int ealg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) 27951da177e4SLinus Torvalds { 2796f398035fSHerbert Xu unsigned int id = d->desc.sadb_alg_id; 2797f398035fSHerbert Xu 2798f398035fSHerbert Xu if (id >= sizeof(t->ealgos) * 8) 2799f398035fSHerbert Xu return 0; 2800f398035fSHerbert Xu 2801f398035fSHerbert Xu return (t->ealgos >> id) & 1; 28021da177e4SLinus Torvalds } 28031da177e4SLinus Torvalds 28041da177e4SLinus Torvalds static int count_ah_combs(struct xfrm_tmpl *t) 28051da177e4SLinus Torvalds { 28061da177e4SLinus Torvalds int i, sz = 0; 28071da177e4SLinus Torvalds 28081da177e4SLinus Torvalds for (i = 0; ; i++) { 28091da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 28101da177e4SLinus Torvalds if (!aalg) 28111da177e4SLinus Torvalds break; 28121da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 28131da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 28141da177e4SLinus Torvalds } 28151da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 28161da177e4SLinus Torvalds } 28171da177e4SLinus Torvalds 28181da177e4SLinus Torvalds static int count_esp_combs(struct xfrm_tmpl *t) 28191da177e4SLinus Torvalds { 28201da177e4SLinus Torvalds int i, k, sz = 0; 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds for (i = 0; ; i++) { 28231da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 28241da177e4SLinus Torvalds if (!ealg) 28251da177e4SLinus Torvalds break; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 28281da177e4SLinus Torvalds continue; 28291da177e4SLinus Torvalds 28301da177e4SLinus Torvalds for (k = 1; ; k++) { 28311da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 28321da177e4SLinus Torvalds if (!aalg) 28331da177e4SLinus Torvalds break; 28341da177e4SLinus Torvalds 28351da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 28361da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 28371da177e4SLinus Torvalds } 28381da177e4SLinus Torvalds } 28391da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 28401da177e4SLinus Torvalds } 28411da177e4SLinus Torvalds 28421da177e4SLinus Torvalds static void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) 28431da177e4SLinus Torvalds { 28441da177e4SLinus Torvalds struct sadb_prop *p; 28451da177e4SLinus Torvalds int i; 28461da177e4SLinus Torvalds 28471da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28481da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28491da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28501da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28511da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28521da177e4SLinus Torvalds 28531da177e4SLinus Torvalds for (i = 0; ; i++) { 28541da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 28551da177e4SLinus Torvalds if (!aalg) 28561da177e4SLinus Torvalds break; 28571da177e4SLinus Torvalds 28581da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) { 28591da177e4SLinus Torvalds struct sadb_comb *c; 28601da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 28611da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 28621da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 28631da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 28641da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 28651da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 28661da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 28671da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 28681da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 28691da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 28701da177e4SLinus Torvalds } 28711da177e4SLinus Torvalds } 28721da177e4SLinus Torvalds } 28731da177e4SLinus Torvalds 28741da177e4SLinus Torvalds static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) 28751da177e4SLinus Torvalds { 28761da177e4SLinus Torvalds struct sadb_prop *p; 28771da177e4SLinus Torvalds int i, k; 28781da177e4SLinus Torvalds 28791da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28801da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28811da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28821da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28831da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28841da177e4SLinus Torvalds 28851da177e4SLinus Torvalds for (i=0; ; i++) { 28861da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 28871da177e4SLinus Torvalds if (!ealg) 28881da177e4SLinus Torvalds break; 28891da177e4SLinus Torvalds 28901da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 28911da177e4SLinus Torvalds continue; 28921da177e4SLinus Torvalds 28931da177e4SLinus Torvalds for (k = 1; ; k++) { 28941da177e4SLinus Torvalds struct sadb_comb *c; 28951da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 28961da177e4SLinus Torvalds if (!aalg) 28971da177e4SLinus Torvalds break; 28981da177e4SLinus Torvalds if (!(aalg_tmpl_set(t, aalg) && aalg->available)) 28991da177e4SLinus Torvalds continue; 29001da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 29011da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 29021da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 29031da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 29041da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 29051da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 29061da177e4SLinus Torvalds c->sadb_comb_encrypt = ealg->desc.sadb_alg_id; 29071da177e4SLinus Torvalds c->sadb_comb_encrypt_minbits = ealg->desc.sadb_alg_minbits; 29081da177e4SLinus Torvalds c->sadb_comb_encrypt_maxbits = ealg->desc.sadb_alg_maxbits; 29091da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 29101da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 29111da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 29121da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 29131da177e4SLinus Torvalds } 29141da177e4SLinus Torvalds } 29151da177e4SLinus Torvalds } 29161da177e4SLinus Torvalds 291726b15dadSJamal Hadi Salim static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c) 291826b15dadSJamal Hadi Salim { 291926b15dadSJamal Hadi Salim return 0; 292026b15dadSJamal Hadi Salim } 292126b15dadSJamal Hadi Salim 292226b15dadSJamal Hadi Salim static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) 29231da177e4SLinus Torvalds { 29241da177e4SLinus Torvalds struct sk_buff *out_skb; 29251da177e4SLinus Torvalds struct sadb_msg *out_hdr; 292626b15dadSJamal Hadi Salim int hard; 292726b15dadSJamal Hadi Salim int hsc; 292826b15dadSJamal Hadi Salim 2929bf08867fSHerbert Xu hard = c->data.hard; 293026b15dadSJamal Hadi Salim if (hard) 293126b15dadSJamal Hadi Salim hsc = 2; 293226b15dadSJamal Hadi Salim else 293326b15dadSJamal Hadi Salim hsc = 1; 29341da177e4SLinus Torvalds 2935050f009eSHerbert Xu out_skb = pfkey_xfrm_state2msg_expire(x, hsc); 29361da177e4SLinus Torvalds if (IS_ERR(out_skb)) 29371da177e4SLinus Torvalds return PTR_ERR(out_skb); 29381da177e4SLinus Torvalds 29391da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 29401da177e4SLinus Torvalds out_hdr->sadb_msg_version = PF_KEY_V2; 29411da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_EXPIRE; 29421da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 29431da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 29441da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 29451da177e4SLinus Torvalds out_hdr->sadb_msg_seq = 0; 29461da177e4SLinus Torvalds out_hdr->sadb_msg_pid = 0; 29471da177e4SLinus Torvalds 29481da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 29491da177e4SLinus Torvalds return 0; 29501da177e4SLinus Torvalds } 29511da177e4SLinus Torvalds 295226b15dadSJamal Hadi Salim static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) 295326b15dadSJamal Hadi Salim { 295426b15dadSJamal Hadi Salim switch (c->event) { 2955f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 295626b15dadSJamal Hadi Salim return key_notify_sa_expire(x, c); 2957f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 2958f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 2959f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 296026b15dadSJamal Hadi Salim return key_notify_sa(x, c); 2961f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 296226b15dadSJamal Hadi Salim return key_notify_sa_flush(c); 2963d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: /* not yet supported */ 2964d51d081dSJamal Hadi Salim break; 296526b15dadSJamal Hadi Salim default: 296626b15dadSJamal Hadi Salim printk("pfkey: Unknown SA event %d\n", c->event); 296726b15dadSJamal Hadi Salim break; 296826b15dadSJamal Hadi Salim } 296926b15dadSJamal Hadi Salim 297026b15dadSJamal Hadi Salim return 0; 297126b15dadSJamal Hadi Salim } 297226b15dadSJamal Hadi Salim 297326b15dadSJamal Hadi Salim static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 297426b15dadSJamal Hadi Salim { 2975f7b6983fSMasahide NAKAMURA if (xp && xp->type != XFRM_POLICY_TYPE_MAIN) 2976f7b6983fSMasahide NAKAMURA return 0; 2977f7b6983fSMasahide NAKAMURA 297826b15dadSJamal Hadi Salim switch (c->event) { 2979f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 298026b15dadSJamal Hadi Salim return key_notify_policy_expire(xp, c); 2981f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 2982f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 2983f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 298426b15dadSJamal Hadi Salim return key_notify_policy(xp, dir, c); 2985f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 2986f7b6983fSMasahide NAKAMURA if (c->data.type != XFRM_POLICY_TYPE_MAIN) 2987f7b6983fSMasahide NAKAMURA break; 298826b15dadSJamal Hadi Salim return key_notify_policy_flush(c); 298926b15dadSJamal Hadi Salim default: 299026b15dadSJamal Hadi Salim printk("pfkey: Unknown policy event %d\n", c->event); 299126b15dadSJamal Hadi Salim break; 299226b15dadSJamal Hadi Salim } 299326b15dadSJamal Hadi Salim 299426b15dadSJamal Hadi Salim return 0; 299526b15dadSJamal Hadi Salim } 299626b15dadSJamal Hadi Salim 29971da177e4SLinus Torvalds static u32 get_acqseq(void) 29981da177e4SLinus Torvalds { 29991da177e4SLinus Torvalds u32 res; 30001da177e4SLinus Torvalds static u32 acqseq; 30011da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 30021da177e4SLinus Torvalds 30031da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 30041da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 30051da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 30061da177e4SLinus Torvalds return res; 30071da177e4SLinus Torvalds } 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir) 30101da177e4SLinus Torvalds { 30111da177e4SLinus Torvalds struct sk_buff *skb; 30121da177e4SLinus Torvalds struct sadb_msg *hdr; 30131da177e4SLinus Torvalds struct sadb_address *addr; 30141da177e4SLinus Torvalds struct sadb_x_policy *pol; 30151da177e4SLinus Torvalds struct sockaddr_in *sin; 30161da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 30171da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 30181da177e4SLinus Torvalds #endif 30191da177e4SLinus Torvalds int sockaddr_size; 30201da177e4SLinus Torvalds int size; 30214e2ba18eSVenkat Yekkirala struct sadb_x_sec_ctx *sec_ctx; 30224e2ba18eSVenkat Yekkirala struct xfrm_sec_ctx *xfrm_ctx; 30234e2ba18eSVenkat Yekkirala int ctx_size = 0; 30241da177e4SLinus Torvalds 30251da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 30261da177e4SLinus Torvalds if (!sockaddr_size) 30271da177e4SLinus Torvalds return -EINVAL; 30281da177e4SLinus Torvalds 30291da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 30301da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 30311da177e4SLinus Torvalds (sockaddr_size * 2) + 30321da177e4SLinus Torvalds sizeof(struct sadb_x_policy); 30331da177e4SLinus Torvalds 30341da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 30351da177e4SLinus Torvalds size += count_ah_combs(t); 30361da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 30371da177e4SLinus Torvalds size += count_esp_combs(t); 30381da177e4SLinus Torvalds 30394e2ba18eSVenkat Yekkirala if ((xfrm_ctx = x->security)) { 30404e2ba18eSVenkat Yekkirala ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 30414e2ba18eSVenkat Yekkirala size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 30424e2ba18eSVenkat Yekkirala } 30434e2ba18eSVenkat Yekkirala 30441da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 30451da177e4SLinus Torvalds if (skb == NULL) 30461da177e4SLinus Torvalds return -ENOMEM; 30471da177e4SLinus Torvalds 30481da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 30491da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 30501da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_ACQUIRE; 30511da177e4SLinus Torvalds hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 30521da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 30531da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 30541da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 30551da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 30561da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 30571da177e4SLinus Torvalds 30581da177e4SLinus Torvalds /* src address */ 30591da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30601da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30611da177e4SLinus Torvalds addr->sadb_address_len = 30621da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30631da177e4SLinus Torvalds sizeof(uint64_t); 30641da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 30651da177e4SLinus Torvalds addr->sadb_address_proto = 0; 30661da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 30671da177e4SLinus Torvalds if (x->props.family == AF_INET) { 30681da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 30691da177e4SLinus Torvalds 30701da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 30711da177e4SLinus Torvalds sin->sin_family = AF_INET; 30721da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 30731da177e4SLinus Torvalds sin->sin_port = 0; 30741da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 30751da177e4SLinus Torvalds } 30761da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 30771da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 30781da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 30791da177e4SLinus Torvalds 30801da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 30811da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 30821da177e4SLinus Torvalds sin6->sin6_port = 0; 30831da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 30841da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 30851da177e4SLinus Torvalds x->props.saddr.a6, sizeof(struct in6_addr)); 30861da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 30871da177e4SLinus Torvalds } 30881da177e4SLinus Torvalds #endif 30891da177e4SLinus Torvalds else 30901da177e4SLinus Torvalds BUG(); 30911da177e4SLinus Torvalds 30921da177e4SLinus Torvalds /* dst address */ 30931da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30941da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30951da177e4SLinus Torvalds addr->sadb_address_len = 30961da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30971da177e4SLinus Torvalds sizeof(uint64_t); 30981da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 30991da177e4SLinus Torvalds addr->sadb_address_proto = 0; 31001da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 31011da177e4SLinus Torvalds if (x->props.family == AF_INET) { 31021da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 31031da177e4SLinus Torvalds 31041da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 31051da177e4SLinus Torvalds sin->sin_family = AF_INET; 31061da177e4SLinus Torvalds sin->sin_addr.s_addr = x->id.daddr.a4; 31071da177e4SLinus Torvalds sin->sin_port = 0; 31081da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 31091da177e4SLinus Torvalds } 31101da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 31111da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 31121da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 31131da177e4SLinus Torvalds 31141da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 31151da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 31161da177e4SLinus Torvalds sin6->sin6_port = 0; 31171da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 31181da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 31191da177e4SLinus Torvalds x->id.daddr.a6, sizeof(struct in6_addr)); 31201da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 31211da177e4SLinus Torvalds } 31221da177e4SLinus Torvalds #endif 31231da177e4SLinus Torvalds else 31241da177e4SLinus Torvalds BUG(); 31251da177e4SLinus Torvalds 31261da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 31271da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 31281da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 31291da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 31301da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 31311da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 31321da177e4SLinus Torvalds 31331da177e4SLinus Torvalds /* Set sadb_comb's. */ 31341da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 31351da177e4SLinus Torvalds dump_ah_combs(skb, t); 31361da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 31371da177e4SLinus Torvalds dump_esp_combs(skb, t); 31381da177e4SLinus Torvalds 31394e2ba18eSVenkat Yekkirala /* security context */ 31404e2ba18eSVenkat Yekkirala if (xfrm_ctx) { 31414e2ba18eSVenkat Yekkirala sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, 31424e2ba18eSVenkat Yekkirala sizeof(struct sadb_x_sec_ctx) + ctx_size); 31434e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_len = 31444e2ba18eSVenkat Yekkirala (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); 31454e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 31464e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 31474e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 31484e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 31494e2ba18eSVenkat Yekkirala memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 31504e2ba18eSVenkat Yekkirala xfrm_ctx->ctx_len); 31514e2ba18eSVenkat Yekkirala } 31524e2ba18eSVenkat Yekkirala 31531da177e4SLinus Torvalds return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 31541da177e4SLinus Torvalds } 31551da177e4SLinus Torvalds 3156cb969f07SVenkat Yekkirala static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, 31571da177e4SLinus Torvalds u8 *data, int len, int *dir) 31581da177e4SLinus Torvalds { 31591da177e4SLinus Torvalds struct xfrm_policy *xp; 31601da177e4SLinus Torvalds struct sadb_x_policy *pol = (struct sadb_x_policy*)data; 3161df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 31621da177e4SLinus Torvalds 3163cb969f07SVenkat Yekkirala switch (sk->sk_family) { 31641da177e4SLinus Torvalds case AF_INET: 31651da177e4SLinus Torvalds if (opt != IP_IPSEC_POLICY) { 31661da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31671da177e4SLinus Torvalds return NULL; 31681da177e4SLinus Torvalds } 31691da177e4SLinus Torvalds break; 31701da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 31711da177e4SLinus Torvalds case AF_INET6: 31721da177e4SLinus Torvalds if (opt != IPV6_IPSEC_POLICY) { 31731da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31741da177e4SLinus Torvalds return NULL; 31751da177e4SLinus Torvalds } 31761da177e4SLinus Torvalds break; 31771da177e4SLinus Torvalds #endif 31781da177e4SLinus Torvalds default: 31791da177e4SLinus Torvalds *dir = -EINVAL; 31801da177e4SLinus Torvalds return NULL; 31811da177e4SLinus Torvalds } 31821da177e4SLinus Torvalds 31831da177e4SLinus Torvalds *dir = -EINVAL; 31841da177e4SLinus Torvalds 31851da177e4SLinus Torvalds if (len < sizeof(struct sadb_x_policy) || 31861da177e4SLinus Torvalds pol->sadb_x_policy_len*8 > len || 31871da177e4SLinus Torvalds pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS || 31881da177e4SLinus Torvalds (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND)) 31891da177e4SLinus Torvalds return NULL; 31901da177e4SLinus Torvalds 31911da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_ATOMIC); 31921da177e4SLinus Torvalds if (xp == NULL) { 31931da177e4SLinus Torvalds *dir = -ENOBUFS; 31941da177e4SLinus Torvalds return NULL; 31951da177e4SLinus Torvalds } 31961da177e4SLinus Torvalds 31971da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 31981da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 31991da177e4SLinus Torvalds 32001da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 32011da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 32021da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 32031da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 3204cb969f07SVenkat Yekkirala xp->family = sk->sk_family; 32051da177e4SLinus Torvalds 32061da177e4SLinus Torvalds xp->xfrm_nr = 0; 32071da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 32081da177e4SLinus Torvalds (*dir = parse_ipsecrequests(xp, pol)) < 0) 32091da177e4SLinus Torvalds goto out; 32101da177e4SLinus Torvalds 3211df71837dSTrent Jaeger /* security context too */ 3212df71837dSTrent Jaeger if (len >= (pol->sadb_x_policy_len*8 + 3213df71837dSTrent Jaeger sizeof(struct sadb_x_sec_ctx))) { 3214df71837dSTrent Jaeger char *p = (char *)pol; 3215df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 3216df71837dSTrent Jaeger 3217df71837dSTrent Jaeger p += pol->sadb_x_policy_len*8; 3218df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *)p; 3219df71837dSTrent Jaeger if (len < pol->sadb_x_policy_len*8 + 3220cb969f07SVenkat Yekkirala sec_ctx->sadb_x_sec_len) { 3221cb969f07SVenkat Yekkirala *dir = -EINVAL; 3222df71837dSTrent Jaeger goto out; 3223cb969f07SVenkat Yekkirala } 3224df71837dSTrent Jaeger if ((*dir = verify_sec_ctx_len(p))) 3225df71837dSTrent Jaeger goto out; 3226df71837dSTrent Jaeger uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 3227df71837dSTrent Jaeger *dir = security_xfrm_policy_alloc(xp, uctx); 3228df71837dSTrent Jaeger kfree(uctx); 3229df71837dSTrent Jaeger 3230df71837dSTrent Jaeger if (*dir) 3231df71837dSTrent Jaeger goto out; 3232df71837dSTrent Jaeger } 3233df71837dSTrent Jaeger 32341da177e4SLinus Torvalds *dir = pol->sadb_x_policy_dir-1; 32351da177e4SLinus Torvalds return xp; 32361da177e4SLinus Torvalds 32371da177e4SLinus Torvalds out: 323864c31b3fSWANG Cong xfrm_policy_destroy(xp); 32391da177e4SLinus Torvalds return NULL; 32401da177e4SLinus Torvalds } 32411da177e4SLinus Torvalds 32425d36b180SAl Viro static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 32431da177e4SLinus Torvalds { 32441da177e4SLinus Torvalds struct sk_buff *skb; 32451da177e4SLinus Torvalds struct sadb_msg *hdr; 32461da177e4SLinus Torvalds struct sadb_sa *sa; 32471da177e4SLinus Torvalds struct sadb_address *addr; 32481da177e4SLinus Torvalds struct sadb_x_nat_t_port *n_port; 32491da177e4SLinus Torvalds struct sockaddr_in *sin; 32501da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 32511da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 32521da177e4SLinus Torvalds #endif 32531da177e4SLinus Torvalds int sockaddr_size; 32541da177e4SLinus Torvalds int size; 32551da177e4SLinus Torvalds __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0); 32561da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 32571da177e4SLinus Torvalds 32581da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 32591da177e4SLinus Torvalds if (!sockaddr_size) 32601da177e4SLinus Torvalds return -EINVAL; 32611da177e4SLinus Torvalds 32621da177e4SLinus Torvalds if (!satype) 32631da177e4SLinus Torvalds return -EINVAL; 32641da177e4SLinus Torvalds 32651da177e4SLinus Torvalds if (!x->encap) 32661da177e4SLinus Torvalds return -EINVAL; 32671da177e4SLinus Torvalds 32681da177e4SLinus Torvalds natt = x->encap; 32691da177e4SLinus Torvalds 32701da177e4SLinus Torvalds /* Build an SADB_X_NAT_T_NEW_MAPPING message: 32711da177e4SLinus Torvalds * 32721da177e4SLinus Torvalds * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) | 32731da177e4SLinus Torvalds * ADDRESS_DST (new addr) | NAT_T_DPORT (new port) 32741da177e4SLinus Torvalds */ 32751da177e4SLinus Torvalds 32761da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 32771da177e4SLinus Torvalds sizeof(struct sadb_sa) + 32781da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 32791da177e4SLinus Torvalds (sockaddr_size * 2) + 32801da177e4SLinus Torvalds (sizeof(struct sadb_x_nat_t_port) * 2); 32811da177e4SLinus Torvalds 32821da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 32831da177e4SLinus Torvalds if (skb == NULL) 32841da177e4SLinus Torvalds return -ENOMEM; 32851da177e4SLinus Torvalds 32861da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 32871da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 32881da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING; 32891da177e4SLinus Torvalds hdr->sadb_msg_satype = satype; 32901da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 32911da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 32921da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 32931da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 32941da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 32951da177e4SLinus Torvalds 32961da177e4SLinus Torvalds /* SA */ 32971da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 32981da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 32991da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 33001da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 33011da177e4SLinus Torvalds sa->sadb_sa_replay = 0; 33021da177e4SLinus Torvalds sa->sadb_sa_state = 0; 33031da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 33041da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 33051da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 33061da177e4SLinus Torvalds 33071da177e4SLinus Torvalds /* ADDRESS_SRC (old addr) */ 33081da177e4SLinus Torvalds addr = (struct sadb_address*) 33091da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 33101da177e4SLinus Torvalds addr->sadb_address_len = 33111da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 33121da177e4SLinus Torvalds sizeof(uint64_t); 33131da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 33141da177e4SLinus Torvalds addr->sadb_address_proto = 0; 33151da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 33161da177e4SLinus Torvalds if (x->props.family == AF_INET) { 33171da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 33181da177e4SLinus Torvalds 33191da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 33201da177e4SLinus Torvalds sin->sin_family = AF_INET; 33211da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 33221da177e4SLinus Torvalds sin->sin_port = 0; 33231da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 33241da177e4SLinus Torvalds } 33251da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 33261da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 33271da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 33281da177e4SLinus Torvalds 33291da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 33301da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 33311da177e4SLinus Torvalds sin6->sin6_port = 0; 33321da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 33331da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 33341da177e4SLinus Torvalds x->props.saddr.a6, sizeof(struct in6_addr)); 33351da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 33361da177e4SLinus Torvalds } 33371da177e4SLinus Torvalds #endif 33381da177e4SLinus Torvalds else 33391da177e4SLinus Torvalds BUG(); 33401da177e4SLinus Torvalds 33411da177e4SLinus Torvalds /* NAT_T_SPORT (old port) */ 33421da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33431da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33441da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; 33451da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_sport; 33461da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33471da177e4SLinus Torvalds 33481da177e4SLinus Torvalds /* ADDRESS_DST (new addr) */ 33491da177e4SLinus Torvalds addr = (struct sadb_address*) 33501da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 33511da177e4SLinus Torvalds addr->sadb_address_len = 33521da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 33531da177e4SLinus Torvalds sizeof(uint64_t); 33541da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 33551da177e4SLinus Torvalds addr->sadb_address_proto = 0; 33561da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 33571da177e4SLinus Torvalds if (x->props.family == AF_INET) { 33581da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 33591da177e4SLinus Torvalds 33601da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 33611da177e4SLinus Torvalds sin->sin_family = AF_INET; 33621da177e4SLinus Torvalds sin->sin_addr.s_addr = ipaddr->a4; 33631da177e4SLinus Torvalds sin->sin_port = 0; 33641da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 33651da177e4SLinus Torvalds } 33661da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 33671da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 33681da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 33691da177e4SLinus Torvalds 33701da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 33711da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 33721da177e4SLinus Torvalds sin6->sin6_port = 0; 33731da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 33741da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr)); 33751da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 33761da177e4SLinus Torvalds } 33771da177e4SLinus Torvalds #endif 33781da177e4SLinus Torvalds else 33791da177e4SLinus Torvalds BUG(); 33801da177e4SLinus Torvalds 33811da177e4SLinus Torvalds /* NAT_T_DPORT (new port) */ 33821da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33831da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33841da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; 33851da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = sport; 33861da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33871da177e4SLinus Torvalds 33881da177e4SLinus Torvalds return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 33891da177e4SLinus Torvalds } 33901da177e4SLinus Torvalds 339108de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 339208de61beSShinta Sugimoto static int set_sadb_address(struct sk_buff *skb, int sasize, int type, 339308de61beSShinta Sugimoto struct xfrm_selector *sel) 339408de61beSShinta Sugimoto { 339508de61beSShinta Sugimoto struct sadb_address *addr; 339608de61beSShinta Sugimoto struct sockaddr_in *sin; 339708de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 339808de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 339908de61beSShinta Sugimoto #endif 340008de61beSShinta Sugimoto addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); 340108de61beSShinta Sugimoto addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; 340208de61beSShinta Sugimoto addr->sadb_address_exttype = type; 340308de61beSShinta Sugimoto addr->sadb_address_proto = sel->proto; 340408de61beSShinta Sugimoto addr->sadb_address_reserved = 0; 340508de61beSShinta Sugimoto 340608de61beSShinta Sugimoto switch (type) { 340708de61beSShinta Sugimoto case SADB_EXT_ADDRESS_SRC: 340808de61beSShinta Sugimoto if (sel->family == AF_INET) { 340908de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_s; 341008de61beSShinta Sugimoto sin = (struct sockaddr_in *)(addr + 1); 341108de61beSShinta Sugimoto sin->sin_family = AF_INET; 341208de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, &sel->saddr, 341308de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 341408de61beSShinta Sugimoto sin->sin_port = 0; 341508de61beSShinta Sugimoto memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 341608de61beSShinta Sugimoto } 341708de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 341808de61beSShinta Sugimoto else if (sel->family == AF_INET6) { 341908de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_s; 342008de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(addr + 1); 342108de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 342208de61beSShinta Sugimoto sin6->sin6_port = 0; 342308de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 342408de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 342508de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr, 342608de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 342708de61beSShinta Sugimoto } 342808de61beSShinta Sugimoto #endif 342908de61beSShinta Sugimoto break; 343008de61beSShinta Sugimoto case SADB_EXT_ADDRESS_DST: 343108de61beSShinta Sugimoto if (sel->family == AF_INET) { 343208de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_d; 343308de61beSShinta Sugimoto sin = (struct sockaddr_in *)(addr + 1); 343408de61beSShinta Sugimoto sin->sin_family = AF_INET; 343508de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, &sel->daddr, 343608de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 343708de61beSShinta Sugimoto sin->sin_port = 0; 343808de61beSShinta Sugimoto memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 343908de61beSShinta Sugimoto } 344008de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 344108de61beSShinta Sugimoto else if (sel->family == AF_INET6) { 344208de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_d; 344308de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(addr + 1); 344408de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 344508de61beSShinta Sugimoto sin6->sin6_port = 0; 344608de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 344708de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 344808de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr, 344908de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 345008de61beSShinta Sugimoto } 345108de61beSShinta Sugimoto #endif 345208de61beSShinta Sugimoto break; 345308de61beSShinta Sugimoto default: 345408de61beSShinta Sugimoto return -EINVAL; 345508de61beSShinta Sugimoto } 345608de61beSShinta Sugimoto 345708de61beSShinta Sugimoto return 0; 345808de61beSShinta Sugimoto } 345908de61beSShinta Sugimoto 346008de61beSShinta Sugimoto static int set_ipsecrequest(struct sk_buff *skb, 346108de61beSShinta Sugimoto uint8_t proto, uint8_t mode, int level, 346208de61beSShinta Sugimoto uint32_t reqid, uint8_t family, 346308de61beSShinta Sugimoto xfrm_address_t *src, xfrm_address_t *dst) 346408de61beSShinta Sugimoto { 346508de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 346608de61beSShinta Sugimoto struct sockaddr_in *sin; 346708de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 346808de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 346908de61beSShinta Sugimoto #endif 347008de61beSShinta Sugimoto int size_req; 347108de61beSShinta Sugimoto 347208de61beSShinta Sugimoto size_req = sizeof(struct sadb_x_ipsecrequest) + 347308de61beSShinta Sugimoto pfkey_sockaddr_pair_size(family); 347408de61beSShinta Sugimoto 347508de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req); 347608de61beSShinta Sugimoto memset(rq, 0, size_req); 347708de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_len = size_req; 347808de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_proto = proto; 347908de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_mode = mode; 348008de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_level = level; 348108de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_reqid = reqid; 348208de61beSShinta Sugimoto 348308de61beSShinta Sugimoto switch (family) { 348408de61beSShinta Sugimoto case AF_INET: 348508de61beSShinta Sugimoto sin = (struct sockaddr_in *)(rq + 1); 348608de61beSShinta Sugimoto sin->sin_family = AF_INET; 348708de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, src, 348808de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 348908de61beSShinta Sugimoto sin++; 349008de61beSShinta Sugimoto sin->sin_family = AF_INET; 349108de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, dst, 349208de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 349308de61beSShinta Sugimoto break; 349408de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 349508de61beSShinta Sugimoto case AF_INET6: 349608de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(rq + 1); 349708de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 349808de61beSShinta Sugimoto sin6->sin6_port = 0; 349908de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 350008de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 350108de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, src, 350208de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 350308de61beSShinta Sugimoto sin6++; 350408de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 350508de61beSShinta Sugimoto sin6->sin6_port = 0; 350608de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 350708de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 350808de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, dst, 350908de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 351008de61beSShinta Sugimoto break; 351108de61beSShinta Sugimoto #endif 351208de61beSShinta Sugimoto default: 351308de61beSShinta Sugimoto return -EINVAL; 351408de61beSShinta Sugimoto } 351508de61beSShinta Sugimoto 351608de61beSShinta Sugimoto return 0; 351708de61beSShinta Sugimoto } 351808de61beSShinta Sugimoto #endif 351908de61beSShinta Sugimoto 352008de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 352108de61beSShinta Sugimoto static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 352208de61beSShinta Sugimoto struct xfrm_migrate *m, int num_bundles) 352308de61beSShinta Sugimoto { 352408de61beSShinta Sugimoto int i; 352508de61beSShinta Sugimoto int sasize_sel; 352608de61beSShinta Sugimoto int size = 0; 352708de61beSShinta Sugimoto int size_pol = 0; 352808de61beSShinta Sugimoto struct sk_buff *skb; 352908de61beSShinta Sugimoto struct sadb_msg *hdr; 353008de61beSShinta Sugimoto struct sadb_x_policy *pol; 353108de61beSShinta Sugimoto struct xfrm_migrate *mp; 353208de61beSShinta Sugimoto 353308de61beSShinta Sugimoto if (type != XFRM_POLICY_TYPE_MAIN) 353408de61beSShinta Sugimoto return 0; 353508de61beSShinta Sugimoto 353608de61beSShinta Sugimoto if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) 353708de61beSShinta Sugimoto return -EINVAL; 353808de61beSShinta Sugimoto 353908de61beSShinta Sugimoto /* selector */ 354008de61beSShinta Sugimoto sasize_sel = pfkey_sockaddr_size(sel->family); 354108de61beSShinta Sugimoto if (!sasize_sel) 354208de61beSShinta Sugimoto return -EINVAL; 354308de61beSShinta Sugimoto size += (sizeof(struct sadb_address) + sasize_sel) * 2; 354408de61beSShinta Sugimoto 354508de61beSShinta Sugimoto /* policy info */ 354608de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_policy); 354708de61beSShinta Sugimoto 354808de61beSShinta Sugimoto /* ipsecrequests */ 354908de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 355008de61beSShinta Sugimoto /* old locator pair */ 355108de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 355208de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->old_family); 355308de61beSShinta Sugimoto /* new locator pair */ 355408de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 355508de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->new_family); 355608de61beSShinta Sugimoto } 355708de61beSShinta Sugimoto 355808de61beSShinta Sugimoto size += sizeof(struct sadb_msg) + size_pol; 355908de61beSShinta Sugimoto 356008de61beSShinta Sugimoto /* alloc buffer */ 356108de61beSShinta Sugimoto skb = alloc_skb(size, GFP_ATOMIC); 356208de61beSShinta Sugimoto if (skb == NULL) 356308de61beSShinta Sugimoto return -ENOMEM; 356408de61beSShinta Sugimoto 356508de61beSShinta Sugimoto hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg)); 356608de61beSShinta Sugimoto hdr->sadb_msg_version = PF_KEY_V2; 356708de61beSShinta Sugimoto hdr->sadb_msg_type = SADB_X_MIGRATE; 356808de61beSShinta Sugimoto hdr->sadb_msg_satype = pfkey_proto2satype(m->proto); 356908de61beSShinta Sugimoto hdr->sadb_msg_len = size / 8; 357008de61beSShinta Sugimoto hdr->sadb_msg_errno = 0; 357108de61beSShinta Sugimoto hdr->sadb_msg_reserved = 0; 357208de61beSShinta Sugimoto hdr->sadb_msg_seq = 0; 357308de61beSShinta Sugimoto hdr->sadb_msg_pid = 0; 357408de61beSShinta Sugimoto 357508de61beSShinta Sugimoto /* selector src */ 357608de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); 357708de61beSShinta Sugimoto 357808de61beSShinta Sugimoto /* selector dst */ 357908de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel); 358008de61beSShinta Sugimoto 358108de61beSShinta Sugimoto /* policy information */ 358208de61beSShinta Sugimoto pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy)); 358308de61beSShinta Sugimoto pol->sadb_x_policy_len = size_pol / 8; 358408de61beSShinta Sugimoto pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 358508de61beSShinta Sugimoto pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 358608de61beSShinta Sugimoto pol->sadb_x_policy_dir = dir + 1; 358708de61beSShinta Sugimoto pol->sadb_x_policy_id = 0; 358808de61beSShinta Sugimoto pol->sadb_x_policy_priority = 0; 358908de61beSShinta Sugimoto 359008de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 359108de61beSShinta Sugimoto /* old ipsecrequest */ 359255569ce2SKazunori MIYAZAWA int mode = pfkey_mode_from_xfrm(mp->mode); 359355569ce2SKazunori MIYAZAWA if (mode < 0) 3594d4782c32SPatrick McHardy goto err; 359555569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 359608de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 359708de61beSShinta Sugimoto mp->reqid, mp->old_family, 3598d4782c32SPatrick McHardy &mp->old_saddr, &mp->old_daddr) < 0) 3599d4782c32SPatrick McHardy goto err; 360008de61beSShinta Sugimoto 360108de61beSShinta Sugimoto /* new ipsecrequest */ 360255569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 360308de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 360408de61beSShinta Sugimoto mp->reqid, mp->new_family, 3605d4782c32SPatrick McHardy &mp->new_saddr, &mp->new_daddr) < 0) 3606d4782c32SPatrick McHardy goto err; 360708de61beSShinta Sugimoto } 360808de61beSShinta Sugimoto 360908de61beSShinta Sugimoto /* broadcast migrate message to sockets */ 361008de61beSShinta Sugimoto pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 361108de61beSShinta Sugimoto 361208de61beSShinta Sugimoto return 0; 3613d4782c32SPatrick McHardy 3614d4782c32SPatrick McHardy err: 3615d4782c32SPatrick McHardy kfree_skb(skb); 3616d4782c32SPatrick McHardy return -EINVAL; 361708de61beSShinta Sugimoto } 361808de61beSShinta Sugimoto #else 361908de61beSShinta Sugimoto static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 362008de61beSShinta Sugimoto struct xfrm_migrate *m, int num_bundles) 362108de61beSShinta Sugimoto { 362208de61beSShinta Sugimoto return -ENOPROTOOPT; 362308de61beSShinta Sugimoto } 362408de61beSShinta Sugimoto #endif 362508de61beSShinta Sugimoto 36261da177e4SLinus Torvalds static int pfkey_sendmsg(struct kiocb *kiocb, 36271da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len) 36281da177e4SLinus Torvalds { 36291da177e4SLinus Torvalds struct sock *sk = sock->sk; 36301da177e4SLinus Torvalds struct sk_buff *skb = NULL; 36311da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 36321da177e4SLinus Torvalds int err; 36331da177e4SLinus Torvalds 36341da177e4SLinus Torvalds err = -EOPNOTSUPP; 36351da177e4SLinus Torvalds if (msg->msg_flags & MSG_OOB) 36361da177e4SLinus Torvalds goto out; 36371da177e4SLinus Torvalds 36381da177e4SLinus Torvalds err = -EMSGSIZE; 36391da177e4SLinus Torvalds if ((unsigned)len > sk->sk_sndbuf - 32) 36401da177e4SLinus Torvalds goto out; 36411da177e4SLinus Torvalds 36421da177e4SLinus Torvalds err = -ENOBUFS; 36431da177e4SLinus Torvalds skb = alloc_skb(len, GFP_KERNEL); 36441da177e4SLinus Torvalds if (skb == NULL) 36451da177e4SLinus Torvalds goto out; 36461da177e4SLinus Torvalds 36471da177e4SLinus Torvalds err = -EFAULT; 36481da177e4SLinus Torvalds if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) 36491da177e4SLinus Torvalds goto out; 36501da177e4SLinus Torvalds 36511da177e4SLinus Torvalds hdr = pfkey_get_base_msg(skb, &err); 36521da177e4SLinus Torvalds if (!hdr) 36531da177e4SLinus Torvalds goto out; 36541da177e4SLinus Torvalds 36554a3e2f71SArjan van de Ven mutex_lock(&xfrm_cfg_mutex); 36561da177e4SLinus Torvalds err = pfkey_process(sk, skb, hdr); 36574a3e2f71SArjan van de Ven mutex_unlock(&xfrm_cfg_mutex); 36581da177e4SLinus Torvalds 36591da177e4SLinus Torvalds out: 36601da177e4SLinus Torvalds if (err && hdr && pfkey_error(hdr, err, sk) == 0) 36611da177e4SLinus Torvalds err = 0; 36621da177e4SLinus Torvalds if (skb) 36631da177e4SLinus Torvalds kfree_skb(skb); 36641da177e4SLinus Torvalds 36651da177e4SLinus Torvalds return err ? : len; 36661da177e4SLinus Torvalds } 36671da177e4SLinus Torvalds 36681da177e4SLinus Torvalds static int pfkey_recvmsg(struct kiocb *kiocb, 36691da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len, 36701da177e4SLinus Torvalds int flags) 36711da177e4SLinus Torvalds { 36721da177e4SLinus Torvalds struct sock *sk = sock->sk; 36731da177e4SLinus Torvalds struct sk_buff *skb; 36741da177e4SLinus Torvalds int copied, err; 36751da177e4SLinus Torvalds 36761da177e4SLinus Torvalds err = -EINVAL; 36771da177e4SLinus Torvalds if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) 36781da177e4SLinus Torvalds goto out; 36791da177e4SLinus Torvalds 36801da177e4SLinus Torvalds msg->msg_namelen = 0; 36811da177e4SLinus Torvalds skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); 36821da177e4SLinus Torvalds if (skb == NULL) 36831da177e4SLinus Torvalds goto out; 36841da177e4SLinus Torvalds 36851da177e4SLinus Torvalds copied = skb->len; 36861da177e4SLinus Torvalds if (copied > len) { 36871da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC; 36881da177e4SLinus Torvalds copied = len; 36891da177e4SLinus Torvalds } 36901da177e4SLinus Torvalds 3691badff6d0SArnaldo Carvalho de Melo skb_reset_transport_header(skb); 36921da177e4SLinus Torvalds err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 36931da177e4SLinus Torvalds if (err) 36941da177e4SLinus Torvalds goto out_free; 36951da177e4SLinus Torvalds 36961da177e4SLinus Torvalds sock_recv_timestamp(msg, sk, skb); 36971da177e4SLinus Torvalds 36981da177e4SLinus Torvalds err = (flags & MSG_TRUNC) ? skb->len : copied; 36991da177e4SLinus Torvalds 37001da177e4SLinus Torvalds out_free: 37011da177e4SLinus Torvalds skb_free_datagram(sk, skb); 37021da177e4SLinus Torvalds out: 37031da177e4SLinus Torvalds return err; 37041da177e4SLinus Torvalds } 37051da177e4SLinus Torvalds 370690ddc4f0SEric Dumazet static const struct proto_ops pfkey_ops = { 37071da177e4SLinus Torvalds .family = PF_KEY, 37081da177e4SLinus Torvalds .owner = THIS_MODULE, 37091da177e4SLinus Torvalds /* Operations that make no sense on pfkey sockets. */ 37101da177e4SLinus Torvalds .bind = sock_no_bind, 37111da177e4SLinus Torvalds .connect = sock_no_connect, 37121da177e4SLinus Torvalds .socketpair = sock_no_socketpair, 37131da177e4SLinus Torvalds .accept = sock_no_accept, 37141da177e4SLinus Torvalds .getname = sock_no_getname, 37151da177e4SLinus Torvalds .ioctl = sock_no_ioctl, 37161da177e4SLinus Torvalds .listen = sock_no_listen, 37171da177e4SLinus Torvalds .shutdown = sock_no_shutdown, 37181da177e4SLinus Torvalds .setsockopt = sock_no_setsockopt, 37191da177e4SLinus Torvalds .getsockopt = sock_no_getsockopt, 37201da177e4SLinus Torvalds .mmap = sock_no_mmap, 37211da177e4SLinus Torvalds .sendpage = sock_no_sendpage, 37221da177e4SLinus Torvalds 37231da177e4SLinus Torvalds /* Now the operations that really occur. */ 37241da177e4SLinus Torvalds .release = pfkey_release, 37251da177e4SLinus Torvalds .poll = datagram_poll, 37261da177e4SLinus Torvalds .sendmsg = pfkey_sendmsg, 37271da177e4SLinus Torvalds .recvmsg = pfkey_recvmsg, 37281da177e4SLinus Torvalds }; 37291da177e4SLinus Torvalds 37301da177e4SLinus Torvalds static struct net_proto_family pfkey_family_ops = { 37311da177e4SLinus Torvalds .family = PF_KEY, 37321da177e4SLinus Torvalds .create = pfkey_create, 37331da177e4SLinus Torvalds .owner = THIS_MODULE, 37341da177e4SLinus Torvalds }; 37351da177e4SLinus Torvalds 37361da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 37371da177e4SLinus Torvalds static int pfkey_read_proc(char *buffer, char **start, off_t offset, 37381da177e4SLinus Torvalds int length, int *eof, void *data) 37391da177e4SLinus Torvalds { 37401da177e4SLinus Torvalds off_t pos = 0; 37411da177e4SLinus Torvalds off_t begin = 0; 37421da177e4SLinus Torvalds int len = 0; 37431da177e4SLinus Torvalds struct sock *s; 37441da177e4SLinus Torvalds struct hlist_node *node; 37451da177e4SLinus Torvalds 37461da177e4SLinus Torvalds len += sprintf(buffer,"sk RefCnt Rmem Wmem User Inode\n"); 37471da177e4SLinus Torvalds 37481da177e4SLinus Torvalds read_lock(&pfkey_table_lock); 37491da177e4SLinus Torvalds 37501da177e4SLinus Torvalds sk_for_each(s, node, &pfkey_table) { 37511da177e4SLinus Torvalds len += sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu", 37521da177e4SLinus Torvalds s, 37531da177e4SLinus Torvalds atomic_read(&s->sk_refcnt), 37541da177e4SLinus Torvalds atomic_read(&s->sk_rmem_alloc), 37551da177e4SLinus Torvalds atomic_read(&s->sk_wmem_alloc), 37561da177e4SLinus Torvalds sock_i_uid(s), 37571da177e4SLinus Torvalds sock_i_ino(s) 37581da177e4SLinus Torvalds ); 37591da177e4SLinus Torvalds 37601da177e4SLinus Torvalds buffer[len++] = '\n'; 37611da177e4SLinus Torvalds 37621da177e4SLinus Torvalds pos = begin + len; 37631da177e4SLinus Torvalds if (pos < offset) { 37641da177e4SLinus Torvalds len = 0; 37651da177e4SLinus Torvalds begin = pos; 37661da177e4SLinus Torvalds } 37671da177e4SLinus Torvalds if(pos > offset + length) 37681da177e4SLinus Torvalds goto done; 37691da177e4SLinus Torvalds } 37701da177e4SLinus Torvalds *eof = 1; 37711da177e4SLinus Torvalds 37721da177e4SLinus Torvalds done: 37731da177e4SLinus Torvalds read_unlock(&pfkey_table_lock); 37741da177e4SLinus Torvalds 37751da177e4SLinus Torvalds *start = buffer + (offset - begin); 37761da177e4SLinus Torvalds len -= (offset - begin); 37771da177e4SLinus Torvalds 37781da177e4SLinus Torvalds if (len > length) 37791da177e4SLinus Torvalds len = length; 37801da177e4SLinus Torvalds if (len < 0) 37811da177e4SLinus Torvalds len = 0; 37821da177e4SLinus Torvalds 37831da177e4SLinus Torvalds return len; 37841da177e4SLinus Torvalds } 37851da177e4SLinus Torvalds #endif 37861da177e4SLinus Torvalds 37871da177e4SLinus Torvalds static struct xfrm_mgr pfkeyv2_mgr = 37881da177e4SLinus Torvalds { 37891da177e4SLinus Torvalds .id = "pfkeyv2", 37901da177e4SLinus Torvalds .notify = pfkey_send_notify, 37911da177e4SLinus Torvalds .acquire = pfkey_send_acquire, 37921da177e4SLinus Torvalds .compile_policy = pfkey_compile_policy, 37931da177e4SLinus Torvalds .new_mapping = pfkey_send_new_mapping, 379426b15dadSJamal Hadi Salim .notify_policy = pfkey_send_policy_notify, 379508de61beSShinta Sugimoto .migrate = pfkey_send_migrate, 37961da177e4SLinus Torvalds }; 37971da177e4SLinus Torvalds 37981da177e4SLinus Torvalds static void __exit ipsec_pfkey_exit(void) 37991da177e4SLinus Torvalds { 38001da177e4SLinus Torvalds xfrm_unregister_km(&pfkeyv2_mgr); 3801457c4cbcSEric W. Biederman remove_proc_entry("pfkey", init_net.proc_net); 38021da177e4SLinus Torvalds sock_unregister(PF_KEY); 38031da177e4SLinus Torvalds proto_unregister(&key_proto); 38041da177e4SLinus Torvalds } 38051da177e4SLinus Torvalds 38061da177e4SLinus Torvalds static int __init ipsec_pfkey_init(void) 38071da177e4SLinus Torvalds { 38081da177e4SLinus Torvalds int err = proto_register(&key_proto, 0); 38091da177e4SLinus Torvalds 38101da177e4SLinus Torvalds if (err != 0) 38111da177e4SLinus Torvalds goto out; 38121da177e4SLinus Torvalds 38131da177e4SLinus Torvalds err = sock_register(&pfkey_family_ops); 38141da177e4SLinus Torvalds if (err != 0) 38151da177e4SLinus Torvalds goto out_unregister_key_proto; 38161da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 38171da177e4SLinus Torvalds err = -ENOMEM; 3818457c4cbcSEric W. Biederman if (create_proc_read_entry("pfkey", 0, init_net.proc_net, pfkey_read_proc, NULL) == NULL) 38191da177e4SLinus Torvalds goto out_sock_unregister; 38201da177e4SLinus Torvalds #endif 38211da177e4SLinus Torvalds err = xfrm_register_km(&pfkeyv2_mgr); 38221da177e4SLinus Torvalds if (err != 0) 38231da177e4SLinus Torvalds goto out_remove_proc_entry; 38241da177e4SLinus Torvalds out: 38251da177e4SLinus Torvalds return err; 38261da177e4SLinus Torvalds out_remove_proc_entry: 38271da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 38281da177e4SLinus Torvalds remove_proc_entry("net/pfkey", NULL); 38291da177e4SLinus Torvalds out_sock_unregister: 38301da177e4SLinus Torvalds #endif 38311da177e4SLinus Torvalds sock_unregister(PF_KEY); 38321da177e4SLinus Torvalds out_unregister_key_proto: 38331da177e4SLinus Torvalds proto_unregister(&key_proto); 38341da177e4SLinus Torvalds goto out; 38351da177e4SLinus Torvalds } 38361da177e4SLinus Torvalds 38371da177e4SLinus Torvalds module_init(ipsec_pfkey_init); 38381da177e4SLinus Torvalds module_exit(ipsec_pfkey_exit); 38391da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 38401da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_KEY); 3841