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> 291da177e4SLinus Torvalds #include <net/xfrm.h> 30161a09e7SJoy Latten #include <linux/audit.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 1391da177e4SLinus Torvalds static int pfkey_create(struct socket *sock, int protocol) 1401da177e4SLinus Torvalds { 1411da177e4SLinus Torvalds struct sock *sk; 1421da177e4SLinus Torvalds int err; 1431da177e4SLinus Torvalds 1441da177e4SLinus Torvalds if (!capable(CAP_NET_ADMIN)) 1451da177e4SLinus Torvalds return -EPERM; 1461da177e4SLinus Torvalds if (sock->type != SOCK_RAW) 1471da177e4SLinus Torvalds return -ESOCKTNOSUPPORT; 1481da177e4SLinus Torvalds if (protocol != PF_KEY_V2) 1491da177e4SLinus Torvalds return -EPROTONOSUPPORT; 1501da177e4SLinus Torvalds 1511da177e4SLinus Torvalds err = -ENOMEM; 1521da177e4SLinus Torvalds sk = sk_alloc(PF_KEY, GFP_KERNEL, &key_proto, 1); 1531da177e4SLinus Torvalds if (sk == NULL) 1541da177e4SLinus Torvalds goto out; 1551da177e4SLinus Torvalds 1561da177e4SLinus Torvalds sock->ops = &pfkey_ops; 1571da177e4SLinus Torvalds sock_init_data(sock, sk); 1581da177e4SLinus Torvalds 1591da177e4SLinus Torvalds sk->sk_family = PF_KEY; 1601da177e4SLinus Torvalds sk->sk_destruct = pfkey_sock_destruct; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds atomic_inc(&pfkey_socks_nr); 1631da177e4SLinus Torvalds 1641da177e4SLinus Torvalds pfkey_insert(sk); 1651da177e4SLinus Torvalds 1661da177e4SLinus Torvalds return 0; 1671da177e4SLinus Torvalds out: 1681da177e4SLinus Torvalds return err; 1691da177e4SLinus Torvalds } 1701da177e4SLinus Torvalds 1711da177e4SLinus Torvalds static int pfkey_release(struct socket *sock) 1721da177e4SLinus Torvalds { 1731da177e4SLinus Torvalds struct sock *sk = sock->sk; 1741da177e4SLinus Torvalds 1751da177e4SLinus Torvalds if (!sk) 1761da177e4SLinus Torvalds return 0; 1771da177e4SLinus Torvalds 1781da177e4SLinus Torvalds pfkey_remove(sk); 1791da177e4SLinus Torvalds 1801da177e4SLinus Torvalds sock_orphan(sk); 1811da177e4SLinus Torvalds sock->sk = NULL; 1821da177e4SLinus Torvalds skb_queue_purge(&sk->sk_write_queue); 1831da177e4SLinus Torvalds sock_put(sk); 1841da177e4SLinus Torvalds 1851da177e4SLinus Torvalds return 0; 1861da177e4SLinus Torvalds } 1871da177e4SLinus Torvalds 1881da177e4SLinus Torvalds static int pfkey_broadcast_one(struct sk_buff *skb, struct sk_buff **skb2, 189dd0fc66fSAl Viro gfp_t allocation, struct sock *sk) 1901da177e4SLinus Torvalds { 1911da177e4SLinus Torvalds int err = -ENOBUFS; 1921da177e4SLinus Torvalds 1931da177e4SLinus Torvalds sock_hold(sk); 1941da177e4SLinus Torvalds if (*skb2 == NULL) { 1951da177e4SLinus Torvalds if (atomic_read(&skb->users) != 1) { 1961da177e4SLinus Torvalds *skb2 = skb_clone(skb, allocation); 1971da177e4SLinus Torvalds } else { 1981da177e4SLinus Torvalds *skb2 = skb; 1991da177e4SLinus Torvalds atomic_inc(&skb->users); 2001da177e4SLinus Torvalds } 2011da177e4SLinus Torvalds } 2021da177e4SLinus Torvalds if (*skb2 != NULL) { 2031da177e4SLinus Torvalds if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) { 2041da177e4SLinus Torvalds skb_orphan(*skb2); 2051da177e4SLinus Torvalds skb_set_owner_r(*skb2, sk); 2061da177e4SLinus Torvalds skb_queue_tail(&sk->sk_receive_queue, *skb2); 2071da177e4SLinus Torvalds sk->sk_data_ready(sk, (*skb2)->len); 2081da177e4SLinus Torvalds *skb2 = NULL; 2091da177e4SLinus Torvalds err = 0; 2101da177e4SLinus Torvalds } 2111da177e4SLinus Torvalds } 2121da177e4SLinus Torvalds sock_put(sk); 2131da177e4SLinus Torvalds return err; 2141da177e4SLinus Torvalds } 2151da177e4SLinus Torvalds 2161da177e4SLinus Torvalds /* Send SKB to all pfkey sockets matching selected criteria. */ 2171da177e4SLinus Torvalds #define BROADCAST_ALL 0 2181da177e4SLinus Torvalds #define BROADCAST_ONE 1 2191da177e4SLinus Torvalds #define BROADCAST_REGISTERED 2 2201da177e4SLinus Torvalds #define BROADCAST_PROMISC_ONLY 4 221dd0fc66fSAl Viro static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation, 2221da177e4SLinus Torvalds int broadcast_flags, struct sock *one_sk) 2231da177e4SLinus Torvalds { 2241da177e4SLinus Torvalds struct sock *sk; 2251da177e4SLinus Torvalds struct hlist_node *node; 2261da177e4SLinus Torvalds struct sk_buff *skb2 = NULL; 2271da177e4SLinus Torvalds int err = -ESRCH; 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds /* XXX Do we need something like netlink_overrun? I think 2301da177e4SLinus Torvalds * XXX PF_KEY socket apps will not mind current behavior. 2311da177e4SLinus Torvalds */ 2321da177e4SLinus Torvalds if (!skb) 2331da177e4SLinus Torvalds return -ENOMEM; 2341da177e4SLinus Torvalds 2351da177e4SLinus Torvalds pfkey_lock_table(); 2361da177e4SLinus Torvalds sk_for_each(sk, node, &pfkey_table) { 2371da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 2381da177e4SLinus Torvalds int err2; 2391da177e4SLinus Torvalds 2401da177e4SLinus Torvalds /* Yes, it means that if you are meant to receive this 2411da177e4SLinus Torvalds * pfkey message you receive it twice as promiscuous 2421da177e4SLinus Torvalds * socket. 2431da177e4SLinus Torvalds */ 2441da177e4SLinus Torvalds if (pfk->promisc) 2451da177e4SLinus Torvalds pfkey_broadcast_one(skb, &skb2, allocation, sk); 2461da177e4SLinus Torvalds 2471da177e4SLinus Torvalds /* the exact target will be processed later */ 2481da177e4SLinus Torvalds if (sk == one_sk) 2491da177e4SLinus Torvalds continue; 2501da177e4SLinus Torvalds if (broadcast_flags != BROADCAST_ALL) { 2511da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_PROMISC_ONLY) 2521da177e4SLinus Torvalds continue; 2531da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && 2541da177e4SLinus Torvalds !pfk->registered) 2551da177e4SLinus Torvalds continue; 2561da177e4SLinus Torvalds if (broadcast_flags & BROADCAST_ONE) 2571da177e4SLinus Torvalds continue; 2581da177e4SLinus Torvalds } 2591da177e4SLinus Torvalds 2601da177e4SLinus Torvalds err2 = pfkey_broadcast_one(skb, &skb2, allocation, sk); 2611da177e4SLinus Torvalds 2621da177e4SLinus Torvalds /* Error is cleare after succecful sending to at least one 2631da177e4SLinus Torvalds * registered KM */ 2641da177e4SLinus Torvalds if ((broadcast_flags & BROADCAST_REGISTERED) && err) 2651da177e4SLinus Torvalds err = err2; 2661da177e4SLinus Torvalds } 2671da177e4SLinus Torvalds pfkey_unlock_table(); 2681da177e4SLinus Torvalds 2691da177e4SLinus Torvalds if (one_sk != NULL) 2701da177e4SLinus Torvalds err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk); 2711da177e4SLinus Torvalds 2721da177e4SLinus Torvalds if (skb2) 2731da177e4SLinus Torvalds kfree_skb(skb2); 2741da177e4SLinus Torvalds kfree_skb(skb); 2751da177e4SLinus Torvalds return err; 2761da177e4SLinus Torvalds } 2771da177e4SLinus Torvalds 2781da177e4SLinus Torvalds static inline void pfkey_hdr_dup(struct sadb_msg *new, struct sadb_msg *orig) 2791da177e4SLinus Torvalds { 2801da177e4SLinus Torvalds *new = *orig; 2811da177e4SLinus Torvalds } 2821da177e4SLinus Torvalds 2831da177e4SLinus Torvalds static int pfkey_error(struct sadb_msg *orig, int err, struct sock *sk) 2841da177e4SLinus Torvalds { 2851da177e4SLinus Torvalds struct sk_buff *skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_KERNEL); 2861da177e4SLinus Torvalds struct sadb_msg *hdr; 2871da177e4SLinus Torvalds 2881da177e4SLinus Torvalds if (!skb) 2891da177e4SLinus Torvalds return -ENOBUFS; 2901da177e4SLinus Torvalds 2911da177e4SLinus Torvalds /* Woe be to the platform trying to support PFKEY yet 2921da177e4SLinus Torvalds * having normal errnos outside the 1-255 range, inclusive. 2931da177e4SLinus Torvalds */ 2941da177e4SLinus Torvalds err = -err; 2951da177e4SLinus Torvalds if (err == ERESTARTSYS || 2961da177e4SLinus Torvalds err == ERESTARTNOHAND || 2971da177e4SLinus Torvalds err == ERESTARTNOINTR) 2981da177e4SLinus Torvalds err = EINTR; 2991da177e4SLinus Torvalds if (err >= 512) 3001da177e4SLinus Torvalds err = EINVAL; 30109a62660SKris Katterjohn BUG_ON(err <= 0 || err >= 256); 3021da177e4SLinus Torvalds 3031da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 3041da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 3051da177e4SLinus Torvalds hdr->sadb_msg_errno = (uint8_t) err; 3061da177e4SLinus Torvalds hdr->sadb_msg_len = (sizeof(struct sadb_msg) / 3071da177e4SLinus Torvalds sizeof(uint64_t)); 3081da177e4SLinus Torvalds 3091da177e4SLinus Torvalds pfkey_broadcast(skb, GFP_KERNEL, BROADCAST_ONE, sk); 3101da177e4SLinus Torvalds 3111da177e4SLinus Torvalds return 0; 3121da177e4SLinus Torvalds } 3131da177e4SLinus Torvalds 3141da177e4SLinus Torvalds static u8 sadb_ext_min_len[] = { 3151da177e4SLinus Torvalds [SADB_EXT_RESERVED] = (u8) 0, 3161da177e4SLinus Torvalds [SADB_EXT_SA] = (u8) sizeof(struct sadb_sa), 3171da177e4SLinus Torvalds [SADB_EXT_LIFETIME_CURRENT] = (u8) sizeof(struct sadb_lifetime), 3181da177e4SLinus Torvalds [SADB_EXT_LIFETIME_HARD] = (u8) sizeof(struct sadb_lifetime), 3191da177e4SLinus Torvalds [SADB_EXT_LIFETIME_SOFT] = (u8) sizeof(struct sadb_lifetime), 3201da177e4SLinus Torvalds [SADB_EXT_ADDRESS_SRC] = (u8) sizeof(struct sadb_address), 3211da177e4SLinus Torvalds [SADB_EXT_ADDRESS_DST] = (u8) sizeof(struct sadb_address), 3221da177e4SLinus Torvalds [SADB_EXT_ADDRESS_PROXY] = (u8) sizeof(struct sadb_address), 3231da177e4SLinus Torvalds [SADB_EXT_KEY_AUTH] = (u8) sizeof(struct sadb_key), 3241da177e4SLinus Torvalds [SADB_EXT_KEY_ENCRYPT] = (u8) sizeof(struct sadb_key), 3251da177e4SLinus Torvalds [SADB_EXT_IDENTITY_SRC] = (u8) sizeof(struct sadb_ident), 3261da177e4SLinus Torvalds [SADB_EXT_IDENTITY_DST] = (u8) sizeof(struct sadb_ident), 3271da177e4SLinus Torvalds [SADB_EXT_SENSITIVITY] = (u8) sizeof(struct sadb_sens), 3281da177e4SLinus Torvalds [SADB_EXT_PROPOSAL] = (u8) sizeof(struct sadb_prop), 3291da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_AUTH] = (u8) sizeof(struct sadb_supported), 3301da177e4SLinus Torvalds [SADB_EXT_SUPPORTED_ENCRYPT] = (u8) sizeof(struct sadb_supported), 3311da177e4SLinus Torvalds [SADB_EXT_SPIRANGE] = (u8) sizeof(struct sadb_spirange), 3321da177e4SLinus Torvalds [SADB_X_EXT_KMPRIVATE] = (u8) sizeof(struct sadb_x_kmprivate), 3331da177e4SLinus Torvalds [SADB_X_EXT_POLICY] = (u8) sizeof(struct sadb_x_policy), 3341da177e4SLinus Torvalds [SADB_X_EXT_SA2] = (u8) sizeof(struct sadb_x_sa2), 3351da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_TYPE] = (u8) sizeof(struct sadb_x_nat_t_type), 3361da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_SPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3371da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_DPORT] = (u8) sizeof(struct sadb_x_nat_t_port), 3381da177e4SLinus Torvalds [SADB_X_EXT_NAT_T_OA] = (u8) sizeof(struct sadb_address), 339df71837dSTrent Jaeger [SADB_X_EXT_SEC_CTX] = (u8) sizeof(struct sadb_x_sec_ctx), 3401da177e4SLinus Torvalds }; 3411da177e4SLinus Torvalds 3421da177e4SLinus Torvalds /* Verify sadb_address_{len,prefixlen} against sa_family. */ 3431da177e4SLinus Torvalds static int verify_address_len(void *p) 3441da177e4SLinus Torvalds { 3451da177e4SLinus Torvalds struct sadb_address *sp = p; 3461da177e4SLinus Torvalds struct sockaddr *addr = (struct sockaddr *)(sp + 1); 3471da177e4SLinus Torvalds struct sockaddr_in *sin; 3481da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3491da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 3501da177e4SLinus Torvalds #endif 3511da177e4SLinus Torvalds int len; 3521da177e4SLinus Torvalds 3531da177e4SLinus Torvalds switch (addr->sa_family) { 3541da177e4SLinus Torvalds case AF_INET: 3551da177e4SLinus Torvalds len = sizeof(*sp) + sizeof(*sin) + (sizeof(uint64_t) - 1); 3561da177e4SLinus Torvalds len /= sizeof(uint64_t); 3571da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3581da177e4SLinus Torvalds sp->sadb_address_prefixlen > 32) 3591da177e4SLinus Torvalds return -EINVAL; 3601da177e4SLinus Torvalds break; 3611da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 3621da177e4SLinus Torvalds case AF_INET6: 3631da177e4SLinus Torvalds len = sizeof(*sp) + sizeof(*sin6) + (sizeof(uint64_t) - 1); 3641da177e4SLinus Torvalds len /= sizeof(uint64_t); 3651da177e4SLinus Torvalds if (sp->sadb_address_len != len || 3661da177e4SLinus Torvalds sp->sadb_address_prefixlen > 128) 3671da177e4SLinus Torvalds return -EINVAL; 3681da177e4SLinus Torvalds break; 3691da177e4SLinus Torvalds #endif 3701da177e4SLinus Torvalds default: 3711da177e4SLinus Torvalds /* It is user using kernel to keep track of security 3721da177e4SLinus Torvalds * associations for another protocol, such as 3731da177e4SLinus Torvalds * OSPF/RSVP/RIPV2/MIP. It is user's job to verify 3741da177e4SLinus Torvalds * lengths. 3751da177e4SLinus Torvalds * 3761da177e4SLinus Torvalds * XXX Actually, association/policy database is not yet 3771da177e4SLinus Torvalds * XXX able to cope with arbitrary sockaddr families. 3781da177e4SLinus Torvalds * XXX When it can, remove this -EINVAL. -DaveM 3791da177e4SLinus Torvalds */ 3801da177e4SLinus Torvalds return -EINVAL; 3811da177e4SLinus Torvalds break; 3821da177e4SLinus Torvalds }; 3831da177e4SLinus Torvalds 3841da177e4SLinus Torvalds return 0; 3851da177e4SLinus Torvalds } 3861da177e4SLinus Torvalds 387df71837dSTrent Jaeger static inline int pfkey_sec_ctx_len(struct sadb_x_sec_ctx *sec_ctx) 388df71837dSTrent Jaeger { 389df71837dSTrent Jaeger int len = 0; 390df71837dSTrent Jaeger 391df71837dSTrent Jaeger len += sizeof(struct sadb_x_sec_ctx); 392df71837dSTrent Jaeger len += sec_ctx->sadb_x_ctx_len; 393df71837dSTrent Jaeger len += sizeof(uint64_t) - 1; 394df71837dSTrent Jaeger len /= sizeof(uint64_t); 395df71837dSTrent Jaeger 396df71837dSTrent Jaeger return len; 397df71837dSTrent Jaeger } 398df71837dSTrent Jaeger 399df71837dSTrent Jaeger static inline int verify_sec_ctx_len(void *p) 400df71837dSTrent Jaeger { 401df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx = (struct sadb_x_sec_ctx *)p; 402df71837dSTrent Jaeger int len; 403df71837dSTrent Jaeger 404df71837dSTrent Jaeger if (sec_ctx->sadb_x_ctx_len > PAGE_SIZE) 405df71837dSTrent Jaeger return -EINVAL; 406df71837dSTrent Jaeger 407df71837dSTrent Jaeger len = pfkey_sec_ctx_len(sec_ctx); 408df71837dSTrent Jaeger 409df71837dSTrent Jaeger if (sec_ctx->sadb_x_sec_len != len) 410df71837dSTrent Jaeger return -EINVAL; 411df71837dSTrent Jaeger 412df71837dSTrent Jaeger return 0; 413df71837dSTrent Jaeger } 414df71837dSTrent Jaeger 415df71837dSTrent Jaeger static inline struct xfrm_user_sec_ctx *pfkey_sadb2xfrm_user_sec_ctx(struct sadb_x_sec_ctx *sec_ctx) 416df71837dSTrent Jaeger { 417df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = NULL; 418df71837dSTrent Jaeger int ctx_size = sec_ctx->sadb_x_ctx_len; 419df71837dSTrent Jaeger 420df71837dSTrent Jaeger uctx = kmalloc((sizeof(*uctx)+ctx_size), GFP_KERNEL); 421df71837dSTrent Jaeger 422df71837dSTrent Jaeger if (!uctx) 423df71837dSTrent Jaeger return NULL; 424df71837dSTrent Jaeger 425df71837dSTrent Jaeger uctx->len = pfkey_sec_ctx_len(sec_ctx); 426df71837dSTrent Jaeger uctx->exttype = sec_ctx->sadb_x_sec_exttype; 427df71837dSTrent Jaeger uctx->ctx_doi = sec_ctx->sadb_x_ctx_doi; 428df71837dSTrent Jaeger uctx->ctx_alg = sec_ctx->sadb_x_ctx_alg; 429df71837dSTrent Jaeger uctx->ctx_len = sec_ctx->sadb_x_ctx_len; 430df71837dSTrent Jaeger memcpy(uctx + 1, sec_ctx + 1, 431df71837dSTrent Jaeger uctx->ctx_len); 432df71837dSTrent Jaeger 433df71837dSTrent Jaeger return uctx; 434df71837dSTrent Jaeger } 435df71837dSTrent Jaeger 4361da177e4SLinus Torvalds static int present_and_same_family(struct sadb_address *src, 4371da177e4SLinus Torvalds struct sadb_address *dst) 4381da177e4SLinus Torvalds { 4391da177e4SLinus Torvalds struct sockaddr *s_addr, *d_addr; 4401da177e4SLinus Torvalds 4411da177e4SLinus Torvalds if (!src || !dst) 4421da177e4SLinus Torvalds return 0; 4431da177e4SLinus Torvalds 4441da177e4SLinus Torvalds s_addr = (struct sockaddr *)(src + 1); 4451da177e4SLinus Torvalds d_addr = (struct sockaddr *)(dst + 1); 4461da177e4SLinus Torvalds if (s_addr->sa_family != d_addr->sa_family) 4471da177e4SLinus Torvalds return 0; 4481da177e4SLinus Torvalds if (s_addr->sa_family != AF_INET 4491da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 4501da177e4SLinus Torvalds && s_addr->sa_family != AF_INET6 4511da177e4SLinus Torvalds #endif 4521da177e4SLinus Torvalds ) 4531da177e4SLinus Torvalds return 0; 4541da177e4SLinus Torvalds 4551da177e4SLinus Torvalds return 1; 4561da177e4SLinus Torvalds } 4571da177e4SLinus Torvalds 4581da177e4SLinus Torvalds static int parse_exthdrs(struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 4591da177e4SLinus Torvalds { 4601da177e4SLinus Torvalds char *p = (char *) hdr; 4611da177e4SLinus Torvalds int len = skb->len; 4621da177e4SLinus Torvalds 4631da177e4SLinus Torvalds len -= sizeof(*hdr); 4641da177e4SLinus Torvalds p += sizeof(*hdr); 4651da177e4SLinus Torvalds while (len > 0) { 4661da177e4SLinus Torvalds struct sadb_ext *ehdr = (struct sadb_ext *) p; 4671da177e4SLinus Torvalds uint16_t ext_type; 4681da177e4SLinus Torvalds int ext_len; 4691da177e4SLinus Torvalds 4701da177e4SLinus Torvalds ext_len = ehdr->sadb_ext_len; 4711da177e4SLinus Torvalds ext_len *= sizeof(uint64_t); 4721da177e4SLinus Torvalds ext_type = ehdr->sadb_ext_type; 4731da177e4SLinus Torvalds if (ext_len < sizeof(uint64_t) || 4741da177e4SLinus Torvalds ext_len > len || 4751da177e4SLinus Torvalds ext_type == SADB_EXT_RESERVED) 4761da177e4SLinus Torvalds return -EINVAL; 4771da177e4SLinus Torvalds 4781da177e4SLinus Torvalds if (ext_type <= SADB_EXT_MAX) { 4791da177e4SLinus Torvalds int min = (int) sadb_ext_min_len[ext_type]; 4801da177e4SLinus Torvalds if (ext_len < min) 4811da177e4SLinus Torvalds return -EINVAL; 4821da177e4SLinus Torvalds if (ext_hdrs[ext_type-1] != NULL) 4831da177e4SLinus Torvalds return -EINVAL; 4841da177e4SLinus Torvalds if (ext_type == SADB_EXT_ADDRESS_SRC || 4851da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_DST || 4861da177e4SLinus Torvalds ext_type == SADB_EXT_ADDRESS_PROXY || 4871da177e4SLinus Torvalds ext_type == SADB_X_EXT_NAT_T_OA) { 4881da177e4SLinus Torvalds if (verify_address_len(p)) 4891da177e4SLinus Torvalds return -EINVAL; 4901da177e4SLinus Torvalds } 491df71837dSTrent Jaeger if (ext_type == SADB_X_EXT_SEC_CTX) { 492df71837dSTrent Jaeger if (verify_sec_ctx_len(p)) 493df71837dSTrent Jaeger return -EINVAL; 494df71837dSTrent Jaeger } 4951da177e4SLinus Torvalds ext_hdrs[ext_type-1] = p; 4961da177e4SLinus Torvalds } 4971da177e4SLinus Torvalds p += ext_len; 4981da177e4SLinus Torvalds len -= ext_len; 4991da177e4SLinus Torvalds } 5001da177e4SLinus Torvalds 5011da177e4SLinus Torvalds return 0; 5021da177e4SLinus Torvalds } 5031da177e4SLinus Torvalds 5041da177e4SLinus Torvalds static uint16_t 5051da177e4SLinus Torvalds pfkey_satype2proto(uint8_t satype) 5061da177e4SLinus Torvalds { 5071da177e4SLinus Torvalds switch (satype) { 5081da177e4SLinus Torvalds case SADB_SATYPE_UNSPEC: 5091da177e4SLinus Torvalds return IPSEC_PROTO_ANY; 5101da177e4SLinus Torvalds case SADB_SATYPE_AH: 5111da177e4SLinus Torvalds return IPPROTO_AH; 5121da177e4SLinus Torvalds case SADB_SATYPE_ESP: 5131da177e4SLinus Torvalds return IPPROTO_ESP; 5141da177e4SLinus Torvalds case SADB_X_SATYPE_IPCOMP: 5151da177e4SLinus Torvalds return IPPROTO_COMP; 5161da177e4SLinus Torvalds break; 5171da177e4SLinus Torvalds default: 5181da177e4SLinus Torvalds return 0; 5191da177e4SLinus Torvalds } 5201da177e4SLinus Torvalds /* NOTREACHED */ 5211da177e4SLinus Torvalds } 5221da177e4SLinus Torvalds 5231da177e4SLinus Torvalds static uint8_t 5241da177e4SLinus Torvalds pfkey_proto2satype(uint16_t proto) 5251da177e4SLinus Torvalds { 5261da177e4SLinus Torvalds switch (proto) { 5271da177e4SLinus Torvalds case IPPROTO_AH: 5281da177e4SLinus Torvalds return SADB_SATYPE_AH; 5291da177e4SLinus Torvalds case IPPROTO_ESP: 5301da177e4SLinus Torvalds return SADB_SATYPE_ESP; 5311da177e4SLinus Torvalds case IPPROTO_COMP: 5321da177e4SLinus Torvalds return SADB_X_SATYPE_IPCOMP; 5331da177e4SLinus Torvalds break; 5341da177e4SLinus Torvalds default: 5351da177e4SLinus Torvalds return 0; 5361da177e4SLinus Torvalds } 5371da177e4SLinus Torvalds /* NOTREACHED */ 5381da177e4SLinus Torvalds } 5391da177e4SLinus Torvalds 5401da177e4SLinus Torvalds /* BTW, this scheme means that there is no way with PFKEY2 sockets to 5411da177e4SLinus Torvalds * say specifically 'just raw sockets' as we encode them as 255. 5421da177e4SLinus Torvalds */ 5431da177e4SLinus Torvalds 5441da177e4SLinus Torvalds static uint8_t pfkey_proto_to_xfrm(uint8_t proto) 5451da177e4SLinus Torvalds { 5461da177e4SLinus Torvalds return (proto == IPSEC_PROTO_ANY ? 0 : proto); 5471da177e4SLinus Torvalds } 5481da177e4SLinus Torvalds 5491da177e4SLinus Torvalds static uint8_t pfkey_proto_from_xfrm(uint8_t proto) 5501da177e4SLinus Torvalds { 5511da177e4SLinus Torvalds return (proto ? proto : IPSEC_PROTO_ANY); 5521da177e4SLinus Torvalds } 5531da177e4SLinus Torvalds 5541da177e4SLinus Torvalds static int pfkey_sadb_addr2xfrm_addr(struct sadb_address *addr, 5551da177e4SLinus Torvalds xfrm_address_t *xaddr) 5561da177e4SLinus Torvalds { 5571da177e4SLinus Torvalds switch (((struct sockaddr*)(addr + 1))->sa_family) { 5581da177e4SLinus Torvalds case AF_INET: 5591da177e4SLinus Torvalds xaddr->a4 = 5601da177e4SLinus Torvalds ((struct sockaddr_in *)(addr + 1))->sin_addr.s_addr; 5611da177e4SLinus Torvalds return AF_INET; 5621da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 5631da177e4SLinus Torvalds case AF_INET6: 5641da177e4SLinus Torvalds memcpy(xaddr->a6, 5651da177e4SLinus Torvalds &((struct sockaddr_in6 *)(addr + 1))->sin6_addr, 5661da177e4SLinus Torvalds sizeof(struct in6_addr)); 5671da177e4SLinus Torvalds return AF_INET6; 5681da177e4SLinus Torvalds #endif 5691da177e4SLinus Torvalds default: 5701da177e4SLinus Torvalds return 0; 5711da177e4SLinus Torvalds } 5721da177e4SLinus Torvalds /* NOTREACHED */ 5731da177e4SLinus Torvalds } 5741da177e4SLinus Torvalds 5751da177e4SLinus Torvalds static struct xfrm_state *pfkey_xfrm_state_lookup(struct sadb_msg *hdr, void **ext_hdrs) 5761da177e4SLinus Torvalds { 5771da177e4SLinus Torvalds struct sadb_sa *sa; 5781da177e4SLinus Torvalds struct sadb_address *addr; 5791da177e4SLinus Torvalds uint16_t proto; 5801da177e4SLinus Torvalds unsigned short family; 5811da177e4SLinus Torvalds xfrm_address_t *xaddr; 5821da177e4SLinus Torvalds 5831da177e4SLinus Torvalds sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 5841da177e4SLinus Torvalds if (sa == NULL) 5851da177e4SLinus Torvalds return NULL; 5861da177e4SLinus Torvalds 5871da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 5881da177e4SLinus Torvalds if (proto == 0) 5891da177e4SLinus Torvalds return NULL; 5901da177e4SLinus Torvalds 5911da177e4SLinus Torvalds /* sadb_address_len should be checked by caller */ 5921da177e4SLinus Torvalds addr = (struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 5931da177e4SLinus Torvalds if (addr == NULL) 5941da177e4SLinus Torvalds return NULL; 5951da177e4SLinus Torvalds 5961da177e4SLinus Torvalds family = ((struct sockaddr *)(addr + 1))->sa_family; 5971da177e4SLinus Torvalds switch (family) { 5981da177e4SLinus Torvalds case AF_INET: 5991da177e4SLinus Torvalds xaddr = (xfrm_address_t *)&((struct sockaddr_in *)(addr + 1))->sin_addr; 6001da177e4SLinus Torvalds break; 6011da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6021da177e4SLinus Torvalds case AF_INET6: 6031da177e4SLinus Torvalds xaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(addr + 1))->sin6_addr; 6041da177e4SLinus Torvalds break; 6051da177e4SLinus Torvalds #endif 6061da177e4SLinus Torvalds default: 6071da177e4SLinus Torvalds xaddr = NULL; 6081da177e4SLinus Torvalds } 6091da177e4SLinus Torvalds 6101da177e4SLinus Torvalds if (!xaddr) 6111da177e4SLinus Torvalds return NULL; 6121da177e4SLinus Torvalds 6131da177e4SLinus Torvalds return xfrm_state_lookup(xaddr, sa->sadb_sa_spi, proto, family); 6141da177e4SLinus Torvalds } 6151da177e4SLinus Torvalds 6161da177e4SLinus Torvalds #define PFKEY_ALIGN8(a) (1 + (((a) - 1) | (8 - 1))) 6171da177e4SLinus Torvalds static int 6181da177e4SLinus Torvalds pfkey_sockaddr_size(sa_family_t family) 6191da177e4SLinus Torvalds { 6201da177e4SLinus Torvalds switch (family) { 6211da177e4SLinus Torvalds case AF_INET: 6221da177e4SLinus Torvalds return PFKEY_ALIGN8(sizeof(struct sockaddr_in)); 6231da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6241da177e4SLinus Torvalds case AF_INET6: 6251da177e4SLinus Torvalds return PFKEY_ALIGN8(sizeof(struct sockaddr_in6)); 6261da177e4SLinus Torvalds #endif 6271da177e4SLinus Torvalds default: 6281da177e4SLinus Torvalds return 0; 6291da177e4SLinus Torvalds } 6301da177e4SLinus Torvalds /* NOTREACHED */ 6311da177e4SLinus Torvalds } 6321da177e4SLinus Torvalds 63355569ce2SKazunori MIYAZAWA static inline int pfkey_mode_from_xfrm(int mode) 63455569ce2SKazunori MIYAZAWA { 63555569ce2SKazunori MIYAZAWA switch(mode) { 63655569ce2SKazunori MIYAZAWA case XFRM_MODE_TRANSPORT: 63755569ce2SKazunori MIYAZAWA return IPSEC_MODE_TRANSPORT; 63855569ce2SKazunori MIYAZAWA case XFRM_MODE_TUNNEL: 63955569ce2SKazunori MIYAZAWA return IPSEC_MODE_TUNNEL; 64055569ce2SKazunori MIYAZAWA case XFRM_MODE_BEET: 64155569ce2SKazunori MIYAZAWA return IPSEC_MODE_BEET; 64255569ce2SKazunori MIYAZAWA default: 64355569ce2SKazunori MIYAZAWA return -1; 64455569ce2SKazunori MIYAZAWA } 64555569ce2SKazunori MIYAZAWA } 64655569ce2SKazunori MIYAZAWA 64755569ce2SKazunori MIYAZAWA static inline int pfkey_mode_to_xfrm(int mode) 64855569ce2SKazunori MIYAZAWA { 64955569ce2SKazunori MIYAZAWA switch(mode) { 65055569ce2SKazunori MIYAZAWA case IPSEC_MODE_ANY: /*XXX*/ 65155569ce2SKazunori MIYAZAWA case IPSEC_MODE_TRANSPORT: 65255569ce2SKazunori MIYAZAWA return XFRM_MODE_TRANSPORT; 65355569ce2SKazunori MIYAZAWA case IPSEC_MODE_TUNNEL: 65455569ce2SKazunori MIYAZAWA return XFRM_MODE_TUNNEL; 65555569ce2SKazunori MIYAZAWA case IPSEC_MODE_BEET: 65655569ce2SKazunori MIYAZAWA return XFRM_MODE_BEET; 65755569ce2SKazunori MIYAZAWA default: 65855569ce2SKazunori MIYAZAWA return -1; 65955569ce2SKazunori MIYAZAWA } 66055569ce2SKazunori MIYAZAWA } 66155569ce2SKazunori MIYAZAWA 6621da177e4SLinus Torvalds static struct sk_buff * pfkey_xfrm_state2msg(struct xfrm_state *x, int add_keys, int hsc) 6631da177e4SLinus Torvalds { 6641da177e4SLinus Torvalds struct sk_buff *skb; 6651da177e4SLinus Torvalds struct sadb_msg *hdr; 6661da177e4SLinus Torvalds struct sadb_sa *sa; 6671da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 6681da177e4SLinus Torvalds struct sadb_address *addr; 6691da177e4SLinus Torvalds struct sadb_key *key; 6701da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 6711da177e4SLinus Torvalds struct sockaddr_in *sin; 672df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 673df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 674df71837dSTrent Jaeger int ctx_size = 0; 6751da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 6761da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 6771da177e4SLinus Torvalds #endif 6781da177e4SLinus Torvalds int size; 6791da177e4SLinus Torvalds int auth_key_size = 0; 6801da177e4SLinus Torvalds int encrypt_key_size = 0; 6811da177e4SLinus Torvalds int sockaddr_size; 6821da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 68355569ce2SKazunori MIYAZAWA int mode; 6841da177e4SLinus Torvalds 6851da177e4SLinus Torvalds /* address family check */ 6861da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 6871da177e4SLinus Torvalds if (!sockaddr_size) 6881da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 6891da177e4SLinus Torvalds 6901da177e4SLinus Torvalds /* base, SA, (lifetime (HSC),) address(SD), (address(P),) 6911da177e4SLinus Torvalds key(AE), (identity(SD),) (sensitivity)> */ 6921da177e4SLinus Torvalds size = sizeof(struct sadb_msg) +sizeof(struct sadb_sa) + 6931da177e4SLinus Torvalds sizeof(struct sadb_lifetime) + 6941da177e4SLinus Torvalds ((hsc & 1) ? sizeof(struct sadb_lifetime) : 0) + 6951da177e4SLinus Torvalds ((hsc & 2) ? sizeof(struct sadb_lifetime) : 0) + 6961da177e4SLinus Torvalds sizeof(struct sadb_address)*2 + 6971da177e4SLinus Torvalds sockaddr_size*2 + 6981da177e4SLinus Torvalds sizeof(struct sadb_x_sa2); 699df71837dSTrent Jaeger 700df71837dSTrent Jaeger if ((xfrm_ctx = x->security)) { 701df71837dSTrent Jaeger ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 702df71837dSTrent Jaeger size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 703df71837dSTrent Jaeger } 704df71837dSTrent Jaeger 7051da177e4SLinus Torvalds /* identity & sensitivity */ 7061da177e4SLinus Torvalds 7071da177e4SLinus Torvalds if ((x->props.family == AF_INET && 7081da177e4SLinus Torvalds x->sel.saddr.a4 != x->props.saddr.a4) 7091da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 7101da177e4SLinus Torvalds || (x->props.family == AF_INET6 && 7111da177e4SLinus Torvalds memcmp (x->sel.saddr.a6, x->props.saddr.a6, sizeof (struct in6_addr))) 7121da177e4SLinus Torvalds #endif 7131da177e4SLinus Torvalds ) 7141da177e4SLinus Torvalds size += sizeof(struct sadb_address) + sockaddr_size; 7151da177e4SLinus Torvalds 7161da177e4SLinus Torvalds if (add_keys) { 7171da177e4SLinus Torvalds if (x->aalg && x->aalg->alg_key_len) { 7181da177e4SLinus Torvalds auth_key_size = 7191da177e4SLinus Torvalds PFKEY_ALIGN8((x->aalg->alg_key_len + 7) / 8); 7201da177e4SLinus Torvalds size += sizeof(struct sadb_key) + auth_key_size; 7211da177e4SLinus Torvalds } 7221da177e4SLinus Torvalds if (x->ealg && x->ealg->alg_key_len) { 7231da177e4SLinus Torvalds encrypt_key_size = 7241da177e4SLinus Torvalds PFKEY_ALIGN8((x->ealg->alg_key_len+7) / 8); 7251da177e4SLinus Torvalds size += sizeof(struct sadb_key) + encrypt_key_size; 7261da177e4SLinus Torvalds } 7271da177e4SLinus Torvalds } 7281da177e4SLinus Torvalds if (x->encap) 7291da177e4SLinus Torvalds natt = x->encap; 7301da177e4SLinus Torvalds 7311da177e4SLinus Torvalds if (natt && natt->encap_type) { 7321da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_type); 7331da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7341da177e4SLinus Torvalds size += sizeof(struct sadb_x_nat_t_port); 7351da177e4SLinus Torvalds } 7361da177e4SLinus Torvalds 7371da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 7381da177e4SLinus Torvalds if (skb == NULL) 7391da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 7401da177e4SLinus Torvalds 7411da177e4SLinus Torvalds /* call should fill header later */ 7421da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 7431da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 7441da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 7451da177e4SLinus Torvalds 7461da177e4SLinus Torvalds /* sa */ 7471da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 7481da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 7491da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 7501da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 7511da177e4SLinus Torvalds sa->sadb_sa_replay = x->props.replay_window; 7524f09f0bbSHerbert Xu switch (x->km.state) { 7534f09f0bbSHerbert Xu case XFRM_STATE_VALID: 7544f09f0bbSHerbert Xu sa->sadb_sa_state = x->km.dying ? 7554f09f0bbSHerbert Xu SADB_SASTATE_DYING : SADB_SASTATE_MATURE; 7564f09f0bbSHerbert Xu break; 7574f09f0bbSHerbert Xu case XFRM_STATE_ACQ: 7581da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_LARVAL; 7594f09f0bbSHerbert Xu break; 7604f09f0bbSHerbert Xu default: 7611da177e4SLinus Torvalds sa->sadb_sa_state = SADB_SASTATE_DEAD; 7624f09f0bbSHerbert Xu break; 7634f09f0bbSHerbert Xu } 7641da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 7651da177e4SLinus Torvalds if (x->aalg) { 7661da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byname(x->aalg->alg_name, 0); 7671da177e4SLinus Torvalds sa->sadb_sa_auth = a ? a->desc.sadb_alg_id : 0; 7681da177e4SLinus Torvalds } 7691da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 7701da177e4SLinus Torvalds BUG_ON(x->ealg && x->calg); 7711da177e4SLinus Torvalds if (x->ealg) { 7721da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byname(x->ealg->alg_name, 0); 7731da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 7741da177e4SLinus Torvalds } 7751da177e4SLinus Torvalds /* KAME compatible: sadb_sa_encrypt is overloaded with calg id */ 7761da177e4SLinus Torvalds if (x->calg) { 7771da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byname(x->calg->alg_name, 0); 7781da177e4SLinus Torvalds sa->sadb_sa_encrypt = a ? a->desc.sadb_alg_id : 0; 7791da177e4SLinus Torvalds } 7801da177e4SLinus Torvalds 7811da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 7821da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_NOECN) 7831da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_NOECN; 7841da177e4SLinus Torvalds if (x->props.flags & XFRM_STATE_DECAP_DSCP) 7851da177e4SLinus Torvalds sa->sadb_sa_flags |= SADB_SAFLAGS_DECAP_DSCP; 786dd87147eSHerbert Xu if (x->props.flags & XFRM_STATE_NOPMTUDISC) 787dd87147eSHerbert Xu sa->sadb_sa_flags |= SADB_SAFLAGS_NOPMTUDISC; 7881da177e4SLinus Torvalds 7891da177e4SLinus Torvalds /* hard time */ 7901da177e4SLinus Torvalds if (hsc & 2) { 7911da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 7921da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 7931da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 7941da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 7951da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 7961da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.hard_packet_limit); 7971da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.hard_byte_limit); 7981da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.hard_add_expires_seconds; 7991da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.hard_use_expires_seconds; 8001da177e4SLinus Torvalds } 8011da177e4SLinus Torvalds /* soft time */ 8021da177e4SLinus Torvalds if (hsc & 1) { 8031da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8041da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8051da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8061da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8071da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 8081da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(x->lft.soft_packet_limit); 8091da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(x->lft.soft_byte_limit); 8101da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->lft.soft_add_expires_seconds; 8111da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->lft.soft_use_expires_seconds; 8121da177e4SLinus Torvalds } 8131da177e4SLinus Torvalds /* current time */ 8141da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 8151da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 8161da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 8171da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 8181da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 8191da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = x->curlft.packets; 8201da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = x->curlft.bytes; 8211da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = x->curlft.add_time; 8221da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = x->curlft.use_time; 8231da177e4SLinus Torvalds /* src address */ 8241da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8251da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8261da177e4SLinus Torvalds addr->sadb_address_len = 8271da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8281da177e4SLinus Torvalds sizeof(uint64_t); 8291da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 8301da177e4SLinus Torvalds /* "if the ports are non-zero, then the sadb_address_proto field, 8311da177e4SLinus Torvalds normally zero, MUST be filled in with the transport 8321da177e4SLinus Torvalds protocol's number." - RFC2367 */ 8331da177e4SLinus Torvalds addr->sadb_address_proto = 0; 8341da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8351da177e4SLinus Torvalds if (x->props.family == AF_INET) { 8361da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 8371da177e4SLinus Torvalds 8381da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8391da177e4SLinus Torvalds sin->sin_family = AF_INET; 8401da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 8411da177e4SLinus Torvalds sin->sin_port = 0; 8421da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8431da177e4SLinus Torvalds } 8441da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 8451da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 8461da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 8471da177e4SLinus Torvalds 8481da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 8491da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 8501da177e4SLinus Torvalds sin6->sin6_port = 0; 8511da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 8521da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->props.saddr.a6, 8531da177e4SLinus Torvalds sizeof(struct in6_addr)); 8541da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds #endif 8571da177e4SLinus Torvalds else 8581da177e4SLinus Torvalds BUG(); 8591da177e4SLinus Torvalds 8601da177e4SLinus Torvalds /* dst address */ 8611da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8621da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8631da177e4SLinus Torvalds addr->sadb_address_len = 8641da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8651da177e4SLinus Torvalds sizeof(uint64_t); 8661da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 8671da177e4SLinus Torvalds addr->sadb_address_proto = 0; 8681da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; /* XXX */ 8691da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8701da177e4SLinus Torvalds if (x->props.family == AF_INET) { 8711da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8721da177e4SLinus Torvalds sin->sin_family = AF_INET; 8731da177e4SLinus Torvalds sin->sin_addr.s_addr = x->id.daddr.a4; 8741da177e4SLinus Torvalds sin->sin_port = 0; 8751da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8761da177e4SLinus Torvalds 8771da177e4SLinus Torvalds if (x->sel.saddr.a4 != x->props.saddr.a4) { 8781da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 8791da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 8801da177e4SLinus Torvalds addr->sadb_address_len = 8811da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 8821da177e4SLinus Torvalds sizeof(uint64_t); 8831da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 8841da177e4SLinus Torvalds addr->sadb_address_proto = 8851da177e4SLinus Torvalds pfkey_proto_from_xfrm(x->sel.proto); 8861da177e4SLinus Torvalds addr->sadb_address_prefixlen = x->sel.prefixlen_s; 8871da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 8881da177e4SLinus Torvalds 8891da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 8901da177e4SLinus Torvalds sin->sin_family = AF_INET; 8911da177e4SLinus Torvalds sin->sin_addr.s_addr = x->sel.saddr.a4; 8921da177e4SLinus Torvalds sin->sin_port = x->sel.sport; 8931da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 8941da177e4SLinus Torvalds } 8951da177e4SLinus Torvalds } 8961da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 8971da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 8981da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 8991da177e4SLinus Torvalds 9001da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 9011da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 9021da177e4SLinus Torvalds sin6->sin6_port = 0; 9031da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 9041da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->id.daddr.a6, sizeof(struct in6_addr)); 9051da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 9061da177e4SLinus Torvalds 9071da177e4SLinus Torvalds if (memcmp (x->sel.saddr.a6, x->props.saddr.a6, 9081da177e4SLinus Torvalds sizeof(struct in6_addr))) { 9091da177e4SLinus Torvalds addr = (struct sadb_address *) skb_put(skb, 9101da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 9111da177e4SLinus Torvalds addr->sadb_address_len = 9121da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 9131da177e4SLinus Torvalds sizeof(uint64_t); 9141da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_PROXY; 9151da177e4SLinus Torvalds addr->sadb_address_proto = 9161da177e4SLinus Torvalds pfkey_proto_from_xfrm(x->sel.proto); 9171da177e4SLinus Torvalds addr->sadb_address_prefixlen = x->sel.prefixlen_s; 9181da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 9191da177e4SLinus Torvalds 9201da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 9211da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 9221da177e4SLinus Torvalds sin6->sin6_port = x->sel.sport; 9231da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 9241da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, x->sel.saddr.a6, 9251da177e4SLinus Torvalds sizeof(struct in6_addr)); 9261da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 9271da177e4SLinus Torvalds } 9281da177e4SLinus Torvalds } 9291da177e4SLinus Torvalds #endif 9301da177e4SLinus Torvalds else 9311da177e4SLinus Torvalds BUG(); 9321da177e4SLinus Torvalds 9331da177e4SLinus Torvalds /* auth key */ 9341da177e4SLinus Torvalds if (add_keys && auth_key_size) { 9351da177e4SLinus Torvalds key = (struct sadb_key *) skb_put(skb, 9361da177e4SLinus Torvalds sizeof(struct sadb_key)+auth_key_size); 9371da177e4SLinus Torvalds key->sadb_key_len = (sizeof(struct sadb_key) + auth_key_size) / 9381da177e4SLinus Torvalds sizeof(uint64_t); 9391da177e4SLinus Torvalds key->sadb_key_exttype = SADB_EXT_KEY_AUTH; 9401da177e4SLinus Torvalds key->sadb_key_bits = x->aalg->alg_key_len; 9411da177e4SLinus Torvalds key->sadb_key_reserved = 0; 9421da177e4SLinus Torvalds memcpy(key + 1, x->aalg->alg_key, (x->aalg->alg_key_len+7)/8); 9431da177e4SLinus Torvalds } 9441da177e4SLinus Torvalds /* encrypt key */ 9451da177e4SLinus Torvalds if (add_keys && encrypt_key_size) { 9461da177e4SLinus Torvalds key = (struct sadb_key *) skb_put(skb, 9471da177e4SLinus Torvalds sizeof(struct sadb_key)+encrypt_key_size); 9481da177e4SLinus Torvalds key->sadb_key_len = (sizeof(struct sadb_key) + 9491da177e4SLinus Torvalds encrypt_key_size) / sizeof(uint64_t); 9501da177e4SLinus Torvalds key->sadb_key_exttype = SADB_EXT_KEY_ENCRYPT; 9511da177e4SLinus Torvalds key->sadb_key_bits = x->ealg->alg_key_len; 9521da177e4SLinus Torvalds key->sadb_key_reserved = 0; 9531da177e4SLinus Torvalds memcpy(key + 1, x->ealg->alg_key, 9541da177e4SLinus Torvalds (x->ealg->alg_key_len+7)/8); 9551da177e4SLinus Torvalds } 9561da177e4SLinus Torvalds 9571da177e4SLinus Torvalds /* sa */ 9581da177e4SLinus Torvalds sa2 = (struct sadb_x_sa2 *) skb_put(skb, sizeof(struct sadb_x_sa2)); 9591da177e4SLinus Torvalds sa2->sadb_x_sa2_len = sizeof(struct sadb_x_sa2)/sizeof(uint64_t); 9601da177e4SLinus Torvalds sa2->sadb_x_sa2_exttype = SADB_X_EXT_SA2; 96155569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_from_xfrm(x->props.mode)) < 0) { 96255569ce2SKazunori MIYAZAWA kfree_skb(skb); 96355569ce2SKazunori MIYAZAWA return ERR_PTR(-EINVAL); 96455569ce2SKazunori MIYAZAWA } 96555569ce2SKazunori MIYAZAWA sa2->sadb_x_sa2_mode = mode; 9661da177e4SLinus Torvalds sa2->sadb_x_sa2_reserved1 = 0; 9671da177e4SLinus Torvalds sa2->sadb_x_sa2_reserved2 = 0; 9681da177e4SLinus Torvalds sa2->sadb_x_sa2_sequence = 0; 9691da177e4SLinus Torvalds sa2->sadb_x_sa2_reqid = x->props.reqid; 9701da177e4SLinus Torvalds 9711da177e4SLinus Torvalds if (natt && natt->encap_type) { 9721da177e4SLinus Torvalds struct sadb_x_nat_t_type *n_type; 9731da177e4SLinus Torvalds struct sadb_x_nat_t_port *n_port; 9741da177e4SLinus Torvalds 9751da177e4SLinus Torvalds /* type */ 9761da177e4SLinus Torvalds n_type = (struct sadb_x_nat_t_type*) skb_put(skb, sizeof(*n_type)); 9771da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_len = sizeof(*n_type)/sizeof(uint64_t); 9781da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_exttype = SADB_X_EXT_NAT_T_TYPE; 9791da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_type = natt->encap_type; 9801da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[0] = 0; 9811da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[1] = 0; 9821da177e4SLinus Torvalds n_type->sadb_x_nat_t_type_reserved[2] = 0; 9831da177e4SLinus Torvalds 9841da177e4SLinus Torvalds /* source port */ 9851da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 9861da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 9871da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; 9881da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_sport; 9891da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 9901da177e4SLinus Torvalds 9911da177e4SLinus Torvalds /* dest port */ 9921da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 9931da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 9941da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; 9951da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_dport; 9961da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 9971da177e4SLinus Torvalds } 9981da177e4SLinus Torvalds 999df71837dSTrent Jaeger /* security context */ 1000df71837dSTrent Jaeger if (xfrm_ctx) { 1001df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, 1002df71837dSTrent Jaeger sizeof(struct sadb_x_sec_ctx) + ctx_size); 1003df71837dSTrent Jaeger sec_ctx->sadb_x_sec_len = 1004df71837dSTrent Jaeger (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); 1005df71837dSTrent Jaeger sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 1006df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 1007df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 1008df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 1009df71837dSTrent Jaeger memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 1010df71837dSTrent Jaeger xfrm_ctx->ctx_len); 1011df71837dSTrent Jaeger } 1012df71837dSTrent Jaeger 10131da177e4SLinus Torvalds return skb; 10141da177e4SLinus Torvalds } 10151da177e4SLinus Torvalds 10161da177e4SLinus Torvalds static struct xfrm_state * pfkey_msg2xfrm_state(struct sadb_msg *hdr, 10171da177e4SLinus Torvalds void **ext_hdrs) 10181da177e4SLinus Torvalds { 10191da177e4SLinus Torvalds struct xfrm_state *x; 10201da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 10211da177e4SLinus Torvalds struct sadb_sa *sa; 10221da177e4SLinus Torvalds struct sadb_key *key; 1023df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 10241da177e4SLinus Torvalds uint16_t proto; 10251da177e4SLinus Torvalds int err; 10261da177e4SLinus Torvalds 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds sa = (struct sadb_sa *) ext_hdrs[SADB_EXT_SA-1]; 10291da177e4SLinus Torvalds if (!sa || 10301da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 10311da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 10321da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10331da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_ESP && 10341da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]) 10351da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10361da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_SATYPE_AH && 10371da177e4SLinus Torvalds !ext_hdrs[SADB_EXT_KEY_AUTH-1]) 10381da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10391da177e4SLinus Torvalds if (!!ext_hdrs[SADB_EXT_LIFETIME_HARD-1] != 10401da177e4SLinus Torvalds !!ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) 10411da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10421da177e4SLinus Torvalds 10431da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 10441da177e4SLinus Torvalds if (proto == 0) 10451da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10461da177e4SLinus Torvalds 10471da177e4SLinus Torvalds /* default error is no buffer space */ 10481da177e4SLinus Torvalds err = -ENOBUFS; 10491da177e4SLinus Torvalds 10501da177e4SLinus Torvalds /* RFC2367: 10511da177e4SLinus Torvalds 10521da177e4SLinus Torvalds Only SADB_SASTATE_MATURE SAs may be submitted in an SADB_ADD message. 10531da177e4SLinus Torvalds SADB_SASTATE_LARVAL SAs are created by SADB_GETSPI and it is not 10541da177e4SLinus Torvalds sensible to add a new SA in the DYING or SADB_SASTATE_DEAD state. 10551da177e4SLinus Torvalds Therefore, the sadb_sa_state field of all submitted SAs MUST be 10561da177e4SLinus Torvalds SADB_SASTATE_MATURE and the kernel MUST return an error if this is 10571da177e4SLinus Torvalds not true. 10581da177e4SLinus Torvalds 10591da177e4SLinus Torvalds However, KAME setkey always uses SADB_SASTATE_LARVAL. 10601da177e4SLinus Torvalds Hence, we have to _ignore_ sadb_sa_state, which is also reasonable. 10611da177e4SLinus Torvalds */ 10621da177e4SLinus Torvalds if (sa->sadb_sa_auth > SADB_AALG_MAX || 10631da177e4SLinus Torvalds (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP && 10641da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_X_CALG_MAX) || 10651da177e4SLinus Torvalds sa->sadb_sa_encrypt > SADB_EALG_MAX) 10661da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10671da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 10681da177e4SLinus Torvalds if (key != NULL && 10691da177e4SLinus Torvalds sa->sadb_sa_auth != SADB_X_AALG_NULL && 10701da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10711da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10721da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10731da177e4SLinus Torvalds key = ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 10741da177e4SLinus Torvalds if (key != NULL && 10751da177e4SLinus Torvalds sa->sadb_sa_encrypt != SADB_EALG_NULL && 10761da177e4SLinus Torvalds ((key->sadb_key_bits+7) / 8 == 0 || 10771da177e4SLinus Torvalds (key->sadb_key_bits+7) / 8 > key->sadb_key_len * sizeof(uint64_t))) 10781da177e4SLinus Torvalds return ERR_PTR(-EINVAL); 10791da177e4SLinus Torvalds 10801da177e4SLinus Torvalds x = xfrm_state_alloc(); 10811da177e4SLinus Torvalds if (x == NULL) 10821da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 10831da177e4SLinus Torvalds 10841da177e4SLinus Torvalds x->id.proto = proto; 10851da177e4SLinus Torvalds x->id.spi = sa->sadb_sa_spi; 10861da177e4SLinus Torvalds x->props.replay_window = sa->sadb_sa_replay; 10871da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_NOECN) 10881da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_NOECN; 10891da177e4SLinus Torvalds if (sa->sadb_sa_flags & SADB_SAFLAGS_DECAP_DSCP) 10901da177e4SLinus Torvalds x->props.flags |= XFRM_STATE_DECAP_DSCP; 1091dd87147eSHerbert Xu if (sa->sadb_sa_flags & SADB_SAFLAGS_NOPMTUDISC) 1092dd87147eSHerbert Xu x->props.flags |= XFRM_STATE_NOPMTUDISC; 10931da177e4SLinus Torvalds 10941da177e4SLinus Torvalds lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_HARD-1]; 10951da177e4SLinus Torvalds if (lifetime != NULL) { 10961da177e4SLinus Torvalds x->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 10971da177e4SLinus Torvalds x->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 10981da177e4SLinus Torvalds x->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 10991da177e4SLinus Torvalds x->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11001da177e4SLinus Torvalds } 11011da177e4SLinus Torvalds lifetime = (struct sadb_lifetime*) ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]; 11021da177e4SLinus Torvalds if (lifetime != NULL) { 11031da177e4SLinus Torvalds x->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 11041da177e4SLinus Torvalds x->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 11051da177e4SLinus Torvalds x->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 11061da177e4SLinus Torvalds x->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 11071da177e4SLinus Torvalds } 1108df71837dSTrent Jaeger 1109df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 1110df71837dSTrent Jaeger if (sec_ctx != NULL) { 1111df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 1112df71837dSTrent Jaeger 1113df71837dSTrent Jaeger if (!uctx) 1114df71837dSTrent Jaeger goto out; 1115df71837dSTrent Jaeger 1116df71837dSTrent Jaeger err = security_xfrm_state_alloc(x, uctx); 1117df71837dSTrent Jaeger kfree(uctx); 1118df71837dSTrent Jaeger 1119df71837dSTrent Jaeger if (err) 1120df71837dSTrent Jaeger goto out; 1121df71837dSTrent Jaeger } 1122df71837dSTrent Jaeger 11231da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_AUTH-1]; 11241da177e4SLinus Torvalds if (sa->sadb_sa_auth) { 11251da177e4SLinus Torvalds int keysize = 0; 11261da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_aalg_get_byid(sa->sadb_sa_auth); 11271da177e4SLinus Torvalds if (!a) { 11281da177e4SLinus Torvalds err = -ENOSYS; 11291da177e4SLinus Torvalds goto out; 11301da177e4SLinus Torvalds } 11311da177e4SLinus Torvalds if (key) 11321da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11331da177e4SLinus Torvalds x->aalg = kmalloc(sizeof(*x->aalg) + keysize, GFP_KERNEL); 11341da177e4SLinus Torvalds if (!x->aalg) 11351da177e4SLinus Torvalds goto out; 11361da177e4SLinus Torvalds strcpy(x->aalg->alg_name, a->name); 11371da177e4SLinus Torvalds x->aalg->alg_key_len = 0; 11381da177e4SLinus Torvalds if (key) { 11391da177e4SLinus Torvalds x->aalg->alg_key_len = key->sadb_key_bits; 11401da177e4SLinus Torvalds memcpy(x->aalg->alg_key, key+1, keysize); 11411da177e4SLinus Torvalds } 11421da177e4SLinus Torvalds x->props.aalgo = sa->sadb_sa_auth; 11431da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11441da177e4SLinus Torvalds } 11451da177e4SLinus Torvalds if (sa->sadb_sa_encrypt) { 11461da177e4SLinus Torvalds if (hdr->sadb_msg_satype == SADB_X_SATYPE_IPCOMP) { 11471da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_calg_get_byid(sa->sadb_sa_encrypt); 11481da177e4SLinus Torvalds if (!a) { 11491da177e4SLinus Torvalds err = -ENOSYS; 11501da177e4SLinus Torvalds goto out; 11511da177e4SLinus Torvalds } 11521da177e4SLinus Torvalds x->calg = kmalloc(sizeof(*x->calg), GFP_KERNEL); 11531da177e4SLinus Torvalds if (!x->calg) 11541da177e4SLinus Torvalds goto out; 11551da177e4SLinus Torvalds strcpy(x->calg->alg_name, a->name); 11561da177e4SLinus Torvalds x->props.calgo = sa->sadb_sa_encrypt; 11571da177e4SLinus Torvalds } else { 11581da177e4SLinus Torvalds int keysize = 0; 11591da177e4SLinus Torvalds struct xfrm_algo_desc *a = xfrm_ealg_get_byid(sa->sadb_sa_encrypt); 11601da177e4SLinus Torvalds if (!a) { 11611da177e4SLinus Torvalds err = -ENOSYS; 11621da177e4SLinus Torvalds goto out; 11631da177e4SLinus Torvalds } 11641da177e4SLinus Torvalds key = (struct sadb_key*) ext_hdrs[SADB_EXT_KEY_ENCRYPT-1]; 11651da177e4SLinus Torvalds if (key) 11661da177e4SLinus Torvalds keysize = (key->sadb_key_bits + 7) / 8; 11671da177e4SLinus Torvalds x->ealg = kmalloc(sizeof(*x->ealg) + keysize, GFP_KERNEL); 11681da177e4SLinus Torvalds if (!x->ealg) 11691da177e4SLinus Torvalds goto out; 11701da177e4SLinus Torvalds strcpy(x->ealg->alg_name, a->name); 11711da177e4SLinus Torvalds x->ealg->alg_key_len = 0; 11721da177e4SLinus Torvalds if (key) { 11731da177e4SLinus Torvalds x->ealg->alg_key_len = key->sadb_key_bits; 11741da177e4SLinus Torvalds memcpy(x->ealg->alg_key, key+1, keysize); 11751da177e4SLinus Torvalds } 11761da177e4SLinus Torvalds x->props.ealgo = sa->sadb_sa_encrypt; 11771da177e4SLinus Torvalds } 11781da177e4SLinus Torvalds } 11791da177e4SLinus Torvalds /* x->algo.flags = sa->sadb_sa_flags; */ 11801da177e4SLinus Torvalds 11811da177e4SLinus Torvalds x->props.family = pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 11821da177e4SLinus Torvalds &x->props.saddr); 11831da177e4SLinus Torvalds if (!x->props.family) { 11841da177e4SLinus Torvalds err = -EAFNOSUPPORT; 11851da177e4SLinus Torvalds goto out; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr((struct sadb_address *) ext_hdrs[SADB_EXT_ADDRESS_DST-1], 11881da177e4SLinus Torvalds &x->id.daddr); 11891da177e4SLinus Torvalds 11901da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_SA2-1]) { 11911da177e4SLinus Torvalds struct sadb_x_sa2 *sa2 = (void*)ext_hdrs[SADB_X_EXT_SA2-1]; 119255569ce2SKazunori MIYAZAWA int mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 119355569ce2SKazunori MIYAZAWA if (mode < 0) { 119455569ce2SKazunori MIYAZAWA err = -EINVAL; 119555569ce2SKazunori MIYAZAWA goto out; 119655569ce2SKazunori MIYAZAWA } 119755569ce2SKazunori MIYAZAWA x->props.mode = mode; 11981da177e4SLinus Torvalds x->props.reqid = sa2->sadb_x_sa2_reqid; 11991da177e4SLinus Torvalds } 12001da177e4SLinus Torvalds 12011da177e4SLinus Torvalds if (ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]) { 12021da177e4SLinus Torvalds struct sadb_address *addr = ext_hdrs[SADB_EXT_ADDRESS_PROXY-1]; 12031da177e4SLinus Torvalds 12041da177e4SLinus Torvalds /* Nobody uses this, but we try. */ 12051da177e4SLinus Torvalds x->sel.family = pfkey_sadb_addr2xfrm_addr(addr, &x->sel.saddr); 12061da177e4SLinus Torvalds x->sel.prefixlen_s = addr->sadb_address_prefixlen; 12071da177e4SLinus Torvalds } 12081da177e4SLinus Torvalds 12091da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]) { 12101da177e4SLinus Torvalds struct sadb_x_nat_t_type* n_type; 12111da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt; 12121da177e4SLinus Torvalds 12131da177e4SLinus Torvalds x->encap = kmalloc(sizeof(*x->encap), GFP_KERNEL); 12141da177e4SLinus Torvalds if (!x->encap) 12151da177e4SLinus Torvalds goto out; 12161da177e4SLinus Torvalds 12171da177e4SLinus Torvalds natt = x->encap; 12181da177e4SLinus Torvalds n_type = ext_hdrs[SADB_X_EXT_NAT_T_TYPE-1]; 12191da177e4SLinus Torvalds natt->encap_type = n_type->sadb_x_nat_t_type_type; 12201da177e4SLinus Torvalds 12211da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]) { 12221da177e4SLinus Torvalds struct sadb_x_nat_t_port* n_port = 12231da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_SPORT-1]; 12241da177e4SLinus Torvalds natt->encap_sport = n_port->sadb_x_nat_t_port_port; 12251da177e4SLinus Torvalds } 12261da177e4SLinus Torvalds if (ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]) { 12271da177e4SLinus Torvalds struct sadb_x_nat_t_port* n_port = 12281da177e4SLinus Torvalds ext_hdrs[SADB_X_EXT_NAT_T_DPORT-1]; 12291da177e4SLinus Torvalds natt->encap_dport = n_port->sadb_x_nat_t_port_port; 12301da177e4SLinus Torvalds } 12311da177e4SLinus Torvalds } 12321da177e4SLinus Torvalds 123372cb6962SHerbert Xu err = xfrm_init_state(x); 123472cb6962SHerbert Xu if (err) 12351da177e4SLinus Torvalds goto out; 123672cb6962SHerbert Xu 12371da177e4SLinus Torvalds x->km.seq = hdr->sadb_msg_seq; 12381da177e4SLinus Torvalds return x; 12391da177e4SLinus Torvalds 12401da177e4SLinus Torvalds out: 12411da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 12421da177e4SLinus Torvalds xfrm_state_put(x); 12431da177e4SLinus Torvalds return ERR_PTR(err); 12441da177e4SLinus Torvalds } 12451da177e4SLinus Torvalds 12461da177e4SLinus Torvalds static int pfkey_reserved(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 12471da177e4SLinus Torvalds { 12481da177e4SLinus Torvalds return -EOPNOTSUPP; 12491da177e4SLinus Torvalds } 12501da177e4SLinus Torvalds 12511da177e4SLinus Torvalds static int pfkey_getspi(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 12521da177e4SLinus Torvalds { 12531da177e4SLinus Torvalds struct sk_buff *resp_skb; 12541da177e4SLinus Torvalds struct sadb_x_sa2 *sa2; 12551da177e4SLinus Torvalds struct sadb_address *saddr, *daddr; 12561da177e4SLinus Torvalds struct sadb_msg *out_hdr; 12571da177e4SLinus Torvalds struct xfrm_state *x = NULL; 125855569ce2SKazunori MIYAZAWA int mode; 12591da177e4SLinus Torvalds u32 reqid; 12601da177e4SLinus Torvalds u8 proto; 12611da177e4SLinus Torvalds unsigned short family; 12621da177e4SLinus Torvalds xfrm_address_t *xsaddr = NULL, *xdaddr = NULL; 12631da177e4SLinus Torvalds 12641da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 12651da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 12661da177e4SLinus Torvalds return -EINVAL; 12671da177e4SLinus Torvalds 12681da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 12691da177e4SLinus Torvalds if (proto == 0) 12701da177e4SLinus Torvalds return -EINVAL; 12711da177e4SLinus Torvalds 12721da177e4SLinus Torvalds if ((sa2 = ext_hdrs[SADB_X_EXT_SA2-1]) != NULL) { 127355569ce2SKazunori MIYAZAWA mode = pfkey_mode_to_xfrm(sa2->sadb_x_sa2_mode); 127455569ce2SKazunori MIYAZAWA if (mode < 0) 127555569ce2SKazunori MIYAZAWA return -EINVAL; 12761da177e4SLinus Torvalds reqid = sa2->sadb_x_sa2_reqid; 12771da177e4SLinus Torvalds } else { 12781da177e4SLinus Torvalds mode = 0; 12791da177e4SLinus Torvalds reqid = 0; 12801da177e4SLinus Torvalds } 12811da177e4SLinus Torvalds 12821da177e4SLinus Torvalds saddr = ext_hdrs[SADB_EXT_ADDRESS_SRC-1]; 12831da177e4SLinus Torvalds daddr = ext_hdrs[SADB_EXT_ADDRESS_DST-1]; 12841da177e4SLinus Torvalds 12851da177e4SLinus Torvalds family = ((struct sockaddr *)(saddr + 1))->sa_family; 12861da177e4SLinus Torvalds switch (family) { 12871da177e4SLinus Torvalds case AF_INET: 12881da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in *)(daddr + 1))->sin_addr.s_addr; 12891da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in *)(saddr + 1))->sin_addr.s_addr; 12901da177e4SLinus Torvalds break; 12911da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 12921da177e4SLinus Torvalds case AF_INET6: 12931da177e4SLinus Torvalds xdaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(daddr + 1))->sin6_addr; 12941da177e4SLinus Torvalds xsaddr = (xfrm_address_t *)&((struct sockaddr_in6 *)(saddr + 1))->sin6_addr; 12951da177e4SLinus Torvalds break; 12961da177e4SLinus Torvalds #endif 12971da177e4SLinus Torvalds } 12981da177e4SLinus Torvalds 12991da177e4SLinus Torvalds if (hdr->sadb_msg_seq) { 13001da177e4SLinus Torvalds x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); 13011da177e4SLinus Torvalds if (x && xfrm_addr_cmp(&x->id.daddr, xdaddr, family)) { 13021da177e4SLinus Torvalds xfrm_state_put(x); 13031da177e4SLinus Torvalds x = NULL; 13041da177e4SLinus Torvalds } 13051da177e4SLinus Torvalds } 13061da177e4SLinus Torvalds 13071da177e4SLinus Torvalds if (!x) 13081da177e4SLinus Torvalds x = xfrm_find_acq(mode, reqid, proto, xdaddr, xsaddr, 1, family); 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds if (x == NULL) 13111da177e4SLinus Torvalds return -ENOENT; 13121da177e4SLinus Torvalds 13131da177e4SLinus Torvalds resp_skb = ERR_PTR(-ENOENT); 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds spin_lock_bh(&x->lock); 13161da177e4SLinus Torvalds if (x->km.state != XFRM_STATE_DEAD) { 13171da177e4SLinus Torvalds struct sadb_spirange *range = ext_hdrs[SADB_EXT_SPIRANGE-1]; 13181da177e4SLinus Torvalds u32 min_spi, max_spi; 13191da177e4SLinus Torvalds 13201da177e4SLinus Torvalds if (range != NULL) { 13211da177e4SLinus Torvalds min_spi = range->sadb_spirange_min; 13221da177e4SLinus Torvalds max_spi = range->sadb_spirange_max; 13231da177e4SLinus Torvalds } else { 13241da177e4SLinus Torvalds min_spi = 0x100; 13251da177e4SLinus Torvalds max_spi = 0x0fffffff; 13261da177e4SLinus Torvalds } 13271da177e4SLinus Torvalds xfrm_alloc_spi(x, htonl(min_spi), htonl(max_spi)); 13281da177e4SLinus Torvalds if (x->id.spi) 13291da177e4SLinus Torvalds resp_skb = pfkey_xfrm_state2msg(x, 0, 3); 13301da177e4SLinus Torvalds } 13311da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 13321da177e4SLinus Torvalds 13331da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 13341da177e4SLinus Torvalds xfrm_state_put(x); 13351da177e4SLinus Torvalds return PTR_ERR(resp_skb); 13361da177e4SLinus Torvalds } 13371da177e4SLinus Torvalds 13381da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) resp_skb->data; 13391da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 13401da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_GETSPI; 13411da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 13421da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 13431da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 13441da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 13451da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 13461da177e4SLinus Torvalds 13471da177e4SLinus Torvalds xfrm_state_put(x); 13481da177e4SLinus Torvalds 13491da177e4SLinus Torvalds pfkey_broadcast(resp_skb, GFP_KERNEL, BROADCAST_ONE, sk); 13501da177e4SLinus Torvalds 13511da177e4SLinus Torvalds return 0; 13521da177e4SLinus Torvalds } 13531da177e4SLinus Torvalds 13541da177e4SLinus Torvalds static int pfkey_acquire(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 13551da177e4SLinus Torvalds { 13561da177e4SLinus Torvalds struct xfrm_state *x; 13571da177e4SLinus Torvalds 13581da177e4SLinus Torvalds if (hdr->sadb_msg_len != sizeof(struct sadb_msg)/8) 13591da177e4SLinus Torvalds return -EOPNOTSUPP; 13601da177e4SLinus Torvalds 13611da177e4SLinus Torvalds if (hdr->sadb_msg_seq == 0 || hdr->sadb_msg_errno == 0) 13621da177e4SLinus Torvalds return 0; 13631da177e4SLinus Torvalds 13641da177e4SLinus Torvalds x = xfrm_find_acq_byseq(hdr->sadb_msg_seq); 13651da177e4SLinus Torvalds if (x == NULL) 13661da177e4SLinus Torvalds return 0; 13671da177e4SLinus Torvalds 13681da177e4SLinus Torvalds spin_lock_bh(&x->lock); 13691da177e4SLinus Torvalds if (x->km.state == XFRM_STATE_ACQ) { 13701da177e4SLinus Torvalds x->km.state = XFRM_STATE_ERROR; 13711da177e4SLinus Torvalds wake_up(&km_waitq); 13721da177e4SLinus Torvalds } 13731da177e4SLinus Torvalds spin_unlock_bh(&x->lock); 13741da177e4SLinus Torvalds xfrm_state_put(x); 13751da177e4SLinus Torvalds return 0; 13761da177e4SLinus Torvalds } 13771da177e4SLinus Torvalds 137826b15dadSJamal Hadi Salim static inline int event2poltype(int event) 137926b15dadSJamal Hadi Salim { 138026b15dadSJamal Hadi Salim switch (event) { 1381f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 138226b15dadSJamal Hadi Salim return SADB_X_SPDDELETE; 1383f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 138426b15dadSJamal Hadi Salim return SADB_X_SPDADD; 1385f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 138626b15dadSJamal Hadi Salim return SADB_X_SPDUPDATE; 1387f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 138826b15dadSJamal Hadi Salim // return SADB_X_SPDEXPIRE; 138926b15dadSJamal Hadi Salim default: 139026b15dadSJamal Hadi Salim printk("pfkey: Unknown policy event %d\n", event); 139126b15dadSJamal Hadi Salim break; 139226b15dadSJamal Hadi Salim } 139326b15dadSJamal Hadi Salim 139426b15dadSJamal Hadi Salim return 0; 139526b15dadSJamal Hadi Salim } 139626b15dadSJamal Hadi Salim 139726b15dadSJamal Hadi Salim static inline int event2keytype(int event) 139826b15dadSJamal Hadi Salim { 139926b15dadSJamal Hadi Salim switch (event) { 1400f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 140126b15dadSJamal Hadi Salim return SADB_DELETE; 1402f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 140326b15dadSJamal Hadi Salim return SADB_ADD; 1404f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 140526b15dadSJamal Hadi Salim return SADB_UPDATE; 1406f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 140726b15dadSJamal Hadi Salim return SADB_EXPIRE; 140826b15dadSJamal Hadi Salim default: 140926b15dadSJamal Hadi Salim printk("pfkey: Unknown SA event %d\n", event); 141026b15dadSJamal Hadi Salim break; 141126b15dadSJamal Hadi Salim } 141226b15dadSJamal Hadi Salim 141326b15dadSJamal Hadi Salim return 0; 141426b15dadSJamal Hadi Salim } 141526b15dadSJamal Hadi Salim 141626b15dadSJamal Hadi Salim /* ADD/UPD/DEL */ 141726b15dadSJamal Hadi Salim static int key_notify_sa(struct xfrm_state *x, struct km_event *c) 141826b15dadSJamal Hadi Salim { 141926b15dadSJamal Hadi Salim struct sk_buff *skb; 142026b15dadSJamal Hadi Salim struct sadb_msg *hdr; 142126b15dadSJamal Hadi Salim int hsc = 3; 142226b15dadSJamal Hadi Salim 1423f60f6b8fSHerbert Xu if (c->event == XFRM_MSG_DELSA) 142426b15dadSJamal Hadi Salim hsc = 0; 142526b15dadSJamal Hadi Salim 142626b15dadSJamal Hadi Salim skb = pfkey_xfrm_state2msg(x, 0, hsc); 142726b15dadSJamal Hadi Salim 142826b15dadSJamal Hadi Salim if (IS_ERR(skb)) 142926b15dadSJamal Hadi Salim return PTR_ERR(skb); 143026b15dadSJamal Hadi Salim 143126b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb->data; 143226b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 143326b15dadSJamal Hadi Salim hdr->sadb_msg_type = event2keytype(c->event); 143426b15dadSJamal Hadi Salim hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 143526b15dadSJamal Hadi Salim hdr->sadb_msg_errno = 0; 143626b15dadSJamal Hadi Salim hdr->sadb_msg_reserved = 0; 143726b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 143826b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 143926b15dadSJamal Hadi Salim 144026b15dadSJamal Hadi Salim pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 144126b15dadSJamal Hadi Salim 144226b15dadSJamal Hadi Salim return 0; 144326b15dadSJamal Hadi Salim } 14441da177e4SLinus Torvalds 14451da177e4SLinus Torvalds static int pfkey_add(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 14461da177e4SLinus Torvalds { 14471da177e4SLinus Torvalds struct xfrm_state *x; 14481da177e4SLinus Torvalds int err; 144926b15dadSJamal Hadi Salim struct km_event c; 14501da177e4SLinus Torvalds 14511da177e4SLinus Torvalds xfrm_probe_algs(); 14521da177e4SLinus Torvalds 14531da177e4SLinus Torvalds x = pfkey_msg2xfrm_state(hdr, ext_hdrs); 14541da177e4SLinus Torvalds if (IS_ERR(x)) 14551da177e4SLinus Torvalds return PTR_ERR(x); 14561da177e4SLinus Torvalds 145726b15dadSJamal Hadi Salim xfrm_state_hold(x); 14581da177e4SLinus Torvalds if (hdr->sadb_msg_type == SADB_ADD) 14591da177e4SLinus Torvalds err = xfrm_state_add(x); 14601da177e4SLinus Torvalds else 14611da177e4SLinus Torvalds err = xfrm_state_update(x); 14621da177e4SLinus Torvalds 1463161a09e7SJoy Latten xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, 1464161a09e7SJoy Latten AUDIT_MAC_IPSEC_ADDSA, err ? 0 : 1, NULL, x); 1465161a09e7SJoy Latten 14661da177e4SLinus Torvalds if (err < 0) { 14671da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 146821380b81SHerbert Xu __xfrm_state_put(x); 14697d6dfe1fSPatrick McHardy goto out; 14701da177e4SLinus Torvalds } 14711da177e4SLinus Torvalds 147226b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_ADD) 1473f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWSA; 147426b15dadSJamal Hadi Salim else 1475f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDSA; 147626b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 147726b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 147826b15dadSJamal Hadi Salim km_state_notify(x, &c); 14797d6dfe1fSPatrick McHardy out: 148026b15dadSJamal Hadi Salim xfrm_state_put(x); 148126b15dadSJamal Hadi Salim return err; 14821da177e4SLinus Torvalds } 14831da177e4SLinus Torvalds 14841da177e4SLinus Torvalds static int pfkey_delete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 14851da177e4SLinus Torvalds { 14861da177e4SLinus Torvalds struct xfrm_state *x; 148726b15dadSJamal Hadi Salim struct km_event c; 148826b15dadSJamal Hadi Salim int err; 14891da177e4SLinus Torvalds 14901da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 14911da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 14921da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 14931da177e4SLinus Torvalds return -EINVAL; 14941da177e4SLinus Torvalds 14951da177e4SLinus Torvalds x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); 14961da177e4SLinus Torvalds if (x == NULL) 14971da177e4SLinus Torvalds return -ESRCH; 14981da177e4SLinus Torvalds 1499c8c05a8eSCatherine Zhang if ((err = security_xfrm_state_delete(x))) 1500c8c05a8eSCatherine Zhang goto out; 1501c8c05a8eSCatherine Zhang 15021da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 1503c8c05a8eSCatherine Zhang err = -EPERM; 1504c8c05a8eSCatherine Zhang goto out; 15051da177e4SLinus Torvalds } 15061da177e4SLinus Torvalds 150726b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 1508161a09e7SJoy Latten 1509c8c05a8eSCatherine Zhang if (err < 0) 1510c8c05a8eSCatherine Zhang goto out; 151126b15dadSJamal Hadi Salim 151226b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 151326b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1514f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELSA; 151526b15dadSJamal Hadi Salim km_state_notify(x, &c); 1516c8c05a8eSCatherine Zhang out: 151716bec31dSEric Paris xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, 151816bec31dSEric Paris AUDIT_MAC_IPSEC_DELSA, err ? 0 : 1, NULL, x); 15191da177e4SLinus Torvalds xfrm_state_put(x); 15201da177e4SLinus Torvalds 152126b15dadSJamal Hadi Salim return err; 15221da177e4SLinus Torvalds } 15231da177e4SLinus Torvalds 15241da177e4SLinus Torvalds static int pfkey_get(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 15251da177e4SLinus Torvalds { 15261da177e4SLinus Torvalds __u8 proto; 15271da177e4SLinus Torvalds struct sk_buff *out_skb; 15281da177e4SLinus Torvalds struct sadb_msg *out_hdr; 15291da177e4SLinus Torvalds struct xfrm_state *x; 15301da177e4SLinus Torvalds 15311da177e4SLinus Torvalds if (!ext_hdrs[SADB_EXT_SA-1] || 15321da177e4SLinus Torvalds !present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 15331da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1])) 15341da177e4SLinus Torvalds return -EINVAL; 15351da177e4SLinus Torvalds 15361da177e4SLinus Torvalds x = pfkey_xfrm_state_lookup(hdr, ext_hdrs); 15371da177e4SLinus Torvalds if (x == NULL) 15381da177e4SLinus Torvalds return -ESRCH; 15391da177e4SLinus Torvalds 15401da177e4SLinus Torvalds out_skb = pfkey_xfrm_state2msg(x, 1, 3); 15411da177e4SLinus Torvalds proto = x->id.proto; 15421da177e4SLinus Torvalds xfrm_state_put(x); 15431da177e4SLinus Torvalds if (IS_ERR(out_skb)) 15441da177e4SLinus Torvalds return PTR_ERR(out_skb); 15451da177e4SLinus Torvalds 15461da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 15471da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 15481da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_DUMP; 15491da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(proto); 15501da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 15511da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 15521da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 15531da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 15541da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); 15551da177e4SLinus Torvalds 15561da177e4SLinus Torvalds return 0; 15571da177e4SLinus Torvalds } 15581da177e4SLinus Torvalds 155900fa0233SRandy Dunlap static struct sk_buff *compose_sadb_supported(struct sadb_msg *orig, 1560dd0fc66fSAl Viro gfp_t allocation) 15611da177e4SLinus Torvalds { 15621da177e4SLinus Torvalds struct sk_buff *skb; 15631da177e4SLinus Torvalds struct sadb_msg *hdr; 15641da177e4SLinus Torvalds int len, auth_len, enc_len, i; 15651da177e4SLinus Torvalds 15661da177e4SLinus Torvalds auth_len = xfrm_count_auth_supported(); 15671da177e4SLinus Torvalds if (auth_len) { 15681da177e4SLinus Torvalds auth_len *= sizeof(struct sadb_alg); 15691da177e4SLinus Torvalds auth_len += sizeof(struct sadb_supported); 15701da177e4SLinus Torvalds } 15711da177e4SLinus Torvalds 15721da177e4SLinus Torvalds enc_len = xfrm_count_enc_supported(); 15731da177e4SLinus Torvalds if (enc_len) { 15741da177e4SLinus Torvalds enc_len *= sizeof(struct sadb_alg); 15751da177e4SLinus Torvalds enc_len += sizeof(struct sadb_supported); 15761da177e4SLinus Torvalds } 15771da177e4SLinus Torvalds 15781da177e4SLinus Torvalds len = enc_len + auth_len + sizeof(struct sadb_msg); 15791da177e4SLinus Torvalds 15801da177e4SLinus Torvalds skb = alloc_skb(len + 16, allocation); 15811da177e4SLinus Torvalds if (!skb) 15821da177e4SLinus Torvalds goto out_put_algs; 15831da177e4SLinus Torvalds 15841da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(*hdr)); 15851da177e4SLinus Torvalds pfkey_hdr_dup(hdr, orig); 15861da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 15871da177e4SLinus Torvalds hdr->sadb_msg_len = len / sizeof(uint64_t); 15881da177e4SLinus Torvalds 15891da177e4SLinus Torvalds if (auth_len) { 15901da177e4SLinus Torvalds struct sadb_supported *sp; 15911da177e4SLinus Torvalds struct sadb_alg *ap; 15921da177e4SLinus Torvalds 15931da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, auth_len); 15941da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 15951da177e4SLinus Torvalds 15961da177e4SLinus Torvalds sp->sadb_supported_len = auth_len / sizeof(uint64_t); 15971da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_AUTH; 15981da177e4SLinus Torvalds 15991da177e4SLinus Torvalds for (i = 0; ; i++) { 16001da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 16011da177e4SLinus Torvalds if (!aalg) 16021da177e4SLinus Torvalds break; 16031da177e4SLinus Torvalds if (aalg->available) 16041da177e4SLinus Torvalds *ap++ = aalg->desc; 16051da177e4SLinus Torvalds } 16061da177e4SLinus Torvalds } 16071da177e4SLinus Torvalds 16081da177e4SLinus Torvalds if (enc_len) { 16091da177e4SLinus Torvalds struct sadb_supported *sp; 16101da177e4SLinus Torvalds struct sadb_alg *ap; 16111da177e4SLinus Torvalds 16121da177e4SLinus Torvalds sp = (struct sadb_supported *) skb_put(skb, enc_len); 16131da177e4SLinus Torvalds ap = (struct sadb_alg *) (sp + 1); 16141da177e4SLinus Torvalds 16151da177e4SLinus Torvalds sp->sadb_supported_len = enc_len / sizeof(uint64_t); 16161da177e4SLinus Torvalds sp->sadb_supported_exttype = SADB_EXT_SUPPORTED_ENCRYPT; 16171da177e4SLinus Torvalds 16181da177e4SLinus Torvalds for (i = 0; ; i++) { 16191da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 16201da177e4SLinus Torvalds if (!ealg) 16211da177e4SLinus Torvalds break; 16221da177e4SLinus Torvalds if (ealg->available) 16231da177e4SLinus Torvalds *ap++ = ealg->desc; 16241da177e4SLinus Torvalds } 16251da177e4SLinus Torvalds } 16261da177e4SLinus Torvalds 16271da177e4SLinus Torvalds out_put_algs: 16281da177e4SLinus Torvalds return skb; 16291da177e4SLinus Torvalds } 16301da177e4SLinus Torvalds 16311da177e4SLinus Torvalds static int pfkey_register(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 16321da177e4SLinus Torvalds { 16331da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 16341da177e4SLinus Torvalds struct sk_buff *supp_skb; 16351da177e4SLinus Torvalds 16361da177e4SLinus Torvalds if (hdr->sadb_msg_satype > SADB_SATYPE_MAX) 16371da177e4SLinus Torvalds return -EINVAL; 16381da177e4SLinus Torvalds 16391da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) { 16401da177e4SLinus Torvalds if (pfk->registered&(1<<hdr->sadb_msg_satype)) 16411da177e4SLinus Torvalds return -EEXIST; 16421da177e4SLinus Torvalds pfk->registered |= (1<<hdr->sadb_msg_satype); 16431da177e4SLinus Torvalds } 16441da177e4SLinus Torvalds 16451da177e4SLinus Torvalds xfrm_probe_algs(); 16461da177e4SLinus Torvalds 16471da177e4SLinus Torvalds supp_skb = compose_sadb_supported(hdr, GFP_KERNEL); 16481da177e4SLinus Torvalds if (!supp_skb) { 16491da177e4SLinus Torvalds if (hdr->sadb_msg_satype != SADB_SATYPE_UNSPEC) 16501da177e4SLinus Torvalds pfk->registered &= ~(1<<hdr->sadb_msg_satype); 16511da177e4SLinus Torvalds 16521da177e4SLinus Torvalds return -ENOBUFS; 16531da177e4SLinus Torvalds } 16541da177e4SLinus Torvalds 16551da177e4SLinus Torvalds pfkey_broadcast(supp_skb, GFP_KERNEL, BROADCAST_REGISTERED, sk); 16561da177e4SLinus Torvalds 16571da177e4SLinus Torvalds return 0; 16581da177e4SLinus Torvalds } 16591da177e4SLinus Torvalds 166026b15dadSJamal Hadi Salim static int key_notify_sa_flush(struct km_event *c) 166126b15dadSJamal Hadi Salim { 166226b15dadSJamal Hadi Salim struct sk_buff *skb; 166326b15dadSJamal Hadi Salim struct sadb_msg *hdr; 166426b15dadSJamal Hadi Salim 166526b15dadSJamal Hadi Salim skb = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 166626b15dadSJamal Hadi Salim if (!skb) 166726b15dadSJamal Hadi Salim return -ENOBUFS; 166826b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 1669bf08867fSHerbert Xu hdr->sadb_msg_satype = pfkey_proto2satype(c->data.proto); 1670151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_FLUSH; 167126b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 167226b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 167326b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 167426b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 167526b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 167626b15dadSJamal Hadi Salim 167726b15dadSJamal Hadi Salim pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 167826b15dadSJamal Hadi Salim 167926b15dadSJamal Hadi Salim return 0; 168026b15dadSJamal Hadi Salim } 168126b15dadSJamal Hadi Salim 16821da177e4SLinus Torvalds static int pfkey_flush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 16831da177e4SLinus Torvalds { 16841da177e4SLinus Torvalds unsigned proto; 168526b15dadSJamal Hadi Salim struct km_event c; 1686161a09e7SJoy Latten struct xfrm_audit audit_info; 16871da177e4SLinus Torvalds 16881da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 16891da177e4SLinus Torvalds if (proto == 0) 16901da177e4SLinus Torvalds return -EINVAL; 16911da177e4SLinus Torvalds 1692161a09e7SJoy Latten audit_info.loginuid = audit_get_loginuid(current->audit_context); 1693161a09e7SJoy Latten audit_info.secid = 0; 1694161a09e7SJoy Latten xfrm_state_flush(proto, &audit_info); 1695bf08867fSHerbert Xu c.data.proto = proto; 169626b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 169726b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 1698f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHSA; 169926b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 17001da177e4SLinus Torvalds 17011da177e4SLinus Torvalds return 0; 17021da177e4SLinus Torvalds } 17031da177e4SLinus Torvalds 17041da177e4SLinus Torvalds struct pfkey_dump_data 17051da177e4SLinus Torvalds { 17061da177e4SLinus Torvalds struct sk_buff *skb; 17071da177e4SLinus Torvalds struct sadb_msg *hdr; 17081da177e4SLinus Torvalds struct sock *sk; 17091da177e4SLinus Torvalds }; 17101da177e4SLinus Torvalds 17111da177e4SLinus Torvalds static int dump_sa(struct xfrm_state *x, int count, void *ptr) 17121da177e4SLinus Torvalds { 17131da177e4SLinus Torvalds struct pfkey_dump_data *data = ptr; 17141da177e4SLinus Torvalds struct sk_buff *out_skb; 17151da177e4SLinus Torvalds struct sadb_msg *out_hdr; 17161da177e4SLinus Torvalds 17171da177e4SLinus Torvalds out_skb = pfkey_xfrm_state2msg(x, 1, 3); 17181da177e4SLinus Torvalds if (IS_ERR(out_skb)) 17191da177e4SLinus Torvalds return PTR_ERR(out_skb); 17201da177e4SLinus Torvalds 17211da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 17221da177e4SLinus Torvalds out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; 17231da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_DUMP; 17241da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 17251da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 17261da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 17271da177e4SLinus Torvalds out_hdr->sadb_msg_seq = count; 17281da177e4SLinus Torvalds out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; 17291da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); 17301da177e4SLinus Torvalds return 0; 17311da177e4SLinus Torvalds } 17321da177e4SLinus Torvalds 17331da177e4SLinus Torvalds static int pfkey_dump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 17341da177e4SLinus Torvalds { 17351da177e4SLinus Torvalds u8 proto; 17361da177e4SLinus Torvalds struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 17371da177e4SLinus Torvalds 17381da177e4SLinus Torvalds proto = pfkey_satype2proto(hdr->sadb_msg_satype); 17391da177e4SLinus Torvalds if (proto == 0) 17401da177e4SLinus Torvalds return -EINVAL; 17411da177e4SLinus Torvalds 17421da177e4SLinus Torvalds return xfrm_state_walk(proto, dump_sa, &data); 17431da177e4SLinus Torvalds } 17441da177e4SLinus Torvalds 17451da177e4SLinus Torvalds static int pfkey_promisc(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 17461da177e4SLinus Torvalds { 17471da177e4SLinus Torvalds struct pfkey_sock *pfk = pfkey_sk(sk); 17481da177e4SLinus Torvalds int satype = hdr->sadb_msg_satype; 17491da177e4SLinus Torvalds 17501da177e4SLinus Torvalds if (hdr->sadb_msg_len == (sizeof(*hdr) / sizeof(uint64_t))) { 17511da177e4SLinus Torvalds /* XXX we mangle packet... */ 17521da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 17531da177e4SLinus Torvalds if (satype != 0 && satype != 1) 17541da177e4SLinus Torvalds return -EINVAL; 17551da177e4SLinus Torvalds pfk->promisc = satype; 17561da177e4SLinus Torvalds } 17571da177e4SLinus Torvalds pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, BROADCAST_ALL, NULL); 17581da177e4SLinus Torvalds return 0; 17591da177e4SLinus Torvalds } 17601da177e4SLinus Torvalds 17611da177e4SLinus Torvalds static int check_reqid(struct xfrm_policy *xp, int dir, int count, void *ptr) 17621da177e4SLinus Torvalds { 17631da177e4SLinus Torvalds int i; 17641da177e4SLinus Torvalds u32 reqid = *(u32*)ptr; 17651da177e4SLinus Torvalds 17661da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 17671da177e4SLinus Torvalds if (xp->xfrm_vec[i].reqid == reqid) 17681da177e4SLinus Torvalds return -EEXIST; 17691da177e4SLinus Torvalds } 17701da177e4SLinus Torvalds return 0; 17711da177e4SLinus Torvalds } 17721da177e4SLinus Torvalds 17731da177e4SLinus Torvalds static u32 gen_reqid(void) 17741da177e4SLinus Torvalds { 17751da177e4SLinus Torvalds u32 start; 17761da177e4SLinus Torvalds static u32 reqid = IPSEC_MANUAL_REQID_MAX; 17771da177e4SLinus Torvalds 17781da177e4SLinus Torvalds start = reqid; 17791da177e4SLinus Torvalds do { 17801da177e4SLinus Torvalds ++reqid; 17811da177e4SLinus Torvalds if (reqid == 0) 17821da177e4SLinus Torvalds reqid = IPSEC_MANUAL_REQID_MAX+1; 1783f7b6983fSMasahide NAKAMURA if (xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, check_reqid, 1784f7b6983fSMasahide NAKAMURA (void*)&reqid) != -EEXIST) 17851da177e4SLinus Torvalds return reqid; 17861da177e4SLinus Torvalds } while (reqid != start); 17871da177e4SLinus Torvalds return 0; 17881da177e4SLinus Torvalds } 17891da177e4SLinus Torvalds 17901da177e4SLinus Torvalds static int 17911da177e4SLinus Torvalds parse_ipsecrequest(struct xfrm_policy *xp, struct sadb_x_ipsecrequest *rq) 17921da177e4SLinus Torvalds { 17931da177e4SLinus Torvalds struct xfrm_tmpl *t = xp->xfrm_vec + xp->xfrm_nr; 17941da177e4SLinus Torvalds struct sockaddr_in *sin; 17951da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 17961da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 17971da177e4SLinus Torvalds #endif 179855569ce2SKazunori MIYAZAWA int mode; 17991da177e4SLinus Torvalds 18001da177e4SLinus Torvalds if (xp->xfrm_nr >= XFRM_MAX_DEPTH) 18011da177e4SLinus Torvalds return -ELOOP; 18021da177e4SLinus Torvalds 18031da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_mode == 0) 18041da177e4SLinus Torvalds return -EINVAL; 18051da177e4SLinus Torvalds 18061da177e4SLinus Torvalds t->id.proto = rq->sadb_x_ipsecrequest_proto; /* XXX check proto */ 180755569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq->sadb_x_ipsecrequest_mode)) < 0) 180855569ce2SKazunori MIYAZAWA return -EINVAL; 180955569ce2SKazunori MIYAZAWA t->mode = mode; 18101da177e4SLinus Torvalds if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_USE) 18111da177e4SLinus Torvalds t->optional = 1; 18121da177e4SLinus Torvalds else if (rq->sadb_x_ipsecrequest_level == IPSEC_LEVEL_UNIQUE) { 18131da177e4SLinus Torvalds t->reqid = rq->sadb_x_ipsecrequest_reqid; 18141da177e4SLinus Torvalds if (t->reqid > IPSEC_MANUAL_REQID_MAX) 18151da177e4SLinus Torvalds t->reqid = 0; 18161da177e4SLinus Torvalds if (!t->reqid && !(t->reqid = gen_reqid())) 18171da177e4SLinus Torvalds return -ENOBUFS; 18181da177e4SLinus Torvalds } 18191da177e4SLinus Torvalds 18201da177e4SLinus Torvalds /* addresses present only in tunnel mode */ 18217e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) { 18222718aa7cSMiika Komu struct sockaddr *sa; 18232718aa7cSMiika Komu sa = (struct sockaddr *)(rq+1); 18242718aa7cSMiika Komu switch(sa->sa_family) { 18251da177e4SLinus Torvalds case AF_INET: 18262718aa7cSMiika Komu sin = (struct sockaddr_in*)sa; 18271da177e4SLinus Torvalds t->saddr.a4 = sin->sin_addr.s_addr; 18281da177e4SLinus Torvalds sin++; 18291da177e4SLinus Torvalds if (sin->sin_family != AF_INET) 18301da177e4SLinus Torvalds return -EINVAL; 18311da177e4SLinus Torvalds t->id.daddr.a4 = sin->sin_addr.s_addr; 18321da177e4SLinus Torvalds break; 18331da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 18341da177e4SLinus Torvalds case AF_INET6: 18352718aa7cSMiika Komu sin6 = (struct sockaddr_in6*)sa; 18361da177e4SLinus Torvalds memcpy(t->saddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); 18371da177e4SLinus Torvalds sin6++; 18381da177e4SLinus Torvalds if (sin6->sin6_family != AF_INET6) 18391da177e4SLinus Torvalds return -EINVAL; 18401da177e4SLinus Torvalds memcpy(t->id.daddr.a6, &sin6->sin6_addr, sizeof(struct in6_addr)); 18411da177e4SLinus Torvalds break; 18421da177e4SLinus Torvalds #endif 18431da177e4SLinus Torvalds default: 18441da177e4SLinus Torvalds return -EINVAL; 18451da177e4SLinus Torvalds } 18462718aa7cSMiika Komu t->encap_family = sa->sa_family; 18472718aa7cSMiika Komu } else 18482718aa7cSMiika Komu t->encap_family = xp->family; 18492718aa7cSMiika Komu 18501da177e4SLinus Torvalds /* No way to set this via kame pfkey */ 18511da177e4SLinus Torvalds t->aalgos = t->ealgos = t->calgos = ~0; 18521da177e4SLinus Torvalds xp->xfrm_nr++; 18531da177e4SLinus Torvalds return 0; 18541da177e4SLinus Torvalds } 18551da177e4SLinus Torvalds 18561da177e4SLinus Torvalds static int 18571da177e4SLinus Torvalds parse_ipsecrequests(struct xfrm_policy *xp, struct sadb_x_policy *pol) 18581da177e4SLinus Torvalds { 18591da177e4SLinus Torvalds int err; 18601da177e4SLinus Torvalds int len = pol->sadb_x_policy_len*8 - sizeof(struct sadb_x_policy); 18611da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq = (void*)(pol+1); 18621da177e4SLinus Torvalds 18631da177e4SLinus Torvalds while (len >= sizeof(struct sadb_x_ipsecrequest)) { 18641da177e4SLinus Torvalds if ((err = parse_ipsecrequest(xp, rq)) < 0) 18651da177e4SLinus Torvalds return err; 18661da177e4SLinus Torvalds len -= rq->sadb_x_ipsecrequest_len; 18671da177e4SLinus Torvalds rq = (void*)((u8*)rq + rq->sadb_x_ipsecrequest_len); 18681da177e4SLinus Torvalds } 18691da177e4SLinus Torvalds return 0; 18701da177e4SLinus Torvalds } 18711da177e4SLinus Torvalds 1872df71837dSTrent Jaeger static inline int pfkey_xfrm_policy2sec_ctx_size(struct xfrm_policy *xp) 1873df71837dSTrent Jaeger { 1874df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx = xp->security; 1875df71837dSTrent Jaeger 1876df71837dSTrent Jaeger if (xfrm_ctx) { 1877df71837dSTrent Jaeger int len = sizeof(struct sadb_x_sec_ctx); 1878df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 1879df71837dSTrent Jaeger return PFKEY_ALIGN8(len); 1880df71837dSTrent Jaeger } 1881df71837dSTrent Jaeger return 0; 1882df71837dSTrent Jaeger } 1883df71837dSTrent Jaeger 18841da177e4SLinus Torvalds static int pfkey_xfrm_policy2msg_size(struct xfrm_policy *xp) 18851da177e4SLinus Torvalds { 18862718aa7cSMiika Komu struct xfrm_tmpl *t; 18871da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 18882718aa7cSMiika Komu int socklen = 0; 18892718aa7cSMiika Komu int i; 18902718aa7cSMiika Komu 18912718aa7cSMiika Komu for (i=0; i<xp->xfrm_nr; i++) { 18922718aa7cSMiika Komu t = xp->xfrm_vec + i; 18932718aa7cSMiika Komu socklen += (t->encap_family == AF_INET ? 18941da177e4SLinus Torvalds sizeof(struct sockaddr_in) : 18951da177e4SLinus Torvalds sizeof(struct sockaddr_in6)); 18962718aa7cSMiika Komu } 18971da177e4SLinus Torvalds 18981da177e4SLinus Torvalds return sizeof(struct sadb_msg) + 18991da177e4SLinus Torvalds (sizeof(struct sadb_lifetime) * 3) + 19001da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 19011da177e4SLinus Torvalds (sockaddr_size * 2) + 19021da177e4SLinus Torvalds sizeof(struct sadb_x_policy) + 19032718aa7cSMiika Komu (xp->xfrm_nr * sizeof(struct sadb_x_ipsecrequest)) + 19042718aa7cSMiika Komu (socklen * 2) + 1905df71837dSTrent Jaeger pfkey_xfrm_policy2sec_ctx_size(xp); 19061da177e4SLinus Torvalds } 19071da177e4SLinus Torvalds 19081da177e4SLinus Torvalds static struct sk_buff * pfkey_xfrm_policy2msg_prep(struct xfrm_policy *xp) 19091da177e4SLinus Torvalds { 19101da177e4SLinus Torvalds struct sk_buff *skb; 19111da177e4SLinus Torvalds int size; 19121da177e4SLinus Torvalds 19131da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19141da177e4SLinus Torvalds 19151da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 19161da177e4SLinus Torvalds if (skb == NULL) 19171da177e4SLinus Torvalds return ERR_PTR(-ENOBUFS); 19181da177e4SLinus Torvalds 19191da177e4SLinus Torvalds return skb; 19201da177e4SLinus Torvalds } 19211da177e4SLinus Torvalds 192255569ce2SKazunori MIYAZAWA static int pfkey_xfrm_policy2msg(struct sk_buff *skb, struct xfrm_policy *xp, int dir) 19231da177e4SLinus Torvalds { 19241da177e4SLinus Torvalds struct sadb_msg *hdr; 19251da177e4SLinus Torvalds struct sadb_address *addr; 19261da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 19271da177e4SLinus Torvalds struct sadb_x_policy *pol; 19281da177e4SLinus Torvalds struct sockaddr_in *sin; 1929df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 1930df71837dSTrent Jaeger struct xfrm_sec_ctx *xfrm_ctx; 19311da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19321da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 19331da177e4SLinus Torvalds #endif 19341da177e4SLinus Torvalds int i; 19351da177e4SLinus Torvalds int size; 19361da177e4SLinus Torvalds int sockaddr_size = pfkey_sockaddr_size(xp->family); 19371da177e4SLinus Torvalds int socklen = (xp->family == AF_INET ? 19381da177e4SLinus Torvalds sizeof(struct sockaddr_in) : 19391da177e4SLinus Torvalds sizeof(struct sockaddr_in6)); 19401da177e4SLinus Torvalds 19411da177e4SLinus Torvalds size = pfkey_xfrm_policy2msg_size(xp); 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds /* call should fill header later */ 19441da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 19451da177e4SLinus Torvalds memset(hdr, 0, size); /* XXX do we need this ? */ 19461da177e4SLinus Torvalds 19471da177e4SLinus Torvalds /* src address */ 19481da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 19491da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 19501da177e4SLinus Torvalds addr->sadb_address_len = 19511da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 19521da177e4SLinus Torvalds sizeof(uint64_t); 19531da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 19541da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 19551da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_s; 19561da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 19571da177e4SLinus Torvalds /* src address */ 19581da177e4SLinus Torvalds if (xp->family == AF_INET) { 19591da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 19601da177e4SLinus Torvalds sin->sin_family = AF_INET; 19611da177e4SLinus Torvalds sin->sin_addr.s_addr = xp->selector.saddr.a4; 19621da177e4SLinus Torvalds sin->sin_port = xp->selector.sport; 19631da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 19641da177e4SLinus Torvalds } 19651da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19661da177e4SLinus Torvalds else if (xp->family == AF_INET6) { 19671da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 19681da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 19691da177e4SLinus Torvalds sin6->sin6_port = xp->selector.sport; 19701da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 19711da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, xp->selector.saddr.a6, 19721da177e4SLinus Torvalds sizeof(struct in6_addr)); 19731da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 19741da177e4SLinus Torvalds } 19751da177e4SLinus Torvalds #endif 19761da177e4SLinus Torvalds else 19771da177e4SLinus Torvalds BUG(); 19781da177e4SLinus Torvalds 19791da177e4SLinus Torvalds /* dst address */ 19801da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 19811da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 19821da177e4SLinus Torvalds addr->sadb_address_len = 19831da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 19841da177e4SLinus Torvalds sizeof(uint64_t); 19851da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 19861da177e4SLinus Torvalds addr->sadb_address_proto = pfkey_proto_from_xfrm(xp->selector.proto); 19871da177e4SLinus Torvalds addr->sadb_address_prefixlen = xp->selector.prefixlen_d; 19881da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 19891da177e4SLinus Torvalds if (xp->family == AF_INET) { 19901da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 19911da177e4SLinus Torvalds sin->sin_family = AF_INET; 19921da177e4SLinus Torvalds sin->sin_addr.s_addr = xp->selector.daddr.a4; 19931da177e4SLinus Torvalds sin->sin_port = xp->selector.dport; 19941da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 19951da177e4SLinus Torvalds } 19961da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 19971da177e4SLinus Torvalds else if (xp->family == AF_INET6) { 19981da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 19991da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 20001da177e4SLinus Torvalds sin6->sin6_port = xp->selector.dport; 20011da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 20021da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, xp->selector.daddr.a6, 20031da177e4SLinus Torvalds sizeof(struct in6_addr)); 20041da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 20051da177e4SLinus Torvalds } 20061da177e4SLinus Torvalds #endif 20071da177e4SLinus Torvalds else 20081da177e4SLinus Torvalds BUG(); 20091da177e4SLinus Torvalds 20101da177e4SLinus Torvalds /* hard time */ 20111da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20121da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20131da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20141da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20151da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_HARD; 20161da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.hard_packet_limit); 20171da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.hard_byte_limit); 20181da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.hard_add_expires_seconds; 20191da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.hard_use_expires_seconds; 20201da177e4SLinus Torvalds /* soft time */ 20211da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20221da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20231da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20241da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20251da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_SOFT; 20261da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = _X2KEY(xp->lft.soft_packet_limit); 20271da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = _X2KEY(xp->lft.soft_byte_limit); 20281da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->lft.soft_add_expires_seconds; 20291da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->lft.soft_use_expires_seconds; 20301da177e4SLinus Torvalds /* current time */ 20311da177e4SLinus Torvalds lifetime = (struct sadb_lifetime *) skb_put(skb, 20321da177e4SLinus Torvalds sizeof(struct sadb_lifetime)); 20331da177e4SLinus Torvalds lifetime->sadb_lifetime_len = 20341da177e4SLinus Torvalds sizeof(struct sadb_lifetime)/sizeof(uint64_t); 20351da177e4SLinus Torvalds lifetime->sadb_lifetime_exttype = SADB_EXT_LIFETIME_CURRENT; 20361da177e4SLinus Torvalds lifetime->sadb_lifetime_allocations = xp->curlft.packets; 20371da177e4SLinus Torvalds lifetime->sadb_lifetime_bytes = xp->curlft.bytes; 20381da177e4SLinus Torvalds lifetime->sadb_lifetime_addtime = xp->curlft.add_time; 20391da177e4SLinus Torvalds lifetime->sadb_lifetime_usetime = xp->curlft.use_time; 20401da177e4SLinus Torvalds 20411da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 20421da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 20431da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 20441da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_DISCARD; 20451da177e4SLinus Torvalds if (xp->action == XFRM_POLICY_ALLOW) { 20461da177e4SLinus Torvalds if (xp->xfrm_nr) 20471da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 20481da177e4SLinus Torvalds else 20491da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_NONE; 20501da177e4SLinus Torvalds } 20511da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 20521da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 20531da177e4SLinus Torvalds pol->sadb_x_policy_priority = xp->priority; 20541da177e4SLinus Torvalds 20551da177e4SLinus Torvalds for (i=0; i<xp->xfrm_nr; i++) { 20561da177e4SLinus Torvalds struct sadb_x_ipsecrequest *rq; 20571da177e4SLinus Torvalds struct xfrm_tmpl *t = xp->xfrm_vec + i; 20581da177e4SLinus Torvalds int req_size; 205955569ce2SKazunori MIYAZAWA int mode; 20601da177e4SLinus Torvalds 20611da177e4SLinus Torvalds req_size = sizeof(struct sadb_x_ipsecrequest); 20627e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) 20632718aa7cSMiika Komu req_size += ((t->encap_family == AF_INET ? 20642718aa7cSMiika Komu sizeof(struct sockaddr_in) : 20652718aa7cSMiika Komu sizeof(struct sockaddr_in6)) * 2); 20661da177e4SLinus Torvalds else 20671da177e4SLinus Torvalds size -= 2*socklen; 20681da177e4SLinus Torvalds rq = (void*)skb_put(skb, req_size); 20691da177e4SLinus Torvalds pol->sadb_x_policy_len += req_size/8; 20701da177e4SLinus Torvalds memset(rq, 0, sizeof(*rq)); 20711da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_len = req_size; 20721da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_proto = t->id.proto; 207355569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_from_xfrm(t->mode)) < 0) 207455569ce2SKazunori MIYAZAWA return -EINVAL; 2075*fefaa75eSDavid S. Miller rq->sadb_x_ipsecrequest_mode = mode; 20761da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_REQUIRE; 20771da177e4SLinus Torvalds if (t->reqid) 20781da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_UNIQUE; 20791da177e4SLinus Torvalds if (t->optional) 20801da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_level = IPSEC_LEVEL_USE; 20811da177e4SLinus Torvalds rq->sadb_x_ipsecrequest_reqid = t->reqid; 20827e49e6deSMasahide NAKAMURA if (t->mode == XFRM_MODE_TUNNEL) { 20832718aa7cSMiika Komu switch (t->encap_family) { 20841da177e4SLinus Torvalds case AF_INET: 20851da177e4SLinus Torvalds sin = (void*)(rq+1); 20861da177e4SLinus Torvalds sin->sin_family = AF_INET; 20871da177e4SLinus Torvalds sin->sin_addr.s_addr = t->saddr.a4; 20881da177e4SLinus Torvalds sin->sin_port = 0; 20891da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 20901da177e4SLinus Torvalds sin++; 20911da177e4SLinus Torvalds sin->sin_family = AF_INET; 20921da177e4SLinus Torvalds sin->sin_addr.s_addr = t->id.daddr.a4; 20931da177e4SLinus Torvalds sin->sin_port = 0; 20941da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 20951da177e4SLinus Torvalds break; 20961da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 20971da177e4SLinus Torvalds case AF_INET6: 20981da177e4SLinus Torvalds sin6 = (void*)(rq+1); 20991da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 21001da177e4SLinus Torvalds sin6->sin6_port = 0; 21011da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 21021da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, t->saddr.a6, 21031da177e4SLinus Torvalds sizeof(struct in6_addr)); 21041da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 21051da177e4SLinus Torvalds 21061da177e4SLinus Torvalds sin6++; 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->id.daddr.a6, 21111da177e4SLinus Torvalds sizeof(struct in6_addr)); 21121da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 21131da177e4SLinus Torvalds break; 21141da177e4SLinus Torvalds #endif 21151da177e4SLinus Torvalds default: 21161da177e4SLinus Torvalds break; 21171da177e4SLinus Torvalds } 21181da177e4SLinus Torvalds } 21191da177e4SLinus Torvalds } 2120df71837dSTrent Jaeger 2121df71837dSTrent Jaeger /* security context */ 2122df71837dSTrent Jaeger if ((xfrm_ctx = xp->security)) { 2123df71837dSTrent Jaeger int ctx_size = pfkey_xfrm_policy2sec_ctx_size(xp); 2124df71837dSTrent Jaeger 2125df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, ctx_size); 2126df71837dSTrent Jaeger sec_ctx->sadb_x_sec_len = ctx_size / sizeof(uint64_t); 2127df71837dSTrent Jaeger sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 2128df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 2129df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 2130df71837dSTrent Jaeger sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 2131df71837dSTrent Jaeger memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 2132df71837dSTrent Jaeger xfrm_ctx->ctx_len); 2133df71837dSTrent Jaeger } 2134df71837dSTrent Jaeger 21351da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 21361da177e4SLinus Torvalds hdr->sadb_msg_reserved = atomic_read(&xp->refcnt); 213755569ce2SKazunori MIYAZAWA 213855569ce2SKazunori MIYAZAWA return 0; 21391da177e4SLinus Torvalds } 21401da177e4SLinus Torvalds 214126b15dadSJamal Hadi Salim static int key_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) 214226b15dadSJamal Hadi Salim { 214326b15dadSJamal Hadi Salim struct sk_buff *out_skb; 214426b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 214526b15dadSJamal Hadi Salim int err; 214626b15dadSJamal Hadi Salim 214726b15dadSJamal Hadi Salim out_skb = pfkey_xfrm_policy2msg_prep(xp); 214826b15dadSJamal Hadi Salim if (IS_ERR(out_skb)) { 214926b15dadSJamal Hadi Salim err = PTR_ERR(out_skb); 215026b15dadSJamal Hadi Salim goto out; 215126b15dadSJamal Hadi Salim } 215255569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 215355569ce2SKazunori MIYAZAWA if (err < 0) 215455569ce2SKazunori MIYAZAWA return err; 215526b15dadSJamal Hadi Salim 215626b15dadSJamal Hadi Salim out_hdr = (struct sadb_msg *) out_skb->data; 215726b15dadSJamal Hadi Salim out_hdr->sadb_msg_version = PF_KEY_V2; 215826b15dadSJamal Hadi Salim 2159f60f6b8fSHerbert Xu if (c->data.byid && c->event == XFRM_MSG_DELPOLICY) 216026b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = SADB_X_SPDDELETE2; 216126b15dadSJamal Hadi Salim else 216226b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = event2poltype(c->event); 216326b15dadSJamal Hadi Salim out_hdr->sadb_msg_errno = 0; 216426b15dadSJamal Hadi Salim out_hdr->sadb_msg_seq = c->seq; 216526b15dadSJamal Hadi Salim out_hdr->sadb_msg_pid = c->pid; 216626b15dadSJamal Hadi Salim pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 216726b15dadSJamal Hadi Salim out: 216826b15dadSJamal Hadi Salim return 0; 216926b15dadSJamal Hadi Salim 217026b15dadSJamal Hadi Salim } 217126b15dadSJamal Hadi Salim 21721da177e4SLinus Torvalds static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 21731da177e4SLinus Torvalds { 2174df71837dSTrent Jaeger int err = 0; 21751da177e4SLinus Torvalds struct sadb_lifetime *lifetime; 21761da177e4SLinus Torvalds struct sadb_address *sa; 21771da177e4SLinus Torvalds struct sadb_x_policy *pol; 21781da177e4SLinus Torvalds struct xfrm_policy *xp; 217926b15dadSJamal Hadi Salim struct km_event c; 2180df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 21811da177e4SLinus Torvalds 21821da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 21831da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 21841da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 21851da177e4SLinus Torvalds return -EINVAL; 21861da177e4SLinus Torvalds 21871da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 21881da177e4SLinus Torvalds if (pol->sadb_x_policy_type > IPSEC_POLICY_IPSEC) 21891da177e4SLinus Torvalds return -EINVAL; 21901da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 21911da177e4SLinus Torvalds return -EINVAL; 21921da177e4SLinus Torvalds 21931da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_KERNEL); 21941da177e4SLinus Torvalds if (xp == NULL) 21951da177e4SLinus Torvalds return -ENOBUFS; 21961da177e4SLinus Torvalds 21971da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 21981da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 21991da177e4SLinus Torvalds xp->priority = pol->sadb_x_policy_priority; 22001da177e4SLinus Torvalds 22011da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 22021da177e4SLinus Torvalds xp->family = pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.saddr); 22031da177e4SLinus Torvalds if (!xp->family) { 22041da177e4SLinus Torvalds err = -EINVAL; 22051da177e4SLinus Torvalds goto out; 22061da177e4SLinus Torvalds } 22071da177e4SLinus Torvalds xp->selector.family = xp->family; 22081da177e4SLinus Torvalds xp->selector.prefixlen_s = sa->sadb_address_prefixlen; 22091da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22101da177e4SLinus Torvalds xp->selector.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 22111da177e4SLinus Torvalds if (xp->selector.sport) 22128f83f23eSAl Viro xp->selector.sport_mask = htons(0xffff); 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 22151da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &xp->selector.daddr); 22161da177e4SLinus Torvalds xp->selector.prefixlen_d = sa->sadb_address_prefixlen; 22171da177e4SLinus Torvalds 22181da177e4SLinus Torvalds /* Amusing, we set this twice. KAME apps appear to set same value 22191da177e4SLinus Torvalds * in both addresses. 22201da177e4SLinus Torvalds */ 22211da177e4SLinus Torvalds xp->selector.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 22221da177e4SLinus Torvalds 22231da177e4SLinus Torvalds xp->selector.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 22241da177e4SLinus Torvalds if (xp->selector.dport) 22258f83f23eSAl Viro xp->selector.dport_mask = htons(0xffff); 22261da177e4SLinus Torvalds 2227df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2228df71837dSTrent Jaeger if (sec_ctx != NULL) { 2229df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2230df71837dSTrent Jaeger 2231df71837dSTrent Jaeger if (!uctx) { 2232df71837dSTrent Jaeger err = -ENOBUFS; 2233df71837dSTrent Jaeger goto out; 2234df71837dSTrent Jaeger } 2235df71837dSTrent Jaeger 2236df71837dSTrent Jaeger err = security_xfrm_policy_alloc(xp, uctx); 2237df71837dSTrent Jaeger kfree(uctx); 2238df71837dSTrent Jaeger 2239df71837dSTrent Jaeger if (err) 2240df71837dSTrent Jaeger goto out; 2241df71837dSTrent Jaeger } 2242df71837dSTrent Jaeger 22431da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 22441da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 22451da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 22461da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 22471da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_HARD-1]) != NULL) { 22481da177e4SLinus Torvalds xp->lft.hard_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22491da177e4SLinus Torvalds xp->lft.hard_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22501da177e4SLinus Torvalds xp->lft.hard_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22511da177e4SLinus Torvalds xp->lft.hard_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22521da177e4SLinus Torvalds } 22531da177e4SLinus Torvalds if ((lifetime = ext_hdrs[SADB_EXT_LIFETIME_SOFT-1]) != NULL) { 22541da177e4SLinus Torvalds xp->lft.soft_packet_limit = _KEY2X(lifetime->sadb_lifetime_allocations); 22551da177e4SLinus Torvalds xp->lft.soft_byte_limit = _KEY2X(lifetime->sadb_lifetime_bytes); 22561da177e4SLinus Torvalds xp->lft.soft_add_expires_seconds = lifetime->sadb_lifetime_addtime; 22571da177e4SLinus Torvalds xp->lft.soft_use_expires_seconds = lifetime->sadb_lifetime_usetime; 22581da177e4SLinus Torvalds } 22591da177e4SLinus Torvalds xp->xfrm_nr = 0; 22601da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 22611da177e4SLinus Torvalds (err = parse_ipsecrequests(xp, pol)) < 0) 22621da177e4SLinus Torvalds goto out; 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds err = xfrm_policy_insert(pol->sadb_x_policy_dir-1, xp, 22651da177e4SLinus Torvalds hdr->sadb_msg_type != SADB_X_SPDUPDATE); 2266df71837dSTrent Jaeger 2267161a09e7SJoy Latten xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, 2268161a09e7SJoy Latten AUDIT_MAC_IPSEC_ADDSPD, err ? 0 : 1, xp, NULL); 2269161a09e7SJoy Latten 2270df71837dSTrent Jaeger if (err) 2271df71837dSTrent Jaeger goto out; 22721da177e4SLinus Torvalds 227326b15dadSJamal Hadi Salim if (hdr->sadb_msg_type == SADB_X_SPDUPDATE) 2274f60f6b8fSHerbert Xu c.event = XFRM_MSG_UPDPOLICY; 227526b15dadSJamal Hadi Salim else 2276f60f6b8fSHerbert Xu c.event = XFRM_MSG_NEWPOLICY; 22771da177e4SLinus Torvalds 227826b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 227926b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 228026b15dadSJamal Hadi Salim 228126b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 22821da177e4SLinus Torvalds xfrm_pol_put(xp); 22831da177e4SLinus Torvalds return 0; 22841da177e4SLinus Torvalds 22851da177e4SLinus Torvalds out: 2286df71837dSTrent Jaeger security_xfrm_policy_free(xp); 22871da177e4SLinus Torvalds kfree(xp); 22881da177e4SLinus Torvalds return err; 22891da177e4SLinus Torvalds } 22901da177e4SLinus Torvalds 22911da177e4SLinus Torvalds static int pfkey_spddelete(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 22921da177e4SLinus Torvalds { 22931da177e4SLinus Torvalds int err; 22941da177e4SLinus Torvalds struct sadb_address *sa; 22951da177e4SLinus Torvalds struct sadb_x_policy *pol; 2296df71837dSTrent Jaeger struct xfrm_policy *xp, tmp; 22971da177e4SLinus Torvalds struct xfrm_selector sel; 229826b15dadSJamal Hadi Salim struct km_event c; 2299df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 23001da177e4SLinus Torvalds 23011da177e4SLinus Torvalds if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23021da177e4SLinus Torvalds ext_hdrs[SADB_EXT_ADDRESS_DST-1]) || 23031da177e4SLinus Torvalds !ext_hdrs[SADB_X_EXT_POLICY-1]) 23041da177e4SLinus Torvalds return -EINVAL; 23051da177e4SLinus Torvalds 23061da177e4SLinus Torvalds pol = ext_hdrs[SADB_X_EXT_POLICY-1]; 23071da177e4SLinus Torvalds if (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) 23081da177e4SLinus Torvalds return -EINVAL; 23091da177e4SLinus Torvalds 23101da177e4SLinus Torvalds memset(&sel, 0, sizeof(sel)); 23111da177e4SLinus Torvalds 23121da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_SRC-1], 23131da177e4SLinus Torvalds sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 23141da177e4SLinus Torvalds sel.prefixlen_s = sa->sadb_address_prefixlen; 23151da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23161da177e4SLinus Torvalds sel.sport = ((struct sockaddr_in *)(sa+1))->sin_port; 23171da177e4SLinus Torvalds if (sel.sport) 23188f83f23eSAl Viro sel.sport_mask = htons(0xffff); 23191da177e4SLinus Torvalds 23201da177e4SLinus Torvalds sa = ext_hdrs[SADB_EXT_ADDRESS_DST-1], 23211da177e4SLinus Torvalds pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 23221da177e4SLinus Torvalds sel.prefixlen_d = sa->sadb_address_prefixlen; 23231da177e4SLinus Torvalds sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 23241da177e4SLinus Torvalds sel.dport = ((struct sockaddr_in *)(sa+1))->sin_port; 23251da177e4SLinus Torvalds if (sel.dport) 23268f83f23eSAl Viro sel.dport_mask = htons(0xffff); 23271da177e4SLinus Torvalds 2328df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *) ext_hdrs[SADB_X_EXT_SEC_CTX-1]; 2329df71837dSTrent Jaeger memset(&tmp, 0, sizeof(struct xfrm_policy)); 2330df71837dSTrent Jaeger 2331df71837dSTrent Jaeger if (sec_ctx != NULL) { 2332df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 2333df71837dSTrent Jaeger 2334df71837dSTrent Jaeger if (!uctx) 2335df71837dSTrent Jaeger return -ENOMEM; 2336df71837dSTrent Jaeger 2337df71837dSTrent Jaeger err = security_xfrm_policy_alloc(&tmp, uctx); 2338df71837dSTrent Jaeger kfree(uctx); 2339df71837dSTrent Jaeger 2340df71837dSTrent Jaeger if (err) 2341df71837dSTrent Jaeger return err; 2342df71837dSTrent Jaeger } 2343df71837dSTrent Jaeger 2344f7b6983fSMasahide NAKAMURA xp = xfrm_policy_bysel_ctx(XFRM_POLICY_TYPE_MAIN, pol->sadb_x_policy_dir-1, 2345ef41aaa0SEric Paris &sel, tmp.security, 1, &err); 2346df71837dSTrent Jaeger security_xfrm_policy_free(&tmp); 2347161a09e7SJoy Latten 23481da177e4SLinus Torvalds if (xp == NULL) 23491da177e4SLinus Torvalds return -ENOENT; 23501da177e4SLinus Torvalds 235113fcfbb0SDavid S. Miller xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, 235213fcfbb0SDavid S. Miller AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); 235313fcfbb0SDavid S. Miller 235413fcfbb0SDavid S. Miller if (err) 2355c8c05a8eSCatherine Zhang goto out; 235613fcfbb0SDavid S. Miller 235726b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 235826b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 2359f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 236026b15dadSJamal Hadi Salim km_policy_notify(xp, pol->sadb_x_policy_dir-1, &c); 236126b15dadSJamal Hadi Salim 2362c8c05a8eSCatherine Zhang out: 236326b15dadSJamal Hadi Salim xfrm_pol_put(xp); 236426b15dadSJamal Hadi Salim return err; 236526b15dadSJamal Hadi Salim } 236626b15dadSJamal Hadi Salim 236726b15dadSJamal Hadi Salim static int key_pol_get_resp(struct sock *sk, struct xfrm_policy *xp, struct sadb_msg *hdr, int dir) 236826b15dadSJamal Hadi Salim { 236926b15dadSJamal Hadi Salim int err; 237026b15dadSJamal Hadi Salim struct sk_buff *out_skb; 237126b15dadSJamal Hadi Salim struct sadb_msg *out_hdr; 237226b15dadSJamal Hadi Salim err = 0; 237326b15dadSJamal Hadi Salim 23741da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 23751da177e4SLinus Torvalds if (IS_ERR(out_skb)) { 23761da177e4SLinus Torvalds err = PTR_ERR(out_skb); 23771da177e4SLinus Torvalds goto out; 23781da177e4SLinus Torvalds } 237955569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 238055569ce2SKazunori MIYAZAWA if (err < 0) 238155569ce2SKazunori MIYAZAWA goto out; 23821da177e4SLinus Torvalds 23831da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 23841da177e4SLinus Torvalds out_hdr->sadb_msg_version = hdr->sadb_msg_version; 238526b15dadSJamal Hadi Salim out_hdr->sadb_msg_type = hdr->sadb_msg_type; 23861da177e4SLinus Torvalds out_hdr->sadb_msg_satype = 0; 23871da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 23881da177e4SLinus Torvalds out_hdr->sadb_msg_seq = hdr->sadb_msg_seq; 23891da177e4SLinus Torvalds out_hdr->sadb_msg_pid = hdr->sadb_msg_pid; 239026b15dadSJamal Hadi Salim pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, sk); 23911da177e4SLinus Torvalds err = 0; 23921da177e4SLinus Torvalds 23931da177e4SLinus Torvalds out: 23941da177e4SLinus Torvalds return err; 23951da177e4SLinus Torvalds } 23961da177e4SLinus Torvalds 239708de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 239808de61beSShinta Sugimoto static int pfkey_sockaddr_pair_size(sa_family_t family) 239908de61beSShinta Sugimoto { 240008de61beSShinta Sugimoto switch (family) { 240108de61beSShinta Sugimoto case AF_INET: 240208de61beSShinta Sugimoto return PFKEY_ALIGN8(sizeof(struct sockaddr_in) * 2); 240308de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 240408de61beSShinta Sugimoto case AF_INET6: 240508de61beSShinta Sugimoto return PFKEY_ALIGN8(sizeof(struct sockaddr_in6) * 2); 240608de61beSShinta Sugimoto #endif 240708de61beSShinta Sugimoto default: 240808de61beSShinta Sugimoto return 0; 240908de61beSShinta Sugimoto } 241008de61beSShinta Sugimoto /* NOTREACHED */ 241108de61beSShinta Sugimoto } 241208de61beSShinta Sugimoto 241308de61beSShinta Sugimoto static int parse_sockaddr_pair(struct sadb_x_ipsecrequest *rq, 241408de61beSShinta Sugimoto xfrm_address_t *saddr, xfrm_address_t *daddr, 241508de61beSShinta Sugimoto u16 *family) 241608de61beSShinta Sugimoto { 241708de61beSShinta Sugimoto struct sockaddr *sa = (struct sockaddr *)(rq + 1); 241808de61beSShinta Sugimoto if (rq->sadb_x_ipsecrequest_len < 241908de61beSShinta Sugimoto pfkey_sockaddr_pair_size(sa->sa_family)) 242008de61beSShinta Sugimoto return -EINVAL; 242108de61beSShinta Sugimoto 242208de61beSShinta Sugimoto switch (sa->sa_family) { 242308de61beSShinta Sugimoto case AF_INET: 242408de61beSShinta Sugimoto { 242508de61beSShinta Sugimoto struct sockaddr_in *sin; 242608de61beSShinta Sugimoto sin = (struct sockaddr_in *)sa; 242708de61beSShinta Sugimoto if ((sin+1)->sin_family != AF_INET) 242808de61beSShinta Sugimoto return -EINVAL; 242908de61beSShinta Sugimoto memcpy(&saddr->a4, &sin->sin_addr, sizeof(saddr->a4)); 243008de61beSShinta Sugimoto sin++; 243108de61beSShinta Sugimoto memcpy(&daddr->a4, &sin->sin_addr, sizeof(daddr->a4)); 243208de61beSShinta Sugimoto *family = AF_INET; 243308de61beSShinta Sugimoto break; 243408de61beSShinta Sugimoto } 243508de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 243608de61beSShinta Sugimoto case AF_INET6: 243708de61beSShinta Sugimoto { 243808de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 243908de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)sa; 244008de61beSShinta Sugimoto if ((sin6+1)->sin6_family != AF_INET6) 244108de61beSShinta Sugimoto return -EINVAL; 244208de61beSShinta Sugimoto memcpy(&saddr->a6, &sin6->sin6_addr, 244308de61beSShinta Sugimoto sizeof(saddr->a6)); 244408de61beSShinta Sugimoto sin6++; 244508de61beSShinta Sugimoto memcpy(&daddr->a6, &sin6->sin6_addr, 244608de61beSShinta Sugimoto sizeof(daddr->a6)); 244708de61beSShinta Sugimoto *family = AF_INET6; 244808de61beSShinta Sugimoto break; 244908de61beSShinta Sugimoto } 245008de61beSShinta Sugimoto #endif 245108de61beSShinta Sugimoto default: 245208de61beSShinta Sugimoto return -EINVAL; 245308de61beSShinta Sugimoto } 245408de61beSShinta Sugimoto 245508de61beSShinta Sugimoto return 0; 245608de61beSShinta Sugimoto } 245708de61beSShinta Sugimoto 245808de61beSShinta Sugimoto static int ipsecrequests_to_migrate(struct sadb_x_ipsecrequest *rq1, int len, 245908de61beSShinta Sugimoto struct xfrm_migrate *m) 246008de61beSShinta Sugimoto { 246108de61beSShinta Sugimoto int err; 246208de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq2; 246355569ce2SKazunori MIYAZAWA int mode; 246408de61beSShinta Sugimoto 246508de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 246608de61beSShinta Sugimoto len < rq1->sadb_x_ipsecrequest_len) 246708de61beSShinta Sugimoto return -EINVAL; 246808de61beSShinta Sugimoto 246908de61beSShinta Sugimoto /* old endoints */ 247008de61beSShinta Sugimoto err = parse_sockaddr_pair(rq1, &m->old_saddr, &m->old_daddr, 247108de61beSShinta Sugimoto &m->old_family); 247208de61beSShinta Sugimoto if (err) 247308de61beSShinta Sugimoto return err; 247408de61beSShinta Sugimoto 247508de61beSShinta Sugimoto rq2 = (struct sadb_x_ipsecrequest *)((u8 *)rq1 + rq1->sadb_x_ipsecrequest_len); 247608de61beSShinta Sugimoto len -= rq1->sadb_x_ipsecrequest_len; 247708de61beSShinta Sugimoto 247808de61beSShinta Sugimoto if (len <= sizeof(struct sadb_x_ipsecrequest) || 247908de61beSShinta Sugimoto len < rq2->sadb_x_ipsecrequest_len) 248008de61beSShinta Sugimoto return -EINVAL; 248108de61beSShinta Sugimoto 248208de61beSShinta Sugimoto /* new endpoints */ 248308de61beSShinta Sugimoto err = parse_sockaddr_pair(rq2, &m->new_saddr, &m->new_daddr, 248408de61beSShinta Sugimoto &m->new_family); 248508de61beSShinta Sugimoto if (err) 248608de61beSShinta Sugimoto return err; 248708de61beSShinta Sugimoto 248808de61beSShinta Sugimoto if (rq1->sadb_x_ipsecrequest_proto != rq2->sadb_x_ipsecrequest_proto || 248908de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_mode != rq2->sadb_x_ipsecrequest_mode || 249008de61beSShinta Sugimoto rq1->sadb_x_ipsecrequest_reqid != rq2->sadb_x_ipsecrequest_reqid) 249108de61beSShinta Sugimoto return -EINVAL; 249208de61beSShinta Sugimoto 249308de61beSShinta Sugimoto m->proto = rq1->sadb_x_ipsecrequest_proto; 249455569ce2SKazunori MIYAZAWA if ((mode = pfkey_mode_to_xfrm(rq1->sadb_x_ipsecrequest_mode)) < 0) 249555569ce2SKazunori MIYAZAWA return -EINVAL; 249655569ce2SKazunori MIYAZAWA m->mode = mode; 249708de61beSShinta Sugimoto m->reqid = rq1->sadb_x_ipsecrequest_reqid; 249808de61beSShinta Sugimoto 249908de61beSShinta Sugimoto return ((int)(rq1->sadb_x_ipsecrequest_len + 250008de61beSShinta Sugimoto rq2->sadb_x_ipsecrequest_len)); 250108de61beSShinta Sugimoto } 250208de61beSShinta Sugimoto 250308de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 250408de61beSShinta Sugimoto struct sadb_msg *hdr, void **ext_hdrs) 250508de61beSShinta Sugimoto { 250608de61beSShinta Sugimoto int i, len, ret, err = -EINVAL; 250708de61beSShinta Sugimoto u8 dir; 250808de61beSShinta Sugimoto struct sadb_address *sa; 250908de61beSShinta Sugimoto struct sadb_x_policy *pol; 251008de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 251108de61beSShinta Sugimoto struct xfrm_selector sel; 251208de61beSShinta Sugimoto struct xfrm_migrate m[XFRM_MAX_DEPTH]; 251308de61beSShinta Sugimoto 251408de61beSShinta Sugimoto if (!present_and_same_family(ext_hdrs[SADB_EXT_ADDRESS_SRC - 1], 251508de61beSShinta Sugimoto ext_hdrs[SADB_EXT_ADDRESS_DST - 1]) || 251608de61beSShinta Sugimoto !ext_hdrs[SADB_X_EXT_POLICY - 1]) { 251708de61beSShinta Sugimoto err = -EINVAL; 251808de61beSShinta Sugimoto goto out; 251908de61beSShinta Sugimoto } 252008de61beSShinta Sugimoto 252108de61beSShinta Sugimoto pol = ext_hdrs[SADB_X_EXT_POLICY - 1]; 252208de61beSShinta Sugimoto if (!pol) { 252308de61beSShinta Sugimoto err = -EINVAL; 252408de61beSShinta Sugimoto goto out; 252508de61beSShinta Sugimoto } 252608de61beSShinta Sugimoto 252708de61beSShinta Sugimoto if (pol->sadb_x_policy_dir >= IPSEC_DIR_MAX) { 252808de61beSShinta Sugimoto err = -EINVAL; 252908de61beSShinta Sugimoto goto out; 253008de61beSShinta Sugimoto } 253108de61beSShinta Sugimoto 253208de61beSShinta Sugimoto dir = pol->sadb_x_policy_dir - 1; 253308de61beSShinta Sugimoto memset(&sel, 0, sizeof(sel)); 253408de61beSShinta Sugimoto 253508de61beSShinta Sugimoto /* set source address info of selector */ 253608de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_SRC - 1]; 253708de61beSShinta Sugimoto sel.family = pfkey_sadb_addr2xfrm_addr(sa, &sel.saddr); 253808de61beSShinta Sugimoto sel.prefixlen_s = sa->sadb_address_prefixlen; 253908de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 254008de61beSShinta Sugimoto sel.sport = ((struct sockaddr_in *)(sa + 1))->sin_port; 254108de61beSShinta Sugimoto if (sel.sport) 254208de61beSShinta Sugimoto sel.sport_mask = ~0; 254308de61beSShinta Sugimoto 254408de61beSShinta Sugimoto /* set destination address info of selector */ 254508de61beSShinta Sugimoto sa = ext_hdrs[SADB_EXT_ADDRESS_DST - 1], 254608de61beSShinta Sugimoto pfkey_sadb_addr2xfrm_addr(sa, &sel.daddr); 254708de61beSShinta Sugimoto sel.prefixlen_d = sa->sadb_address_prefixlen; 254808de61beSShinta Sugimoto sel.proto = pfkey_proto_to_xfrm(sa->sadb_address_proto); 254908de61beSShinta Sugimoto sel.dport = ((struct sockaddr_in *)(sa + 1))->sin_port; 255008de61beSShinta Sugimoto if (sel.dport) 255108de61beSShinta Sugimoto sel.dport_mask = ~0; 255208de61beSShinta Sugimoto 255308de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)(pol + 1); 255408de61beSShinta Sugimoto 255508de61beSShinta Sugimoto /* extract ipsecrequests */ 255608de61beSShinta Sugimoto i = 0; 255708de61beSShinta Sugimoto len = pol->sadb_x_policy_len * 8 - sizeof(struct sadb_x_policy); 255808de61beSShinta Sugimoto 255908de61beSShinta Sugimoto while (len > 0 && i < XFRM_MAX_DEPTH) { 256008de61beSShinta Sugimoto ret = ipsecrequests_to_migrate(rq, len, &m[i]); 256108de61beSShinta Sugimoto if (ret < 0) { 256208de61beSShinta Sugimoto err = ret; 256308de61beSShinta Sugimoto goto out; 256408de61beSShinta Sugimoto } else { 256508de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)((u8 *)rq + ret); 256608de61beSShinta Sugimoto len -= ret; 256708de61beSShinta Sugimoto i++; 256808de61beSShinta Sugimoto } 256908de61beSShinta Sugimoto } 257008de61beSShinta Sugimoto 257108de61beSShinta Sugimoto if (!i || len > 0) { 257208de61beSShinta Sugimoto err = -EINVAL; 257308de61beSShinta Sugimoto goto out; 257408de61beSShinta Sugimoto } 257508de61beSShinta Sugimoto 257608de61beSShinta Sugimoto return xfrm_migrate(&sel, dir, XFRM_POLICY_TYPE_MAIN, m, i); 257708de61beSShinta Sugimoto 257808de61beSShinta Sugimoto out: 257908de61beSShinta Sugimoto return err; 258008de61beSShinta Sugimoto } 258108de61beSShinta Sugimoto #else 258208de61beSShinta Sugimoto static int pfkey_migrate(struct sock *sk, struct sk_buff *skb, 258308de61beSShinta Sugimoto struct sadb_msg *hdr, void **ext_hdrs) 258408de61beSShinta Sugimoto { 258508de61beSShinta Sugimoto return -ENOPROTOOPT; 258608de61beSShinta Sugimoto } 258708de61beSShinta Sugimoto #endif 258808de61beSShinta Sugimoto 258908de61beSShinta Sugimoto 25901da177e4SLinus Torvalds static int pfkey_spdget(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 25911da177e4SLinus Torvalds { 259277d8d7a6SHerbert Xu unsigned int dir; 2593215a2dd3SEric Paris int err = 0, delete; 25941da177e4SLinus Torvalds struct sadb_x_policy *pol; 25951da177e4SLinus Torvalds struct xfrm_policy *xp; 259626b15dadSJamal Hadi Salim struct km_event c; 25971da177e4SLinus Torvalds 25981da177e4SLinus Torvalds if ((pol = ext_hdrs[SADB_X_EXT_POLICY-1]) == NULL) 25991da177e4SLinus Torvalds return -EINVAL; 26001da177e4SLinus Torvalds 260177d8d7a6SHerbert Xu dir = xfrm_policy_id2dir(pol->sadb_x_policy_id); 260277d8d7a6SHerbert Xu if (dir >= XFRM_POLICY_MAX) 260377d8d7a6SHerbert Xu return -EINVAL; 260477d8d7a6SHerbert Xu 2605215a2dd3SEric Paris delete = (hdr->sadb_msg_type == SADB_X_SPDDELETE2); 2606f7b6983fSMasahide NAKAMURA xp = xfrm_policy_byid(XFRM_POLICY_TYPE_MAIN, dir, pol->sadb_x_policy_id, 2607215a2dd3SEric Paris delete, &err); 26081da177e4SLinus Torvalds if (xp == NULL) 26091da177e4SLinus Torvalds return -ENOENT; 26101da177e4SLinus Torvalds 2611215a2dd3SEric Paris if (delete) { 2612215a2dd3SEric Paris xfrm_audit_log(audit_get_loginuid(current->audit_context), 0, 2613215a2dd3SEric Paris AUDIT_MAC_IPSEC_DELSPD, err ? 0 : 1, xp, NULL); 26141da177e4SLinus Torvalds 2615215a2dd3SEric Paris if (err) 2616215a2dd3SEric Paris goto out; 261726b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 261826b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 2619bf08867fSHerbert Xu c.data.byid = 1; 2620f60f6b8fSHerbert Xu c.event = XFRM_MSG_DELPOLICY; 262177d8d7a6SHerbert Xu km_policy_notify(xp, dir, &c); 262226b15dadSJamal Hadi Salim } else { 262377d8d7a6SHerbert Xu err = key_pol_get_resp(sk, xp, hdr, dir); 26241da177e4SLinus Torvalds } 26251da177e4SLinus Torvalds 2626215a2dd3SEric Paris out: 26271da177e4SLinus Torvalds xfrm_pol_put(xp); 26281da177e4SLinus Torvalds return err; 26291da177e4SLinus Torvalds } 26301da177e4SLinus Torvalds 26311da177e4SLinus Torvalds static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr) 26321da177e4SLinus Torvalds { 26331da177e4SLinus Torvalds struct pfkey_dump_data *data = ptr; 26341da177e4SLinus Torvalds struct sk_buff *out_skb; 26351da177e4SLinus Torvalds struct sadb_msg *out_hdr; 263655569ce2SKazunori MIYAZAWA int err; 26371da177e4SLinus Torvalds 26381da177e4SLinus Torvalds out_skb = pfkey_xfrm_policy2msg_prep(xp); 26391da177e4SLinus Torvalds if (IS_ERR(out_skb)) 26401da177e4SLinus Torvalds return PTR_ERR(out_skb); 26411da177e4SLinus Torvalds 264255569ce2SKazunori MIYAZAWA err = pfkey_xfrm_policy2msg(out_skb, xp, dir); 264355569ce2SKazunori MIYAZAWA if (err < 0) 264455569ce2SKazunori MIYAZAWA return err; 26451da177e4SLinus Torvalds 26461da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 26471da177e4SLinus Torvalds out_hdr->sadb_msg_version = data->hdr->sadb_msg_version; 26481da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_X_SPDDUMP; 26491da177e4SLinus Torvalds out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC; 26501da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 26511da177e4SLinus Torvalds out_hdr->sadb_msg_seq = count; 26521da177e4SLinus Torvalds out_hdr->sadb_msg_pid = data->hdr->sadb_msg_pid; 26531da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, data->sk); 26541da177e4SLinus Torvalds return 0; 26551da177e4SLinus Torvalds } 26561da177e4SLinus Torvalds 26571da177e4SLinus Torvalds static int pfkey_spddump(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 26581da177e4SLinus Torvalds { 26591da177e4SLinus Torvalds struct pfkey_dump_data data = { .skb = skb, .hdr = hdr, .sk = sk }; 26601da177e4SLinus Torvalds 2661f7b6983fSMasahide NAKAMURA return xfrm_policy_walk(XFRM_POLICY_TYPE_MAIN, dump_sp, &data); 26621da177e4SLinus Torvalds } 26631da177e4SLinus Torvalds 266426b15dadSJamal Hadi Salim static int key_notify_policy_flush(struct km_event *c) 26651da177e4SLinus Torvalds { 26661da177e4SLinus Torvalds struct sk_buff *skb_out; 266726b15dadSJamal Hadi Salim struct sadb_msg *hdr; 26681da177e4SLinus Torvalds 266926b15dadSJamal Hadi Salim skb_out = alloc_skb(sizeof(struct sadb_msg) + 16, GFP_ATOMIC); 26701da177e4SLinus Torvalds if (!skb_out) 26711da177e4SLinus Torvalds return -ENOBUFS; 267226b15dadSJamal Hadi Salim hdr = (struct sadb_msg *) skb_put(skb_out, sizeof(struct sadb_msg)); 2673151bb0ffSJerome Borsboom hdr->sadb_msg_type = SADB_X_SPDFLUSH; 267426b15dadSJamal Hadi Salim hdr->sadb_msg_seq = c->seq; 267526b15dadSJamal Hadi Salim hdr->sadb_msg_pid = c->pid; 267626b15dadSJamal Hadi Salim hdr->sadb_msg_version = PF_KEY_V2; 267726b15dadSJamal Hadi Salim hdr->sadb_msg_errno = (uint8_t) 0; 267826b15dadSJamal Hadi Salim hdr->sadb_msg_len = (sizeof(struct sadb_msg) / sizeof(uint64_t)); 267926b15dadSJamal Hadi Salim pfkey_broadcast(skb_out, GFP_ATOMIC, BROADCAST_ALL, NULL); 268026b15dadSJamal Hadi Salim return 0; 268126b15dadSJamal Hadi Salim 268226b15dadSJamal Hadi Salim } 268326b15dadSJamal Hadi Salim 268426b15dadSJamal Hadi Salim static int pfkey_spdflush(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr, void **ext_hdrs) 268526b15dadSJamal Hadi Salim { 268626b15dadSJamal Hadi Salim struct km_event c; 2687161a09e7SJoy Latten struct xfrm_audit audit_info; 26881da177e4SLinus Torvalds 2689161a09e7SJoy Latten audit_info.loginuid = audit_get_loginuid(current->audit_context); 2690161a09e7SJoy Latten audit_info.secid = 0; 2691161a09e7SJoy Latten xfrm_policy_flush(XFRM_POLICY_TYPE_MAIN, &audit_info); 2692f7b6983fSMasahide NAKAMURA c.data.type = XFRM_POLICY_TYPE_MAIN; 2693f60f6b8fSHerbert Xu c.event = XFRM_MSG_FLUSHPOLICY; 269426b15dadSJamal Hadi Salim c.pid = hdr->sadb_msg_pid; 269526b15dadSJamal Hadi Salim c.seq = hdr->sadb_msg_seq; 269626b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 26971da177e4SLinus Torvalds 26981da177e4SLinus Torvalds return 0; 26991da177e4SLinus Torvalds } 27001da177e4SLinus Torvalds 27011da177e4SLinus Torvalds typedef int (*pfkey_handler)(struct sock *sk, struct sk_buff *skb, 27021da177e4SLinus Torvalds struct sadb_msg *hdr, void **ext_hdrs); 27031da177e4SLinus Torvalds static pfkey_handler pfkey_funcs[SADB_MAX + 1] = { 27041da177e4SLinus Torvalds [SADB_RESERVED] = pfkey_reserved, 27051da177e4SLinus Torvalds [SADB_GETSPI] = pfkey_getspi, 27061da177e4SLinus Torvalds [SADB_UPDATE] = pfkey_add, 27071da177e4SLinus Torvalds [SADB_ADD] = pfkey_add, 27081da177e4SLinus Torvalds [SADB_DELETE] = pfkey_delete, 27091da177e4SLinus Torvalds [SADB_GET] = pfkey_get, 27101da177e4SLinus Torvalds [SADB_ACQUIRE] = pfkey_acquire, 27111da177e4SLinus Torvalds [SADB_REGISTER] = pfkey_register, 27121da177e4SLinus Torvalds [SADB_EXPIRE] = NULL, 27131da177e4SLinus Torvalds [SADB_FLUSH] = pfkey_flush, 27141da177e4SLinus Torvalds [SADB_DUMP] = pfkey_dump, 27151da177e4SLinus Torvalds [SADB_X_PROMISC] = pfkey_promisc, 27161da177e4SLinus Torvalds [SADB_X_PCHANGE] = NULL, 27171da177e4SLinus Torvalds [SADB_X_SPDUPDATE] = pfkey_spdadd, 27181da177e4SLinus Torvalds [SADB_X_SPDADD] = pfkey_spdadd, 27191da177e4SLinus Torvalds [SADB_X_SPDDELETE] = pfkey_spddelete, 27201da177e4SLinus Torvalds [SADB_X_SPDGET] = pfkey_spdget, 27211da177e4SLinus Torvalds [SADB_X_SPDACQUIRE] = NULL, 27221da177e4SLinus Torvalds [SADB_X_SPDDUMP] = pfkey_spddump, 27231da177e4SLinus Torvalds [SADB_X_SPDFLUSH] = pfkey_spdflush, 27241da177e4SLinus Torvalds [SADB_X_SPDSETIDX] = pfkey_spdadd, 27251da177e4SLinus Torvalds [SADB_X_SPDDELETE2] = pfkey_spdget, 272608de61beSShinta Sugimoto [SADB_X_MIGRATE] = pfkey_migrate, 27271da177e4SLinus Torvalds }; 27281da177e4SLinus Torvalds 27291da177e4SLinus Torvalds static int pfkey_process(struct sock *sk, struct sk_buff *skb, struct sadb_msg *hdr) 27301da177e4SLinus Torvalds { 27311da177e4SLinus Torvalds void *ext_hdrs[SADB_EXT_MAX]; 27321da177e4SLinus Torvalds int err; 27331da177e4SLinus Torvalds 27341da177e4SLinus Torvalds pfkey_broadcast(skb_clone(skb, GFP_KERNEL), GFP_KERNEL, 27351da177e4SLinus Torvalds BROADCAST_PROMISC_ONLY, NULL); 27361da177e4SLinus Torvalds 27371da177e4SLinus Torvalds memset(ext_hdrs, 0, sizeof(ext_hdrs)); 27381da177e4SLinus Torvalds err = parse_exthdrs(skb, hdr, ext_hdrs); 27391da177e4SLinus Torvalds if (!err) { 27401da177e4SLinus Torvalds err = -EOPNOTSUPP; 27411da177e4SLinus Torvalds if (pfkey_funcs[hdr->sadb_msg_type]) 27421da177e4SLinus Torvalds err = pfkey_funcs[hdr->sadb_msg_type](sk, skb, hdr, ext_hdrs); 27431da177e4SLinus Torvalds } 27441da177e4SLinus Torvalds return err; 27451da177e4SLinus Torvalds } 27461da177e4SLinus Torvalds 27471da177e4SLinus Torvalds static struct sadb_msg *pfkey_get_base_msg(struct sk_buff *skb, int *errp) 27481da177e4SLinus Torvalds { 27491da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 27501da177e4SLinus Torvalds 27511da177e4SLinus Torvalds if (skb->len < sizeof(*hdr)) { 27521da177e4SLinus Torvalds *errp = -EMSGSIZE; 27531da177e4SLinus Torvalds } else { 27541da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb->data; 27551da177e4SLinus Torvalds if (hdr->sadb_msg_version != PF_KEY_V2 || 27561da177e4SLinus Torvalds hdr->sadb_msg_reserved != 0 || 27571da177e4SLinus Torvalds (hdr->sadb_msg_type <= SADB_RESERVED || 27581da177e4SLinus Torvalds hdr->sadb_msg_type > SADB_MAX)) { 27591da177e4SLinus Torvalds hdr = NULL; 27601da177e4SLinus Torvalds *errp = -EINVAL; 27611da177e4SLinus Torvalds } else if (hdr->sadb_msg_len != (skb->len / 27621da177e4SLinus Torvalds sizeof(uint64_t)) || 27631da177e4SLinus Torvalds hdr->sadb_msg_len < (sizeof(struct sadb_msg) / 27641da177e4SLinus Torvalds sizeof(uint64_t))) { 27651da177e4SLinus Torvalds hdr = NULL; 27661da177e4SLinus Torvalds *errp = -EMSGSIZE; 27671da177e4SLinus Torvalds } else { 27681da177e4SLinus Torvalds *errp = 0; 27691da177e4SLinus Torvalds } 27701da177e4SLinus Torvalds } 27711da177e4SLinus Torvalds return hdr; 27721da177e4SLinus Torvalds } 27731da177e4SLinus Torvalds 27741da177e4SLinus Torvalds static inline int aalg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) 27751da177e4SLinus Torvalds { 27761da177e4SLinus Torvalds return t->aalgos & (1 << d->desc.sadb_alg_id); 27771da177e4SLinus Torvalds } 27781da177e4SLinus Torvalds 27791da177e4SLinus Torvalds static inline int ealg_tmpl_set(struct xfrm_tmpl *t, struct xfrm_algo_desc *d) 27801da177e4SLinus Torvalds { 27811da177e4SLinus Torvalds return t->ealgos & (1 << d->desc.sadb_alg_id); 27821da177e4SLinus Torvalds } 27831da177e4SLinus Torvalds 27841da177e4SLinus Torvalds static int count_ah_combs(struct xfrm_tmpl *t) 27851da177e4SLinus Torvalds { 27861da177e4SLinus Torvalds int i, sz = 0; 27871da177e4SLinus Torvalds 27881da177e4SLinus Torvalds for (i = 0; ; i++) { 27891da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 27901da177e4SLinus Torvalds if (!aalg) 27911da177e4SLinus Torvalds break; 27921da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 27931da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 27941da177e4SLinus Torvalds } 27951da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 27961da177e4SLinus Torvalds } 27971da177e4SLinus Torvalds 27981da177e4SLinus Torvalds static int count_esp_combs(struct xfrm_tmpl *t) 27991da177e4SLinus Torvalds { 28001da177e4SLinus Torvalds int i, k, sz = 0; 28011da177e4SLinus Torvalds 28021da177e4SLinus Torvalds for (i = 0; ; i++) { 28031da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 28041da177e4SLinus Torvalds if (!ealg) 28051da177e4SLinus Torvalds break; 28061da177e4SLinus Torvalds 28071da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 28081da177e4SLinus Torvalds continue; 28091da177e4SLinus Torvalds 28101da177e4SLinus Torvalds for (k = 1; ; k++) { 28111da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 28121da177e4SLinus Torvalds if (!aalg) 28131da177e4SLinus Torvalds break; 28141da177e4SLinus Torvalds 28151da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) 28161da177e4SLinus Torvalds sz += sizeof(struct sadb_comb); 28171da177e4SLinus Torvalds } 28181da177e4SLinus Torvalds } 28191da177e4SLinus Torvalds return sz + sizeof(struct sadb_prop); 28201da177e4SLinus Torvalds } 28211da177e4SLinus Torvalds 28221da177e4SLinus Torvalds static void dump_ah_combs(struct sk_buff *skb, struct xfrm_tmpl *t) 28231da177e4SLinus Torvalds { 28241da177e4SLinus Torvalds struct sadb_prop *p; 28251da177e4SLinus Torvalds int i; 28261da177e4SLinus Torvalds 28271da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28281da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28291da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28301da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28311da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28321da177e4SLinus Torvalds 28331da177e4SLinus Torvalds for (i = 0; ; i++) { 28341da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(i); 28351da177e4SLinus Torvalds if (!aalg) 28361da177e4SLinus Torvalds break; 28371da177e4SLinus Torvalds 28381da177e4SLinus Torvalds if (aalg_tmpl_set(t, aalg) && aalg->available) { 28391da177e4SLinus Torvalds struct sadb_comb *c; 28401da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 28411da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 28421da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 28431da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 28441da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 28451da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 28461da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 28471da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 28481da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 28491da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 28501da177e4SLinus Torvalds } 28511da177e4SLinus Torvalds } 28521da177e4SLinus Torvalds } 28531da177e4SLinus Torvalds 28541da177e4SLinus Torvalds static void dump_esp_combs(struct sk_buff *skb, struct xfrm_tmpl *t) 28551da177e4SLinus Torvalds { 28561da177e4SLinus Torvalds struct sadb_prop *p; 28571da177e4SLinus Torvalds int i, k; 28581da177e4SLinus Torvalds 28591da177e4SLinus Torvalds p = (struct sadb_prop*)skb_put(skb, sizeof(struct sadb_prop)); 28601da177e4SLinus Torvalds p->sadb_prop_len = sizeof(struct sadb_prop)/8; 28611da177e4SLinus Torvalds p->sadb_prop_exttype = SADB_EXT_PROPOSAL; 28621da177e4SLinus Torvalds p->sadb_prop_replay = 32; 28631da177e4SLinus Torvalds memset(p->sadb_prop_reserved, 0, sizeof(p->sadb_prop_reserved)); 28641da177e4SLinus Torvalds 28651da177e4SLinus Torvalds for (i=0; ; i++) { 28661da177e4SLinus Torvalds struct xfrm_algo_desc *ealg = xfrm_ealg_get_byidx(i); 28671da177e4SLinus Torvalds if (!ealg) 28681da177e4SLinus Torvalds break; 28691da177e4SLinus Torvalds 28701da177e4SLinus Torvalds if (!(ealg_tmpl_set(t, ealg) && ealg->available)) 28711da177e4SLinus Torvalds continue; 28721da177e4SLinus Torvalds 28731da177e4SLinus Torvalds for (k = 1; ; k++) { 28741da177e4SLinus Torvalds struct sadb_comb *c; 28751da177e4SLinus Torvalds struct xfrm_algo_desc *aalg = xfrm_aalg_get_byidx(k); 28761da177e4SLinus Torvalds if (!aalg) 28771da177e4SLinus Torvalds break; 28781da177e4SLinus Torvalds if (!(aalg_tmpl_set(t, aalg) && aalg->available)) 28791da177e4SLinus Torvalds continue; 28801da177e4SLinus Torvalds c = (struct sadb_comb*)skb_put(skb, sizeof(struct sadb_comb)); 28811da177e4SLinus Torvalds memset(c, 0, sizeof(*c)); 28821da177e4SLinus Torvalds p->sadb_prop_len += sizeof(struct sadb_comb)/8; 28831da177e4SLinus Torvalds c->sadb_comb_auth = aalg->desc.sadb_alg_id; 28841da177e4SLinus Torvalds c->sadb_comb_auth_minbits = aalg->desc.sadb_alg_minbits; 28851da177e4SLinus Torvalds c->sadb_comb_auth_maxbits = aalg->desc.sadb_alg_maxbits; 28861da177e4SLinus Torvalds c->sadb_comb_encrypt = ealg->desc.sadb_alg_id; 28871da177e4SLinus Torvalds c->sadb_comb_encrypt_minbits = ealg->desc.sadb_alg_minbits; 28881da177e4SLinus Torvalds c->sadb_comb_encrypt_maxbits = ealg->desc.sadb_alg_maxbits; 28891da177e4SLinus Torvalds c->sadb_comb_hard_addtime = 24*60*60; 28901da177e4SLinus Torvalds c->sadb_comb_soft_addtime = 20*60*60; 28911da177e4SLinus Torvalds c->sadb_comb_hard_usetime = 8*60*60; 28921da177e4SLinus Torvalds c->sadb_comb_soft_usetime = 7*60*60; 28931da177e4SLinus Torvalds } 28941da177e4SLinus Torvalds } 28951da177e4SLinus Torvalds } 28961da177e4SLinus Torvalds 289726b15dadSJamal Hadi Salim static int key_notify_policy_expire(struct xfrm_policy *xp, struct km_event *c) 289826b15dadSJamal Hadi Salim { 289926b15dadSJamal Hadi Salim return 0; 290026b15dadSJamal Hadi Salim } 290126b15dadSJamal Hadi Salim 290226b15dadSJamal Hadi Salim static int key_notify_sa_expire(struct xfrm_state *x, struct km_event *c) 29031da177e4SLinus Torvalds { 29041da177e4SLinus Torvalds struct sk_buff *out_skb; 29051da177e4SLinus Torvalds struct sadb_msg *out_hdr; 290626b15dadSJamal Hadi Salim int hard; 290726b15dadSJamal Hadi Salim int hsc; 290826b15dadSJamal Hadi Salim 2909bf08867fSHerbert Xu hard = c->data.hard; 291026b15dadSJamal Hadi Salim if (hard) 291126b15dadSJamal Hadi Salim hsc = 2; 291226b15dadSJamal Hadi Salim else 291326b15dadSJamal Hadi Salim hsc = 1; 29141da177e4SLinus Torvalds 29151da177e4SLinus Torvalds out_skb = pfkey_xfrm_state2msg(x, 0, hsc); 29161da177e4SLinus Torvalds if (IS_ERR(out_skb)) 29171da177e4SLinus Torvalds return PTR_ERR(out_skb); 29181da177e4SLinus Torvalds 29191da177e4SLinus Torvalds out_hdr = (struct sadb_msg *) out_skb->data; 29201da177e4SLinus Torvalds out_hdr->sadb_msg_version = PF_KEY_V2; 29211da177e4SLinus Torvalds out_hdr->sadb_msg_type = SADB_EXPIRE; 29221da177e4SLinus Torvalds out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 29231da177e4SLinus Torvalds out_hdr->sadb_msg_errno = 0; 29241da177e4SLinus Torvalds out_hdr->sadb_msg_reserved = 0; 29251da177e4SLinus Torvalds out_hdr->sadb_msg_seq = 0; 29261da177e4SLinus Torvalds out_hdr->sadb_msg_pid = 0; 29271da177e4SLinus Torvalds 29281da177e4SLinus Torvalds pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 29291da177e4SLinus Torvalds return 0; 29301da177e4SLinus Torvalds } 29311da177e4SLinus Torvalds 293226b15dadSJamal Hadi Salim static int pfkey_send_notify(struct xfrm_state *x, struct km_event *c) 293326b15dadSJamal Hadi Salim { 293426b15dadSJamal Hadi Salim switch (c->event) { 2935f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 293626b15dadSJamal Hadi Salim return key_notify_sa_expire(x, c); 2937f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 2938f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 2939f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 294026b15dadSJamal Hadi Salim return key_notify_sa(x, c); 2941f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 294226b15dadSJamal Hadi Salim return key_notify_sa_flush(c); 2943d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: /* not yet supported */ 2944d51d081dSJamal Hadi Salim break; 294526b15dadSJamal Hadi Salim default: 294626b15dadSJamal Hadi Salim printk("pfkey: Unknown SA event %d\n", c->event); 294726b15dadSJamal Hadi Salim break; 294826b15dadSJamal Hadi Salim } 294926b15dadSJamal Hadi Salim 295026b15dadSJamal Hadi Salim return 0; 295126b15dadSJamal Hadi Salim } 295226b15dadSJamal Hadi Salim 295326b15dadSJamal Hadi Salim static int pfkey_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 295426b15dadSJamal Hadi Salim { 2955f7b6983fSMasahide NAKAMURA if (xp && xp->type != XFRM_POLICY_TYPE_MAIN) 2956f7b6983fSMasahide NAKAMURA return 0; 2957f7b6983fSMasahide NAKAMURA 295826b15dadSJamal Hadi Salim switch (c->event) { 2959f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 296026b15dadSJamal Hadi Salim return key_notify_policy_expire(xp, c); 2961f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 2962f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 2963f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 296426b15dadSJamal Hadi Salim return key_notify_policy(xp, dir, c); 2965f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 2966f7b6983fSMasahide NAKAMURA if (c->data.type != XFRM_POLICY_TYPE_MAIN) 2967f7b6983fSMasahide NAKAMURA break; 296826b15dadSJamal Hadi Salim return key_notify_policy_flush(c); 296926b15dadSJamal Hadi Salim default: 297026b15dadSJamal Hadi Salim printk("pfkey: Unknown policy event %d\n", c->event); 297126b15dadSJamal Hadi Salim break; 297226b15dadSJamal Hadi Salim } 297326b15dadSJamal Hadi Salim 297426b15dadSJamal Hadi Salim return 0; 297526b15dadSJamal Hadi Salim } 297626b15dadSJamal Hadi Salim 29771da177e4SLinus Torvalds static u32 get_acqseq(void) 29781da177e4SLinus Torvalds { 29791da177e4SLinus Torvalds u32 res; 29801da177e4SLinus Torvalds static u32 acqseq; 29811da177e4SLinus Torvalds static DEFINE_SPINLOCK(acqseq_lock); 29821da177e4SLinus Torvalds 29831da177e4SLinus Torvalds spin_lock_bh(&acqseq_lock); 29841da177e4SLinus Torvalds res = (++acqseq ? : ++acqseq); 29851da177e4SLinus Torvalds spin_unlock_bh(&acqseq_lock); 29861da177e4SLinus Torvalds return res; 29871da177e4SLinus Torvalds } 29881da177e4SLinus Torvalds 29891da177e4SLinus Torvalds static int pfkey_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *t, struct xfrm_policy *xp, int dir) 29901da177e4SLinus Torvalds { 29911da177e4SLinus Torvalds struct sk_buff *skb; 29921da177e4SLinus Torvalds struct sadb_msg *hdr; 29931da177e4SLinus Torvalds struct sadb_address *addr; 29941da177e4SLinus Torvalds struct sadb_x_policy *pol; 29951da177e4SLinus Torvalds struct sockaddr_in *sin; 29961da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 29971da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 29981da177e4SLinus Torvalds #endif 29991da177e4SLinus Torvalds int sockaddr_size; 30001da177e4SLinus Torvalds int size; 30014e2ba18eSVenkat Yekkirala struct sadb_x_sec_ctx *sec_ctx; 30024e2ba18eSVenkat Yekkirala struct xfrm_sec_ctx *xfrm_ctx; 30034e2ba18eSVenkat Yekkirala int ctx_size = 0; 30041da177e4SLinus Torvalds 30051da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 30061da177e4SLinus Torvalds if (!sockaddr_size) 30071da177e4SLinus Torvalds return -EINVAL; 30081da177e4SLinus Torvalds 30091da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 30101da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 30111da177e4SLinus Torvalds (sockaddr_size * 2) + 30121da177e4SLinus Torvalds sizeof(struct sadb_x_policy); 30131da177e4SLinus Torvalds 30141da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 30151da177e4SLinus Torvalds size += count_ah_combs(t); 30161da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 30171da177e4SLinus Torvalds size += count_esp_combs(t); 30181da177e4SLinus Torvalds 30194e2ba18eSVenkat Yekkirala if ((xfrm_ctx = x->security)) { 30204e2ba18eSVenkat Yekkirala ctx_size = PFKEY_ALIGN8(xfrm_ctx->ctx_len); 30214e2ba18eSVenkat Yekkirala size += sizeof(struct sadb_x_sec_ctx) + ctx_size; 30224e2ba18eSVenkat Yekkirala } 30234e2ba18eSVenkat Yekkirala 30241da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 30251da177e4SLinus Torvalds if (skb == NULL) 30261da177e4SLinus Torvalds return -ENOMEM; 30271da177e4SLinus Torvalds 30281da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 30291da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 30301da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_ACQUIRE; 30311da177e4SLinus Torvalds hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto); 30321da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 30331da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 30341da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 30351da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 30361da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 30371da177e4SLinus Torvalds 30381da177e4SLinus Torvalds /* src address */ 30391da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30401da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30411da177e4SLinus Torvalds addr->sadb_address_len = 30421da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30431da177e4SLinus Torvalds sizeof(uint64_t); 30441da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 30451da177e4SLinus Torvalds addr->sadb_address_proto = 0; 30461da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 30471da177e4SLinus Torvalds if (x->props.family == AF_INET) { 30481da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 30491da177e4SLinus Torvalds 30501da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 30511da177e4SLinus Torvalds sin->sin_family = AF_INET; 30521da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 30531da177e4SLinus Torvalds sin->sin_port = 0; 30541da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 30551da177e4SLinus Torvalds } 30561da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 30571da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 30581da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 30591da177e4SLinus Torvalds 30601da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 30611da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 30621da177e4SLinus Torvalds sin6->sin6_port = 0; 30631da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 30641da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 30651da177e4SLinus Torvalds x->props.saddr.a6, sizeof(struct in6_addr)); 30661da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 30671da177e4SLinus Torvalds } 30681da177e4SLinus Torvalds #endif 30691da177e4SLinus Torvalds else 30701da177e4SLinus Torvalds BUG(); 30711da177e4SLinus Torvalds 30721da177e4SLinus Torvalds /* dst address */ 30731da177e4SLinus Torvalds addr = (struct sadb_address*) skb_put(skb, 30741da177e4SLinus Torvalds sizeof(struct sadb_address)+sockaddr_size); 30751da177e4SLinus Torvalds addr->sadb_address_len = 30761da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 30771da177e4SLinus Torvalds sizeof(uint64_t); 30781da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 30791da177e4SLinus Torvalds addr->sadb_address_proto = 0; 30801da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 30811da177e4SLinus Torvalds if (x->props.family == AF_INET) { 30821da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 30831da177e4SLinus Torvalds 30841da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 30851da177e4SLinus Torvalds sin->sin_family = AF_INET; 30861da177e4SLinus Torvalds sin->sin_addr.s_addr = x->id.daddr.a4; 30871da177e4SLinus Torvalds sin->sin_port = 0; 30881da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 30891da177e4SLinus Torvalds } 30901da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 30911da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 30921da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 30931da177e4SLinus Torvalds 30941da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 30951da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 30961da177e4SLinus Torvalds sin6->sin6_port = 0; 30971da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 30981da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 30991da177e4SLinus Torvalds x->id.daddr.a6, sizeof(struct in6_addr)); 31001da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 31011da177e4SLinus Torvalds } 31021da177e4SLinus Torvalds #endif 31031da177e4SLinus Torvalds else 31041da177e4SLinus Torvalds BUG(); 31051da177e4SLinus Torvalds 31061da177e4SLinus Torvalds pol = (struct sadb_x_policy *) skb_put(skb, sizeof(struct sadb_x_policy)); 31071da177e4SLinus Torvalds pol->sadb_x_policy_len = sizeof(struct sadb_x_policy)/sizeof(uint64_t); 31081da177e4SLinus Torvalds pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 31091da177e4SLinus Torvalds pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 31101da177e4SLinus Torvalds pol->sadb_x_policy_dir = dir+1; 31111da177e4SLinus Torvalds pol->sadb_x_policy_id = xp->index; 31121da177e4SLinus Torvalds 31131da177e4SLinus Torvalds /* Set sadb_comb's. */ 31141da177e4SLinus Torvalds if (x->id.proto == IPPROTO_AH) 31151da177e4SLinus Torvalds dump_ah_combs(skb, t); 31161da177e4SLinus Torvalds else if (x->id.proto == IPPROTO_ESP) 31171da177e4SLinus Torvalds dump_esp_combs(skb, t); 31181da177e4SLinus Torvalds 31194e2ba18eSVenkat Yekkirala /* security context */ 31204e2ba18eSVenkat Yekkirala if (xfrm_ctx) { 31214e2ba18eSVenkat Yekkirala sec_ctx = (struct sadb_x_sec_ctx *) skb_put(skb, 31224e2ba18eSVenkat Yekkirala sizeof(struct sadb_x_sec_ctx) + ctx_size); 31234e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_len = 31244e2ba18eSVenkat Yekkirala (sizeof(struct sadb_x_sec_ctx) + ctx_size) / sizeof(uint64_t); 31254e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_sec_exttype = SADB_X_EXT_SEC_CTX; 31264e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_doi = xfrm_ctx->ctx_doi; 31274e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_alg = xfrm_ctx->ctx_alg; 31284e2ba18eSVenkat Yekkirala sec_ctx->sadb_x_ctx_len = xfrm_ctx->ctx_len; 31294e2ba18eSVenkat Yekkirala memcpy(sec_ctx + 1, xfrm_ctx->ctx_str, 31304e2ba18eSVenkat Yekkirala xfrm_ctx->ctx_len); 31314e2ba18eSVenkat Yekkirala } 31324e2ba18eSVenkat Yekkirala 31331da177e4SLinus Torvalds return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 31341da177e4SLinus Torvalds } 31351da177e4SLinus Torvalds 3136cb969f07SVenkat Yekkirala static struct xfrm_policy *pfkey_compile_policy(struct sock *sk, int opt, 31371da177e4SLinus Torvalds u8 *data, int len, int *dir) 31381da177e4SLinus Torvalds { 31391da177e4SLinus Torvalds struct xfrm_policy *xp; 31401da177e4SLinus Torvalds struct sadb_x_policy *pol = (struct sadb_x_policy*)data; 3141df71837dSTrent Jaeger struct sadb_x_sec_ctx *sec_ctx; 31421da177e4SLinus Torvalds 3143cb969f07SVenkat Yekkirala switch (sk->sk_family) { 31441da177e4SLinus Torvalds case AF_INET: 31451da177e4SLinus Torvalds if (opt != IP_IPSEC_POLICY) { 31461da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31471da177e4SLinus Torvalds return NULL; 31481da177e4SLinus Torvalds } 31491da177e4SLinus Torvalds break; 31501da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 31511da177e4SLinus Torvalds case AF_INET6: 31521da177e4SLinus Torvalds if (opt != IPV6_IPSEC_POLICY) { 31531da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 31541da177e4SLinus Torvalds return NULL; 31551da177e4SLinus Torvalds } 31561da177e4SLinus Torvalds break; 31571da177e4SLinus Torvalds #endif 31581da177e4SLinus Torvalds default: 31591da177e4SLinus Torvalds *dir = -EINVAL; 31601da177e4SLinus Torvalds return NULL; 31611da177e4SLinus Torvalds } 31621da177e4SLinus Torvalds 31631da177e4SLinus Torvalds *dir = -EINVAL; 31641da177e4SLinus Torvalds 31651da177e4SLinus Torvalds if (len < sizeof(struct sadb_x_policy) || 31661da177e4SLinus Torvalds pol->sadb_x_policy_len*8 > len || 31671da177e4SLinus Torvalds pol->sadb_x_policy_type > IPSEC_POLICY_BYPASS || 31681da177e4SLinus Torvalds (!pol->sadb_x_policy_dir || pol->sadb_x_policy_dir > IPSEC_DIR_OUTBOUND)) 31691da177e4SLinus Torvalds return NULL; 31701da177e4SLinus Torvalds 31711da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_ATOMIC); 31721da177e4SLinus Torvalds if (xp == NULL) { 31731da177e4SLinus Torvalds *dir = -ENOBUFS; 31741da177e4SLinus Torvalds return NULL; 31751da177e4SLinus Torvalds } 31761da177e4SLinus Torvalds 31771da177e4SLinus Torvalds xp->action = (pol->sadb_x_policy_type == IPSEC_POLICY_DISCARD ? 31781da177e4SLinus Torvalds XFRM_POLICY_BLOCK : XFRM_POLICY_ALLOW); 31791da177e4SLinus Torvalds 31801da177e4SLinus Torvalds xp->lft.soft_byte_limit = XFRM_INF; 31811da177e4SLinus Torvalds xp->lft.hard_byte_limit = XFRM_INF; 31821da177e4SLinus Torvalds xp->lft.soft_packet_limit = XFRM_INF; 31831da177e4SLinus Torvalds xp->lft.hard_packet_limit = XFRM_INF; 3184cb969f07SVenkat Yekkirala xp->family = sk->sk_family; 31851da177e4SLinus Torvalds 31861da177e4SLinus Torvalds xp->xfrm_nr = 0; 31871da177e4SLinus Torvalds if (pol->sadb_x_policy_type == IPSEC_POLICY_IPSEC && 31881da177e4SLinus Torvalds (*dir = parse_ipsecrequests(xp, pol)) < 0) 31891da177e4SLinus Torvalds goto out; 31901da177e4SLinus Torvalds 3191df71837dSTrent Jaeger /* security context too */ 3192df71837dSTrent Jaeger if (len >= (pol->sadb_x_policy_len*8 + 3193df71837dSTrent Jaeger sizeof(struct sadb_x_sec_ctx))) { 3194df71837dSTrent Jaeger char *p = (char *)pol; 3195df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 3196df71837dSTrent Jaeger 3197df71837dSTrent Jaeger p += pol->sadb_x_policy_len*8; 3198df71837dSTrent Jaeger sec_ctx = (struct sadb_x_sec_ctx *)p; 3199df71837dSTrent Jaeger if (len < pol->sadb_x_policy_len*8 + 3200cb969f07SVenkat Yekkirala sec_ctx->sadb_x_sec_len) { 3201cb969f07SVenkat Yekkirala *dir = -EINVAL; 3202df71837dSTrent Jaeger goto out; 3203cb969f07SVenkat Yekkirala } 3204df71837dSTrent Jaeger if ((*dir = verify_sec_ctx_len(p))) 3205df71837dSTrent Jaeger goto out; 3206df71837dSTrent Jaeger uctx = pfkey_sadb2xfrm_user_sec_ctx(sec_ctx); 3207df71837dSTrent Jaeger *dir = security_xfrm_policy_alloc(xp, uctx); 3208df71837dSTrent Jaeger kfree(uctx); 3209df71837dSTrent Jaeger 3210df71837dSTrent Jaeger if (*dir) 3211df71837dSTrent Jaeger goto out; 3212df71837dSTrent Jaeger } 3213df71837dSTrent Jaeger 32141da177e4SLinus Torvalds *dir = pol->sadb_x_policy_dir-1; 32151da177e4SLinus Torvalds return xp; 32161da177e4SLinus Torvalds 32171da177e4SLinus Torvalds out: 3218df71837dSTrent Jaeger security_xfrm_policy_free(xp); 32191da177e4SLinus Torvalds kfree(xp); 32201da177e4SLinus Torvalds return NULL; 32211da177e4SLinus Torvalds } 32221da177e4SLinus Torvalds 32235d36b180SAl Viro static int pfkey_send_new_mapping(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport) 32241da177e4SLinus Torvalds { 32251da177e4SLinus Torvalds struct sk_buff *skb; 32261da177e4SLinus Torvalds struct sadb_msg *hdr; 32271da177e4SLinus Torvalds struct sadb_sa *sa; 32281da177e4SLinus Torvalds struct sadb_address *addr; 32291da177e4SLinus Torvalds struct sadb_x_nat_t_port *n_port; 32301da177e4SLinus Torvalds struct sockaddr_in *sin; 32311da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 32321da177e4SLinus Torvalds struct sockaddr_in6 *sin6; 32331da177e4SLinus Torvalds #endif 32341da177e4SLinus Torvalds int sockaddr_size; 32351da177e4SLinus Torvalds int size; 32361da177e4SLinus Torvalds __u8 satype = (x->id.proto == IPPROTO_ESP ? SADB_SATYPE_ESP : 0); 32371da177e4SLinus Torvalds struct xfrm_encap_tmpl *natt = NULL; 32381da177e4SLinus Torvalds 32391da177e4SLinus Torvalds sockaddr_size = pfkey_sockaddr_size(x->props.family); 32401da177e4SLinus Torvalds if (!sockaddr_size) 32411da177e4SLinus Torvalds return -EINVAL; 32421da177e4SLinus Torvalds 32431da177e4SLinus Torvalds if (!satype) 32441da177e4SLinus Torvalds return -EINVAL; 32451da177e4SLinus Torvalds 32461da177e4SLinus Torvalds if (!x->encap) 32471da177e4SLinus Torvalds return -EINVAL; 32481da177e4SLinus Torvalds 32491da177e4SLinus Torvalds natt = x->encap; 32501da177e4SLinus Torvalds 32511da177e4SLinus Torvalds /* Build an SADB_X_NAT_T_NEW_MAPPING message: 32521da177e4SLinus Torvalds * 32531da177e4SLinus Torvalds * HDR | SA | ADDRESS_SRC (old addr) | NAT_T_SPORT (old port) | 32541da177e4SLinus Torvalds * ADDRESS_DST (new addr) | NAT_T_DPORT (new port) 32551da177e4SLinus Torvalds */ 32561da177e4SLinus Torvalds 32571da177e4SLinus Torvalds size = sizeof(struct sadb_msg) + 32581da177e4SLinus Torvalds sizeof(struct sadb_sa) + 32591da177e4SLinus Torvalds (sizeof(struct sadb_address) * 2) + 32601da177e4SLinus Torvalds (sockaddr_size * 2) + 32611da177e4SLinus Torvalds (sizeof(struct sadb_x_nat_t_port) * 2); 32621da177e4SLinus Torvalds 32631da177e4SLinus Torvalds skb = alloc_skb(size + 16, GFP_ATOMIC); 32641da177e4SLinus Torvalds if (skb == NULL) 32651da177e4SLinus Torvalds return -ENOMEM; 32661da177e4SLinus Torvalds 32671da177e4SLinus Torvalds hdr = (struct sadb_msg *) skb_put(skb, sizeof(struct sadb_msg)); 32681da177e4SLinus Torvalds hdr->sadb_msg_version = PF_KEY_V2; 32691da177e4SLinus Torvalds hdr->sadb_msg_type = SADB_X_NAT_T_NEW_MAPPING; 32701da177e4SLinus Torvalds hdr->sadb_msg_satype = satype; 32711da177e4SLinus Torvalds hdr->sadb_msg_len = size / sizeof(uint64_t); 32721da177e4SLinus Torvalds hdr->sadb_msg_errno = 0; 32731da177e4SLinus Torvalds hdr->sadb_msg_reserved = 0; 32741da177e4SLinus Torvalds hdr->sadb_msg_seq = x->km.seq = get_acqseq(); 32751da177e4SLinus Torvalds hdr->sadb_msg_pid = 0; 32761da177e4SLinus Torvalds 32771da177e4SLinus Torvalds /* SA */ 32781da177e4SLinus Torvalds sa = (struct sadb_sa *) skb_put(skb, sizeof(struct sadb_sa)); 32791da177e4SLinus Torvalds sa->sadb_sa_len = sizeof(struct sadb_sa)/sizeof(uint64_t); 32801da177e4SLinus Torvalds sa->sadb_sa_exttype = SADB_EXT_SA; 32811da177e4SLinus Torvalds sa->sadb_sa_spi = x->id.spi; 32821da177e4SLinus Torvalds sa->sadb_sa_replay = 0; 32831da177e4SLinus Torvalds sa->sadb_sa_state = 0; 32841da177e4SLinus Torvalds sa->sadb_sa_auth = 0; 32851da177e4SLinus Torvalds sa->sadb_sa_encrypt = 0; 32861da177e4SLinus Torvalds sa->sadb_sa_flags = 0; 32871da177e4SLinus Torvalds 32881da177e4SLinus Torvalds /* ADDRESS_SRC (old addr) */ 32891da177e4SLinus Torvalds addr = (struct sadb_address*) 32901da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 32911da177e4SLinus Torvalds addr->sadb_address_len = 32921da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 32931da177e4SLinus Torvalds sizeof(uint64_t); 32941da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_SRC; 32951da177e4SLinus Torvalds addr->sadb_address_proto = 0; 32961da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 32971da177e4SLinus Torvalds if (x->props.family == AF_INET) { 32981da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 32991da177e4SLinus Torvalds 33001da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 33011da177e4SLinus Torvalds sin->sin_family = AF_INET; 33021da177e4SLinus Torvalds sin->sin_addr.s_addr = x->props.saddr.a4; 33031da177e4SLinus Torvalds sin->sin_port = 0; 33041da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 33051da177e4SLinus Torvalds } 33061da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 33071da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 33081da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 33091da177e4SLinus Torvalds 33101da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 33111da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 33121da177e4SLinus Torvalds sin6->sin6_port = 0; 33131da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 33141da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, 33151da177e4SLinus Torvalds x->props.saddr.a6, sizeof(struct in6_addr)); 33161da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 33171da177e4SLinus Torvalds } 33181da177e4SLinus Torvalds #endif 33191da177e4SLinus Torvalds else 33201da177e4SLinus Torvalds BUG(); 33211da177e4SLinus Torvalds 33221da177e4SLinus Torvalds /* NAT_T_SPORT (old port) */ 33231da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33241da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33251da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_SPORT; 33261da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = natt->encap_sport; 33271da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33281da177e4SLinus Torvalds 33291da177e4SLinus Torvalds /* ADDRESS_DST (new addr) */ 33301da177e4SLinus Torvalds addr = (struct sadb_address*) 33311da177e4SLinus Torvalds skb_put(skb, sizeof(struct sadb_address)+sockaddr_size); 33321da177e4SLinus Torvalds addr->sadb_address_len = 33331da177e4SLinus Torvalds (sizeof(struct sadb_address)+sockaddr_size)/ 33341da177e4SLinus Torvalds sizeof(uint64_t); 33351da177e4SLinus Torvalds addr->sadb_address_exttype = SADB_EXT_ADDRESS_DST; 33361da177e4SLinus Torvalds addr->sadb_address_proto = 0; 33371da177e4SLinus Torvalds addr->sadb_address_reserved = 0; 33381da177e4SLinus Torvalds if (x->props.family == AF_INET) { 33391da177e4SLinus Torvalds addr->sadb_address_prefixlen = 32; 33401da177e4SLinus Torvalds 33411da177e4SLinus Torvalds sin = (struct sockaddr_in *) (addr + 1); 33421da177e4SLinus Torvalds sin->sin_family = AF_INET; 33431da177e4SLinus Torvalds sin->sin_addr.s_addr = ipaddr->a4; 33441da177e4SLinus Torvalds sin->sin_port = 0; 33451da177e4SLinus Torvalds memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 33461da177e4SLinus Torvalds } 33471da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 33481da177e4SLinus Torvalds else if (x->props.family == AF_INET6) { 33491da177e4SLinus Torvalds addr->sadb_address_prefixlen = 128; 33501da177e4SLinus Torvalds 33511da177e4SLinus Torvalds sin6 = (struct sockaddr_in6 *) (addr + 1); 33521da177e4SLinus Torvalds sin6->sin6_family = AF_INET6; 33531da177e4SLinus Torvalds sin6->sin6_port = 0; 33541da177e4SLinus Torvalds sin6->sin6_flowinfo = 0; 33551da177e4SLinus Torvalds memcpy(&sin6->sin6_addr, &ipaddr->a6, sizeof(struct in6_addr)); 33561da177e4SLinus Torvalds sin6->sin6_scope_id = 0; 33571da177e4SLinus Torvalds } 33581da177e4SLinus Torvalds #endif 33591da177e4SLinus Torvalds else 33601da177e4SLinus Torvalds BUG(); 33611da177e4SLinus Torvalds 33621da177e4SLinus Torvalds /* NAT_T_DPORT (new port) */ 33631da177e4SLinus Torvalds n_port = (struct sadb_x_nat_t_port*) skb_put(skb, sizeof (*n_port)); 33641da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_len = sizeof(*n_port)/sizeof(uint64_t); 33651da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_exttype = SADB_X_EXT_NAT_T_DPORT; 33661da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_port = sport; 33671da177e4SLinus Torvalds n_port->sadb_x_nat_t_port_reserved = 0; 33681da177e4SLinus Torvalds 33691da177e4SLinus Torvalds return pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_REGISTERED, NULL); 33701da177e4SLinus Torvalds } 33711da177e4SLinus Torvalds 337208de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 337308de61beSShinta Sugimoto static int set_sadb_address(struct sk_buff *skb, int sasize, int type, 337408de61beSShinta Sugimoto struct xfrm_selector *sel) 337508de61beSShinta Sugimoto { 337608de61beSShinta Sugimoto struct sadb_address *addr; 337708de61beSShinta Sugimoto struct sockaddr_in *sin; 337808de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 337908de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 338008de61beSShinta Sugimoto #endif 338108de61beSShinta Sugimoto addr = (struct sadb_address *)skb_put(skb, sizeof(struct sadb_address) + sasize); 338208de61beSShinta Sugimoto addr->sadb_address_len = (sizeof(struct sadb_address) + sasize)/8; 338308de61beSShinta Sugimoto addr->sadb_address_exttype = type; 338408de61beSShinta Sugimoto addr->sadb_address_proto = sel->proto; 338508de61beSShinta Sugimoto addr->sadb_address_reserved = 0; 338608de61beSShinta Sugimoto 338708de61beSShinta Sugimoto switch (type) { 338808de61beSShinta Sugimoto case SADB_EXT_ADDRESS_SRC: 338908de61beSShinta Sugimoto if (sel->family == AF_INET) { 339008de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_s; 339108de61beSShinta Sugimoto sin = (struct sockaddr_in *)(addr + 1); 339208de61beSShinta Sugimoto sin->sin_family = AF_INET; 339308de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, &sel->saddr, 339408de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 339508de61beSShinta Sugimoto sin->sin_port = 0; 339608de61beSShinta Sugimoto memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 339708de61beSShinta Sugimoto } 339808de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 339908de61beSShinta Sugimoto else if (sel->family == AF_INET6) { 340008de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_s; 340108de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(addr + 1); 340208de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 340308de61beSShinta Sugimoto sin6->sin6_port = 0; 340408de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 340508de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 340608de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, &sel->saddr, 340708de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 340808de61beSShinta Sugimoto } 340908de61beSShinta Sugimoto #endif 341008de61beSShinta Sugimoto break; 341108de61beSShinta Sugimoto case SADB_EXT_ADDRESS_DST: 341208de61beSShinta Sugimoto if (sel->family == AF_INET) { 341308de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_d; 341408de61beSShinta Sugimoto sin = (struct sockaddr_in *)(addr + 1); 341508de61beSShinta Sugimoto sin->sin_family = AF_INET; 341608de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, &sel->daddr, 341708de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 341808de61beSShinta Sugimoto sin->sin_port = 0; 341908de61beSShinta Sugimoto memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); 342008de61beSShinta Sugimoto } 342108de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 342208de61beSShinta Sugimoto else if (sel->family == AF_INET6) { 342308de61beSShinta Sugimoto addr->sadb_address_prefixlen = sel->prefixlen_d; 342408de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(addr + 1); 342508de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 342608de61beSShinta Sugimoto sin6->sin6_port = 0; 342708de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 342808de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 342908de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, &sel->daddr, 343008de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 343108de61beSShinta Sugimoto } 343208de61beSShinta Sugimoto #endif 343308de61beSShinta Sugimoto break; 343408de61beSShinta Sugimoto default: 343508de61beSShinta Sugimoto return -EINVAL; 343608de61beSShinta Sugimoto } 343708de61beSShinta Sugimoto 343808de61beSShinta Sugimoto return 0; 343908de61beSShinta Sugimoto } 344008de61beSShinta Sugimoto 344108de61beSShinta Sugimoto static int set_ipsecrequest(struct sk_buff *skb, 344208de61beSShinta Sugimoto uint8_t proto, uint8_t mode, int level, 344308de61beSShinta Sugimoto uint32_t reqid, uint8_t family, 344408de61beSShinta Sugimoto xfrm_address_t *src, xfrm_address_t *dst) 344508de61beSShinta Sugimoto { 344608de61beSShinta Sugimoto struct sadb_x_ipsecrequest *rq; 344708de61beSShinta Sugimoto struct sockaddr_in *sin; 344808de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 344908de61beSShinta Sugimoto struct sockaddr_in6 *sin6; 345008de61beSShinta Sugimoto #endif 345108de61beSShinta Sugimoto int size_req; 345208de61beSShinta Sugimoto 345308de61beSShinta Sugimoto size_req = sizeof(struct sadb_x_ipsecrequest) + 345408de61beSShinta Sugimoto pfkey_sockaddr_pair_size(family); 345508de61beSShinta Sugimoto 345608de61beSShinta Sugimoto rq = (struct sadb_x_ipsecrequest *)skb_put(skb, size_req); 345708de61beSShinta Sugimoto memset(rq, 0, size_req); 345808de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_len = size_req; 345908de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_proto = proto; 346008de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_mode = mode; 346108de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_level = level; 346208de61beSShinta Sugimoto rq->sadb_x_ipsecrequest_reqid = reqid; 346308de61beSShinta Sugimoto 346408de61beSShinta Sugimoto switch (family) { 346508de61beSShinta Sugimoto case AF_INET: 346608de61beSShinta Sugimoto sin = (struct sockaddr_in *)(rq + 1); 346708de61beSShinta Sugimoto sin->sin_family = AF_INET; 346808de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, src, 346908de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 347008de61beSShinta Sugimoto sin++; 347108de61beSShinta Sugimoto sin->sin_family = AF_INET; 347208de61beSShinta Sugimoto memcpy(&sin->sin_addr.s_addr, dst, 347308de61beSShinta Sugimoto sizeof(sin->sin_addr.s_addr)); 347408de61beSShinta Sugimoto break; 347508de61beSShinta Sugimoto #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 347608de61beSShinta Sugimoto case AF_INET6: 347708de61beSShinta Sugimoto sin6 = (struct sockaddr_in6 *)(rq + 1); 347808de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 347908de61beSShinta Sugimoto sin6->sin6_port = 0; 348008de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 348108de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 348208de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, src, 348308de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 348408de61beSShinta Sugimoto sin6++; 348508de61beSShinta Sugimoto sin6->sin6_family = AF_INET6; 348608de61beSShinta Sugimoto sin6->sin6_port = 0; 348708de61beSShinta Sugimoto sin6->sin6_flowinfo = 0; 348808de61beSShinta Sugimoto sin6->sin6_scope_id = 0; 348908de61beSShinta Sugimoto memcpy(&sin6->sin6_addr.s6_addr, dst, 349008de61beSShinta Sugimoto sizeof(sin6->sin6_addr.s6_addr)); 349108de61beSShinta Sugimoto break; 349208de61beSShinta Sugimoto #endif 349308de61beSShinta Sugimoto default: 349408de61beSShinta Sugimoto return -EINVAL; 349508de61beSShinta Sugimoto } 349608de61beSShinta Sugimoto 349708de61beSShinta Sugimoto return 0; 349808de61beSShinta Sugimoto } 349908de61beSShinta Sugimoto #endif 350008de61beSShinta Sugimoto 350108de61beSShinta Sugimoto #ifdef CONFIG_NET_KEY_MIGRATE 350208de61beSShinta Sugimoto static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 350308de61beSShinta Sugimoto struct xfrm_migrate *m, int num_bundles) 350408de61beSShinta Sugimoto { 350508de61beSShinta Sugimoto int i; 350608de61beSShinta Sugimoto int sasize_sel; 350708de61beSShinta Sugimoto int size = 0; 350808de61beSShinta Sugimoto int size_pol = 0; 350908de61beSShinta Sugimoto struct sk_buff *skb; 351008de61beSShinta Sugimoto struct sadb_msg *hdr; 351108de61beSShinta Sugimoto struct sadb_x_policy *pol; 351208de61beSShinta Sugimoto struct xfrm_migrate *mp; 351308de61beSShinta Sugimoto 351408de61beSShinta Sugimoto if (type != XFRM_POLICY_TYPE_MAIN) 351508de61beSShinta Sugimoto return 0; 351608de61beSShinta Sugimoto 351708de61beSShinta Sugimoto if (num_bundles <= 0 || num_bundles > XFRM_MAX_DEPTH) 351808de61beSShinta Sugimoto return -EINVAL; 351908de61beSShinta Sugimoto 352008de61beSShinta Sugimoto /* selector */ 352108de61beSShinta Sugimoto sasize_sel = pfkey_sockaddr_size(sel->family); 352208de61beSShinta Sugimoto if (!sasize_sel) 352308de61beSShinta Sugimoto return -EINVAL; 352408de61beSShinta Sugimoto size += (sizeof(struct sadb_address) + sasize_sel) * 2; 352508de61beSShinta Sugimoto 352608de61beSShinta Sugimoto /* policy info */ 352708de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_policy); 352808de61beSShinta Sugimoto 352908de61beSShinta Sugimoto /* ipsecrequests */ 353008de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 353108de61beSShinta Sugimoto /* old locator pair */ 353208de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 353308de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->old_family); 353408de61beSShinta Sugimoto /* new locator pair */ 353508de61beSShinta Sugimoto size_pol += sizeof(struct sadb_x_ipsecrequest) + 353608de61beSShinta Sugimoto pfkey_sockaddr_pair_size(mp->new_family); 353708de61beSShinta Sugimoto } 353808de61beSShinta Sugimoto 353908de61beSShinta Sugimoto size += sizeof(struct sadb_msg) + size_pol; 354008de61beSShinta Sugimoto 354108de61beSShinta Sugimoto /* alloc buffer */ 354208de61beSShinta Sugimoto skb = alloc_skb(size, GFP_ATOMIC); 354308de61beSShinta Sugimoto if (skb == NULL) 354408de61beSShinta Sugimoto return -ENOMEM; 354508de61beSShinta Sugimoto 354608de61beSShinta Sugimoto hdr = (struct sadb_msg *)skb_put(skb, sizeof(struct sadb_msg)); 354708de61beSShinta Sugimoto hdr->sadb_msg_version = PF_KEY_V2; 354808de61beSShinta Sugimoto hdr->sadb_msg_type = SADB_X_MIGRATE; 354908de61beSShinta Sugimoto hdr->sadb_msg_satype = pfkey_proto2satype(m->proto); 355008de61beSShinta Sugimoto hdr->sadb_msg_len = size / 8; 355108de61beSShinta Sugimoto hdr->sadb_msg_errno = 0; 355208de61beSShinta Sugimoto hdr->sadb_msg_reserved = 0; 355308de61beSShinta Sugimoto hdr->sadb_msg_seq = 0; 355408de61beSShinta Sugimoto hdr->sadb_msg_pid = 0; 355508de61beSShinta Sugimoto 355608de61beSShinta Sugimoto /* selector src */ 355708de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_SRC, sel); 355808de61beSShinta Sugimoto 355908de61beSShinta Sugimoto /* selector dst */ 356008de61beSShinta Sugimoto set_sadb_address(skb, sasize_sel, SADB_EXT_ADDRESS_DST, sel); 356108de61beSShinta Sugimoto 356208de61beSShinta Sugimoto /* policy information */ 356308de61beSShinta Sugimoto pol = (struct sadb_x_policy *)skb_put(skb, sizeof(struct sadb_x_policy)); 356408de61beSShinta Sugimoto pol->sadb_x_policy_len = size_pol / 8; 356508de61beSShinta Sugimoto pol->sadb_x_policy_exttype = SADB_X_EXT_POLICY; 356608de61beSShinta Sugimoto pol->sadb_x_policy_type = IPSEC_POLICY_IPSEC; 356708de61beSShinta Sugimoto pol->sadb_x_policy_dir = dir + 1; 356808de61beSShinta Sugimoto pol->sadb_x_policy_id = 0; 356908de61beSShinta Sugimoto pol->sadb_x_policy_priority = 0; 357008de61beSShinta Sugimoto 357108de61beSShinta Sugimoto for (i = 0, mp = m; i < num_bundles; i++, mp++) { 357208de61beSShinta Sugimoto /* old ipsecrequest */ 357355569ce2SKazunori MIYAZAWA int mode = pfkey_mode_from_xfrm(mp->mode); 357455569ce2SKazunori MIYAZAWA if (mode < 0) 357555569ce2SKazunori MIYAZAWA return -EINVAL; 357655569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 357708de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 357808de61beSShinta Sugimoto mp->reqid, mp->old_family, 357908de61beSShinta Sugimoto &mp->old_saddr, &mp->old_daddr) < 0) { 358008de61beSShinta Sugimoto return -EINVAL; 358108de61beSShinta Sugimoto } 358208de61beSShinta Sugimoto 358308de61beSShinta Sugimoto /* new ipsecrequest */ 358455569ce2SKazunori MIYAZAWA if (set_ipsecrequest(skb, mp->proto, mode, 358508de61beSShinta Sugimoto (mp->reqid ? IPSEC_LEVEL_UNIQUE : IPSEC_LEVEL_REQUIRE), 358608de61beSShinta Sugimoto mp->reqid, mp->new_family, 358708de61beSShinta Sugimoto &mp->new_saddr, &mp->new_daddr) < 0) { 358808de61beSShinta Sugimoto return -EINVAL; 358908de61beSShinta Sugimoto } 359008de61beSShinta Sugimoto } 359108de61beSShinta Sugimoto 359208de61beSShinta Sugimoto /* broadcast migrate message to sockets */ 359308de61beSShinta Sugimoto pfkey_broadcast(skb, GFP_ATOMIC, BROADCAST_ALL, NULL); 359408de61beSShinta Sugimoto 359508de61beSShinta Sugimoto return 0; 359608de61beSShinta Sugimoto } 359708de61beSShinta Sugimoto #else 359808de61beSShinta Sugimoto static int pfkey_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 359908de61beSShinta Sugimoto struct xfrm_migrate *m, int num_bundles) 360008de61beSShinta Sugimoto { 360108de61beSShinta Sugimoto return -ENOPROTOOPT; 360208de61beSShinta Sugimoto } 360308de61beSShinta Sugimoto #endif 360408de61beSShinta Sugimoto 36051da177e4SLinus Torvalds static int pfkey_sendmsg(struct kiocb *kiocb, 36061da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len) 36071da177e4SLinus Torvalds { 36081da177e4SLinus Torvalds struct sock *sk = sock->sk; 36091da177e4SLinus Torvalds struct sk_buff *skb = NULL; 36101da177e4SLinus Torvalds struct sadb_msg *hdr = NULL; 36111da177e4SLinus Torvalds int err; 36121da177e4SLinus Torvalds 36131da177e4SLinus Torvalds err = -EOPNOTSUPP; 36141da177e4SLinus Torvalds if (msg->msg_flags & MSG_OOB) 36151da177e4SLinus Torvalds goto out; 36161da177e4SLinus Torvalds 36171da177e4SLinus Torvalds err = -EMSGSIZE; 36181da177e4SLinus Torvalds if ((unsigned)len > sk->sk_sndbuf - 32) 36191da177e4SLinus Torvalds goto out; 36201da177e4SLinus Torvalds 36211da177e4SLinus Torvalds err = -ENOBUFS; 36221da177e4SLinus Torvalds skb = alloc_skb(len, GFP_KERNEL); 36231da177e4SLinus Torvalds if (skb == NULL) 36241da177e4SLinus Torvalds goto out; 36251da177e4SLinus Torvalds 36261da177e4SLinus Torvalds err = -EFAULT; 36271da177e4SLinus Torvalds if (memcpy_fromiovec(skb_put(skb,len), msg->msg_iov, len)) 36281da177e4SLinus Torvalds goto out; 36291da177e4SLinus Torvalds 36301da177e4SLinus Torvalds hdr = pfkey_get_base_msg(skb, &err); 36311da177e4SLinus Torvalds if (!hdr) 36321da177e4SLinus Torvalds goto out; 36331da177e4SLinus Torvalds 36344a3e2f71SArjan van de Ven mutex_lock(&xfrm_cfg_mutex); 36351da177e4SLinus Torvalds err = pfkey_process(sk, skb, hdr); 36364a3e2f71SArjan van de Ven mutex_unlock(&xfrm_cfg_mutex); 36371da177e4SLinus Torvalds 36381da177e4SLinus Torvalds out: 36391da177e4SLinus Torvalds if (err && hdr && pfkey_error(hdr, err, sk) == 0) 36401da177e4SLinus Torvalds err = 0; 36411da177e4SLinus Torvalds if (skb) 36421da177e4SLinus Torvalds kfree_skb(skb); 36431da177e4SLinus Torvalds 36441da177e4SLinus Torvalds return err ? : len; 36451da177e4SLinus Torvalds } 36461da177e4SLinus Torvalds 36471da177e4SLinus Torvalds static int pfkey_recvmsg(struct kiocb *kiocb, 36481da177e4SLinus Torvalds struct socket *sock, struct msghdr *msg, size_t len, 36491da177e4SLinus Torvalds int flags) 36501da177e4SLinus Torvalds { 36511da177e4SLinus Torvalds struct sock *sk = sock->sk; 36521da177e4SLinus Torvalds struct sk_buff *skb; 36531da177e4SLinus Torvalds int copied, err; 36541da177e4SLinus Torvalds 36551da177e4SLinus Torvalds err = -EINVAL; 36561da177e4SLinus Torvalds if (flags & ~(MSG_PEEK|MSG_DONTWAIT|MSG_TRUNC|MSG_CMSG_COMPAT)) 36571da177e4SLinus Torvalds goto out; 36581da177e4SLinus Torvalds 36591da177e4SLinus Torvalds msg->msg_namelen = 0; 36601da177e4SLinus Torvalds skb = skb_recv_datagram(sk, flags, flags & MSG_DONTWAIT, &err); 36611da177e4SLinus Torvalds if (skb == NULL) 36621da177e4SLinus Torvalds goto out; 36631da177e4SLinus Torvalds 36641da177e4SLinus Torvalds copied = skb->len; 36651da177e4SLinus Torvalds if (copied > len) { 36661da177e4SLinus Torvalds msg->msg_flags |= MSG_TRUNC; 36671da177e4SLinus Torvalds copied = len; 36681da177e4SLinus Torvalds } 36691da177e4SLinus Torvalds 36701da177e4SLinus Torvalds skb->h.raw = skb->data; 36711da177e4SLinus Torvalds err = skb_copy_datagram_iovec(skb, 0, msg->msg_iov, copied); 36721da177e4SLinus Torvalds if (err) 36731da177e4SLinus Torvalds goto out_free; 36741da177e4SLinus Torvalds 36751da177e4SLinus Torvalds sock_recv_timestamp(msg, sk, skb); 36761da177e4SLinus Torvalds 36771da177e4SLinus Torvalds err = (flags & MSG_TRUNC) ? skb->len : copied; 36781da177e4SLinus Torvalds 36791da177e4SLinus Torvalds out_free: 36801da177e4SLinus Torvalds skb_free_datagram(sk, skb); 36811da177e4SLinus Torvalds out: 36821da177e4SLinus Torvalds return err; 36831da177e4SLinus Torvalds } 36841da177e4SLinus Torvalds 368590ddc4f0SEric Dumazet static const struct proto_ops pfkey_ops = { 36861da177e4SLinus Torvalds .family = PF_KEY, 36871da177e4SLinus Torvalds .owner = THIS_MODULE, 36881da177e4SLinus Torvalds /* Operations that make no sense on pfkey sockets. */ 36891da177e4SLinus Torvalds .bind = sock_no_bind, 36901da177e4SLinus Torvalds .connect = sock_no_connect, 36911da177e4SLinus Torvalds .socketpair = sock_no_socketpair, 36921da177e4SLinus Torvalds .accept = sock_no_accept, 36931da177e4SLinus Torvalds .getname = sock_no_getname, 36941da177e4SLinus Torvalds .ioctl = sock_no_ioctl, 36951da177e4SLinus Torvalds .listen = sock_no_listen, 36961da177e4SLinus Torvalds .shutdown = sock_no_shutdown, 36971da177e4SLinus Torvalds .setsockopt = sock_no_setsockopt, 36981da177e4SLinus Torvalds .getsockopt = sock_no_getsockopt, 36991da177e4SLinus Torvalds .mmap = sock_no_mmap, 37001da177e4SLinus Torvalds .sendpage = sock_no_sendpage, 37011da177e4SLinus Torvalds 37021da177e4SLinus Torvalds /* Now the operations that really occur. */ 37031da177e4SLinus Torvalds .release = pfkey_release, 37041da177e4SLinus Torvalds .poll = datagram_poll, 37051da177e4SLinus Torvalds .sendmsg = pfkey_sendmsg, 37061da177e4SLinus Torvalds .recvmsg = pfkey_recvmsg, 37071da177e4SLinus Torvalds }; 37081da177e4SLinus Torvalds 37091da177e4SLinus Torvalds static struct net_proto_family pfkey_family_ops = { 37101da177e4SLinus Torvalds .family = PF_KEY, 37111da177e4SLinus Torvalds .create = pfkey_create, 37121da177e4SLinus Torvalds .owner = THIS_MODULE, 37131da177e4SLinus Torvalds }; 37141da177e4SLinus Torvalds 37151da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 37161da177e4SLinus Torvalds static int pfkey_read_proc(char *buffer, char **start, off_t offset, 37171da177e4SLinus Torvalds int length, int *eof, void *data) 37181da177e4SLinus Torvalds { 37191da177e4SLinus Torvalds off_t pos = 0; 37201da177e4SLinus Torvalds off_t begin = 0; 37211da177e4SLinus Torvalds int len = 0; 37221da177e4SLinus Torvalds struct sock *s; 37231da177e4SLinus Torvalds struct hlist_node *node; 37241da177e4SLinus Torvalds 37251da177e4SLinus Torvalds len += sprintf(buffer,"sk RefCnt Rmem Wmem User Inode\n"); 37261da177e4SLinus Torvalds 37271da177e4SLinus Torvalds read_lock(&pfkey_table_lock); 37281da177e4SLinus Torvalds 37291da177e4SLinus Torvalds sk_for_each(s, node, &pfkey_table) { 37301da177e4SLinus Torvalds len += sprintf(buffer+len,"%p %-6d %-6u %-6u %-6u %-6lu", 37311da177e4SLinus Torvalds s, 37321da177e4SLinus Torvalds atomic_read(&s->sk_refcnt), 37331da177e4SLinus Torvalds atomic_read(&s->sk_rmem_alloc), 37341da177e4SLinus Torvalds atomic_read(&s->sk_wmem_alloc), 37351da177e4SLinus Torvalds sock_i_uid(s), 37361da177e4SLinus Torvalds sock_i_ino(s) 37371da177e4SLinus Torvalds ); 37381da177e4SLinus Torvalds 37391da177e4SLinus Torvalds buffer[len++] = '\n'; 37401da177e4SLinus Torvalds 37411da177e4SLinus Torvalds pos = begin + len; 37421da177e4SLinus Torvalds if (pos < offset) { 37431da177e4SLinus Torvalds len = 0; 37441da177e4SLinus Torvalds begin = pos; 37451da177e4SLinus Torvalds } 37461da177e4SLinus Torvalds if(pos > offset + length) 37471da177e4SLinus Torvalds goto done; 37481da177e4SLinus Torvalds } 37491da177e4SLinus Torvalds *eof = 1; 37501da177e4SLinus Torvalds 37511da177e4SLinus Torvalds done: 37521da177e4SLinus Torvalds read_unlock(&pfkey_table_lock); 37531da177e4SLinus Torvalds 37541da177e4SLinus Torvalds *start = buffer + (offset - begin); 37551da177e4SLinus Torvalds len -= (offset - begin); 37561da177e4SLinus Torvalds 37571da177e4SLinus Torvalds if (len > length) 37581da177e4SLinus Torvalds len = length; 37591da177e4SLinus Torvalds if (len < 0) 37601da177e4SLinus Torvalds len = 0; 37611da177e4SLinus Torvalds 37621da177e4SLinus Torvalds return len; 37631da177e4SLinus Torvalds } 37641da177e4SLinus Torvalds #endif 37651da177e4SLinus Torvalds 37661da177e4SLinus Torvalds static struct xfrm_mgr pfkeyv2_mgr = 37671da177e4SLinus Torvalds { 37681da177e4SLinus Torvalds .id = "pfkeyv2", 37691da177e4SLinus Torvalds .notify = pfkey_send_notify, 37701da177e4SLinus Torvalds .acquire = pfkey_send_acquire, 37711da177e4SLinus Torvalds .compile_policy = pfkey_compile_policy, 37721da177e4SLinus Torvalds .new_mapping = pfkey_send_new_mapping, 377326b15dadSJamal Hadi Salim .notify_policy = pfkey_send_policy_notify, 377408de61beSShinta Sugimoto .migrate = pfkey_send_migrate, 37751da177e4SLinus Torvalds }; 37761da177e4SLinus Torvalds 37771da177e4SLinus Torvalds static void __exit ipsec_pfkey_exit(void) 37781da177e4SLinus Torvalds { 37791da177e4SLinus Torvalds xfrm_unregister_km(&pfkeyv2_mgr); 37801da177e4SLinus Torvalds remove_proc_entry("net/pfkey", NULL); 37811da177e4SLinus Torvalds sock_unregister(PF_KEY); 37821da177e4SLinus Torvalds proto_unregister(&key_proto); 37831da177e4SLinus Torvalds } 37841da177e4SLinus Torvalds 37851da177e4SLinus Torvalds static int __init ipsec_pfkey_init(void) 37861da177e4SLinus Torvalds { 37871da177e4SLinus Torvalds int err = proto_register(&key_proto, 0); 37881da177e4SLinus Torvalds 37891da177e4SLinus Torvalds if (err != 0) 37901da177e4SLinus Torvalds goto out; 37911da177e4SLinus Torvalds 37921da177e4SLinus Torvalds err = sock_register(&pfkey_family_ops); 37931da177e4SLinus Torvalds if (err != 0) 37941da177e4SLinus Torvalds goto out_unregister_key_proto; 37951da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 37961da177e4SLinus Torvalds err = -ENOMEM; 37971da177e4SLinus Torvalds if (create_proc_read_entry("net/pfkey", 0, NULL, pfkey_read_proc, NULL) == NULL) 37981da177e4SLinus Torvalds goto out_sock_unregister; 37991da177e4SLinus Torvalds #endif 38001da177e4SLinus Torvalds err = xfrm_register_km(&pfkeyv2_mgr); 38011da177e4SLinus Torvalds if (err != 0) 38021da177e4SLinus Torvalds goto out_remove_proc_entry; 38031da177e4SLinus Torvalds out: 38041da177e4SLinus Torvalds return err; 38051da177e4SLinus Torvalds out_remove_proc_entry: 38061da177e4SLinus Torvalds #ifdef CONFIG_PROC_FS 38071da177e4SLinus Torvalds remove_proc_entry("net/pfkey", NULL); 38081da177e4SLinus Torvalds out_sock_unregister: 38091da177e4SLinus Torvalds #endif 38101da177e4SLinus Torvalds sock_unregister(PF_KEY); 38111da177e4SLinus Torvalds out_unregister_key_proto: 38121da177e4SLinus Torvalds proto_unregister(&key_proto); 38131da177e4SLinus Torvalds goto out; 38141da177e4SLinus Torvalds } 38151da177e4SLinus Torvalds 38161da177e4SLinus Torvalds module_init(ipsec_pfkey_init); 38171da177e4SLinus Torvalds module_exit(ipsec_pfkey_exit); 38181da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 38191da177e4SLinus Torvalds MODULE_ALIAS_NETPROTO(PF_KEY); 3820