11da177e4SLinus Torvalds /* xfrm_user.c: User interface to configure xfrm engine. 21da177e4SLinus Torvalds * 31da177e4SLinus Torvalds * Copyright (C) 2002 David S. Miller (davem@redhat.com) 41da177e4SLinus Torvalds * 51da177e4SLinus Torvalds * Changes: 61da177e4SLinus Torvalds * Mitsuru KANDA @USAGI 71da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 81da177e4SLinus Torvalds * Kunihiro Ishiguro <kunihiro@ipinfusion.com> 91da177e4SLinus Torvalds * IPv6 support 101da177e4SLinus Torvalds * 111da177e4SLinus Torvalds */ 121da177e4SLinus Torvalds 139409f38aSHerbert Xu #include <linux/crypto.h> 141da177e4SLinus Torvalds #include <linux/module.h> 151da177e4SLinus Torvalds #include <linux/kernel.h> 161da177e4SLinus Torvalds #include <linux/types.h> 171da177e4SLinus Torvalds #include <linux/slab.h> 181da177e4SLinus Torvalds #include <linux/socket.h> 191da177e4SLinus Torvalds #include <linux/string.h> 201da177e4SLinus Torvalds #include <linux/net.h> 211da177e4SLinus Torvalds #include <linux/skbuff.h> 221da177e4SLinus Torvalds #include <linux/pfkeyv2.h> 231da177e4SLinus Torvalds #include <linux/ipsec.h> 241da177e4SLinus Torvalds #include <linux/init.h> 251da177e4SLinus Torvalds #include <linux/security.h> 261da177e4SLinus Torvalds #include <net/sock.h> 271da177e4SLinus Torvalds #include <net/xfrm.h> 2888fc2c84SThomas Graf #include <net/netlink.h> 291da177e4SLinus Torvalds #include <asm/uaccess.h> 30e23c7194SMasahide NAKAMURA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 31e23c7194SMasahide NAKAMURA #include <linux/in6.h> 32e23c7194SMasahide NAKAMURA #endif 331da177e4SLinus Torvalds 341a6509d9SHerbert Xu static inline int aead_len(struct xfrm_algo_aead *alg) 351a6509d9SHerbert Xu { 361a6509d9SHerbert Xu return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); 371a6509d9SHerbert Xu } 381a6509d9SHerbert Xu 395424f32eSThomas Graf static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) 401da177e4SLinus Torvalds { 415424f32eSThomas Graf struct nlattr *rt = attrs[type]; 421da177e4SLinus Torvalds struct xfrm_algo *algp; 431da177e4SLinus Torvalds 441da177e4SLinus Torvalds if (!rt) 451da177e4SLinus Torvalds return 0; 461da177e4SLinus Torvalds 475424f32eSThomas Graf algp = nla_data(rt); 480f99be0dSEric Dumazet if (nla_len(rt) < xfrm_alg_len(algp)) 4931c26852SHerbert Xu return -EINVAL; 5031c26852SHerbert Xu 511da177e4SLinus Torvalds switch (type) { 521da177e4SLinus Torvalds case XFRMA_ALG_AUTH: 531da177e4SLinus Torvalds if (!algp->alg_key_len && 541da177e4SLinus Torvalds strcmp(algp->alg_name, "digest_null") != 0) 551da177e4SLinus Torvalds return -EINVAL; 561da177e4SLinus Torvalds break; 571da177e4SLinus Torvalds 581da177e4SLinus Torvalds case XFRMA_ALG_CRYPT: 591da177e4SLinus Torvalds if (!algp->alg_key_len && 601da177e4SLinus Torvalds strcmp(algp->alg_name, "cipher_null") != 0) 611da177e4SLinus Torvalds return -EINVAL; 621da177e4SLinus Torvalds break; 631da177e4SLinus Torvalds 641da177e4SLinus Torvalds case XFRMA_ALG_COMP: 651da177e4SLinus Torvalds /* Zero length keys are legal. */ 661da177e4SLinus Torvalds break; 671da177e4SLinus Torvalds 681da177e4SLinus Torvalds default: 691da177e4SLinus Torvalds return -EINVAL; 703ff50b79SStephen Hemminger } 711da177e4SLinus Torvalds 721da177e4SLinus Torvalds algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; 731da177e4SLinus Torvalds return 0; 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 761a6509d9SHerbert Xu static int verify_aead(struct nlattr **attrs) 771a6509d9SHerbert Xu { 781a6509d9SHerbert Xu struct nlattr *rt = attrs[XFRMA_ALG_AEAD]; 791a6509d9SHerbert Xu struct xfrm_algo_aead *algp; 801a6509d9SHerbert Xu 811a6509d9SHerbert Xu if (!rt) 821a6509d9SHerbert Xu return 0; 831a6509d9SHerbert Xu 841a6509d9SHerbert Xu algp = nla_data(rt); 851a6509d9SHerbert Xu if (nla_len(rt) < aead_len(algp)) 861a6509d9SHerbert Xu return -EINVAL; 871a6509d9SHerbert Xu 881a6509d9SHerbert Xu algp->alg_name[CRYPTO_MAX_ALG_NAME - 1] = '\0'; 891a6509d9SHerbert Xu return 0; 901a6509d9SHerbert Xu } 911a6509d9SHerbert Xu 925424f32eSThomas Graf static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, 93eb2971b6SMasahide NAKAMURA xfrm_address_t **addrp) 94eb2971b6SMasahide NAKAMURA { 955424f32eSThomas Graf struct nlattr *rt = attrs[type]; 96eb2971b6SMasahide NAKAMURA 97cf5cb79fSThomas Graf if (rt && addrp) 985424f32eSThomas Graf *addrp = nla_data(rt); 99eb2971b6SMasahide NAKAMURA } 100df71837dSTrent Jaeger 1015424f32eSThomas Graf static inline int verify_sec_ctx_len(struct nlattr **attrs) 102df71837dSTrent Jaeger { 1035424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 104df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 105df71837dSTrent Jaeger 106df71837dSTrent Jaeger if (!rt) 107df71837dSTrent Jaeger return 0; 108df71837dSTrent Jaeger 1095424f32eSThomas Graf uctx = nla_data(rt); 110cf5cb79fSThomas Graf if (uctx->len != (sizeof(struct xfrm_user_sec_ctx) + uctx->ctx_len)) 111df71837dSTrent Jaeger return -EINVAL; 112df71837dSTrent Jaeger 113df71837dSTrent Jaeger return 0; 114df71837dSTrent Jaeger } 115df71837dSTrent Jaeger 116df71837dSTrent Jaeger 1171da177e4SLinus Torvalds static int verify_newsa_info(struct xfrm_usersa_info *p, 1185424f32eSThomas Graf struct nlattr **attrs) 1191da177e4SLinus Torvalds { 1201da177e4SLinus Torvalds int err; 1211da177e4SLinus Torvalds 1221da177e4SLinus Torvalds err = -EINVAL; 1231da177e4SLinus Torvalds switch (p->family) { 1241da177e4SLinus Torvalds case AF_INET: 1251da177e4SLinus Torvalds break; 1261da177e4SLinus Torvalds 1271da177e4SLinus Torvalds case AF_INET6: 1281da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1291da177e4SLinus Torvalds break; 1301da177e4SLinus Torvalds #else 1311da177e4SLinus Torvalds err = -EAFNOSUPPORT; 1321da177e4SLinus Torvalds goto out; 1331da177e4SLinus Torvalds #endif 1341da177e4SLinus Torvalds 1351da177e4SLinus Torvalds default: 1361da177e4SLinus Torvalds goto out; 1373ff50b79SStephen Hemminger } 1381da177e4SLinus Torvalds 1391da177e4SLinus Torvalds err = -EINVAL; 1401da177e4SLinus Torvalds switch (p->id.proto) { 1411da177e4SLinus Torvalds case IPPROTO_AH: 14235a7aa08SThomas Graf if (!attrs[XFRMA_ALG_AUTH] || 1431a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 14435a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT] || 14535a7aa08SThomas Graf attrs[XFRMA_ALG_COMP]) 1461da177e4SLinus Torvalds goto out; 1471da177e4SLinus Torvalds break; 1481da177e4SLinus Torvalds 1491da177e4SLinus Torvalds case IPPROTO_ESP: 1501a6509d9SHerbert Xu if (attrs[XFRMA_ALG_COMP]) 1511a6509d9SHerbert Xu goto out; 1521a6509d9SHerbert Xu if (!attrs[XFRMA_ALG_AUTH] && 1531a6509d9SHerbert Xu !attrs[XFRMA_ALG_CRYPT] && 1541a6509d9SHerbert Xu !attrs[XFRMA_ALG_AEAD]) 1551a6509d9SHerbert Xu goto out; 1561a6509d9SHerbert Xu if ((attrs[XFRMA_ALG_AUTH] || 1571a6509d9SHerbert Xu attrs[XFRMA_ALG_CRYPT]) && 1581a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD]) 1591da177e4SLinus Torvalds goto out; 1601da177e4SLinus Torvalds break; 1611da177e4SLinus Torvalds 1621da177e4SLinus Torvalds case IPPROTO_COMP: 16335a7aa08SThomas Graf if (!attrs[XFRMA_ALG_COMP] || 1641a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 16535a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH] || 16635a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT]) 1671da177e4SLinus Torvalds goto out; 1681da177e4SLinus Torvalds break; 1691da177e4SLinus Torvalds 170e23c7194SMasahide NAKAMURA #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 171e23c7194SMasahide NAKAMURA case IPPROTO_DSTOPTS: 172e23c7194SMasahide NAKAMURA case IPPROTO_ROUTING: 17335a7aa08SThomas Graf if (attrs[XFRMA_ALG_COMP] || 17435a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH] || 1751a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD] || 17635a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT] || 17735a7aa08SThomas Graf attrs[XFRMA_ENCAP] || 17835a7aa08SThomas Graf attrs[XFRMA_SEC_CTX] || 17935a7aa08SThomas Graf !attrs[XFRMA_COADDR]) 180e23c7194SMasahide NAKAMURA goto out; 181e23c7194SMasahide NAKAMURA break; 182e23c7194SMasahide NAKAMURA #endif 183e23c7194SMasahide NAKAMURA 1841da177e4SLinus Torvalds default: 1851da177e4SLinus Torvalds goto out; 1863ff50b79SStephen Hemminger } 1871da177e4SLinus Torvalds 1881a6509d9SHerbert Xu if ((err = verify_aead(attrs))) 1891a6509d9SHerbert Xu goto out; 19035a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_AUTH))) 1911da177e4SLinus Torvalds goto out; 19235a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_CRYPT))) 1931da177e4SLinus Torvalds goto out; 19435a7aa08SThomas Graf if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP))) 1951da177e4SLinus Torvalds goto out; 19635a7aa08SThomas Graf if ((err = verify_sec_ctx_len(attrs))) 197df71837dSTrent Jaeger goto out; 1981da177e4SLinus Torvalds 1991da177e4SLinus Torvalds err = -EINVAL; 2001da177e4SLinus Torvalds switch (p->mode) { 2017e49e6deSMasahide NAKAMURA case XFRM_MODE_TRANSPORT: 2027e49e6deSMasahide NAKAMURA case XFRM_MODE_TUNNEL: 203060f02a3SNoriaki TAKAMIYA case XFRM_MODE_ROUTEOPTIMIZATION: 2040a69452cSDiego Beltrami case XFRM_MODE_BEET: 2051da177e4SLinus Torvalds break; 2061da177e4SLinus Torvalds 2071da177e4SLinus Torvalds default: 2081da177e4SLinus Torvalds goto out; 2093ff50b79SStephen Hemminger } 2101da177e4SLinus Torvalds 2111da177e4SLinus Torvalds err = 0; 2121da177e4SLinus Torvalds 2131da177e4SLinus Torvalds out: 2141da177e4SLinus Torvalds return err; 2151da177e4SLinus Torvalds } 2161da177e4SLinus Torvalds 2171da177e4SLinus Torvalds static int attach_one_algo(struct xfrm_algo **algpp, u8 *props, 2181da177e4SLinus Torvalds struct xfrm_algo_desc *(*get_byname)(char *, int), 2195424f32eSThomas Graf struct nlattr *rta) 2201da177e4SLinus Torvalds { 2211da177e4SLinus Torvalds struct xfrm_algo *p, *ualg; 2221da177e4SLinus Torvalds struct xfrm_algo_desc *algo; 2231da177e4SLinus Torvalds 2241da177e4SLinus Torvalds if (!rta) 2251da177e4SLinus Torvalds return 0; 2261da177e4SLinus Torvalds 2275424f32eSThomas Graf ualg = nla_data(rta); 2281da177e4SLinus Torvalds 2291da177e4SLinus Torvalds algo = get_byname(ualg->alg_name, 1); 2301da177e4SLinus Torvalds if (!algo) 2311da177e4SLinus Torvalds return -ENOSYS; 2321da177e4SLinus Torvalds *props = algo->desc.sadb_alg_id; 2331da177e4SLinus Torvalds 2340f99be0dSEric Dumazet p = kmemdup(ualg, xfrm_alg_len(ualg), GFP_KERNEL); 2351da177e4SLinus Torvalds if (!p) 2361da177e4SLinus Torvalds return -ENOMEM; 2371da177e4SLinus Torvalds 23804ff1260SHerbert Xu strcpy(p->alg_name, algo->name); 2391da177e4SLinus Torvalds *algpp = p; 2401da177e4SLinus Torvalds return 0; 2411da177e4SLinus Torvalds } 2421da177e4SLinus Torvalds 2431a6509d9SHerbert Xu static int attach_aead(struct xfrm_algo_aead **algpp, u8 *props, 2441a6509d9SHerbert Xu struct nlattr *rta) 2451a6509d9SHerbert Xu { 2461a6509d9SHerbert Xu struct xfrm_algo_aead *p, *ualg; 2471a6509d9SHerbert Xu struct xfrm_algo_desc *algo; 2481a6509d9SHerbert Xu 2491a6509d9SHerbert Xu if (!rta) 2501a6509d9SHerbert Xu return 0; 2511a6509d9SHerbert Xu 2521a6509d9SHerbert Xu ualg = nla_data(rta); 2531a6509d9SHerbert Xu 2541a6509d9SHerbert Xu algo = xfrm_aead_get_byname(ualg->alg_name, ualg->alg_icv_len, 1); 2551a6509d9SHerbert Xu if (!algo) 2561a6509d9SHerbert Xu return -ENOSYS; 2571a6509d9SHerbert Xu *props = algo->desc.sadb_alg_id; 2581a6509d9SHerbert Xu 2591a6509d9SHerbert Xu p = kmemdup(ualg, aead_len(ualg), GFP_KERNEL); 2601a6509d9SHerbert Xu if (!p) 2611a6509d9SHerbert Xu return -ENOMEM; 2621a6509d9SHerbert Xu 2631a6509d9SHerbert Xu strcpy(p->alg_name, algo->name); 2641a6509d9SHerbert Xu *algpp = p; 2651a6509d9SHerbert Xu return 0; 2661a6509d9SHerbert Xu } 2671a6509d9SHerbert Xu 268661697f7SJoy Latten static inline int xfrm_user_sec_ctx_size(struct xfrm_sec_ctx *xfrm_ctx) 269df71837dSTrent Jaeger { 270df71837dSTrent Jaeger int len = 0; 271df71837dSTrent Jaeger 272df71837dSTrent Jaeger if (xfrm_ctx) { 273df71837dSTrent Jaeger len += sizeof(struct xfrm_user_sec_ctx); 274df71837dSTrent Jaeger len += xfrm_ctx->ctx_len; 275df71837dSTrent Jaeger } 276df71837dSTrent Jaeger return len; 277df71837dSTrent Jaeger } 278df71837dSTrent Jaeger 2791da177e4SLinus Torvalds static void copy_from_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 2801da177e4SLinus Torvalds { 2811da177e4SLinus Torvalds memcpy(&x->id, &p->id, sizeof(x->id)); 2821da177e4SLinus Torvalds memcpy(&x->sel, &p->sel, sizeof(x->sel)); 2831da177e4SLinus Torvalds memcpy(&x->lft, &p->lft, sizeof(x->lft)); 2841da177e4SLinus Torvalds x->props.mode = p->mode; 2851da177e4SLinus Torvalds x->props.replay_window = p->replay_window; 2861da177e4SLinus Torvalds x->props.reqid = p->reqid; 2871da177e4SLinus Torvalds x->props.family = p->family; 28854489c14SDavid S. Miller memcpy(&x->props.saddr, &p->saddr, sizeof(x->props.saddr)); 2891da177e4SLinus Torvalds x->props.flags = p->flags; 290196b0036SHerbert Xu 291196b0036SHerbert Xu /* 292196b0036SHerbert Xu * Set inner address family if the KM left it as zero. 293196b0036SHerbert Xu * See comment in validate_tmpl. 294196b0036SHerbert Xu */ 295196b0036SHerbert Xu if (!x->sel.family) 296196b0036SHerbert Xu x->sel.family = p->family; 2971da177e4SLinus Torvalds } 2981da177e4SLinus Torvalds 299d51d081dSJamal Hadi Salim /* 300d51d081dSJamal Hadi Salim * someday when pfkey also has support, we could have the code 301d51d081dSJamal Hadi Salim * somehow made shareable and move it to xfrm_state.c - JHS 302d51d081dSJamal Hadi Salim * 303d51d081dSJamal Hadi Salim */ 3045424f32eSThomas Graf static void xfrm_update_ae_params(struct xfrm_state *x, struct nlattr **attrs) 305d51d081dSJamal Hadi Salim { 3065424f32eSThomas Graf struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; 3075424f32eSThomas Graf struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; 3085424f32eSThomas Graf struct nlattr *et = attrs[XFRMA_ETIMER_THRESH]; 3095424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_REPLAY_THRESH]; 310d51d081dSJamal Hadi Salim 311d51d081dSJamal Hadi Salim if (rp) { 312d51d081dSJamal Hadi Salim struct xfrm_replay_state *replay; 3135424f32eSThomas Graf replay = nla_data(rp); 314d51d081dSJamal Hadi Salim memcpy(&x->replay, replay, sizeof(*replay)); 315d51d081dSJamal Hadi Salim memcpy(&x->preplay, replay, sizeof(*replay)); 316d51d081dSJamal Hadi Salim } 317d51d081dSJamal Hadi Salim 318d51d081dSJamal Hadi Salim if (lt) { 319d51d081dSJamal Hadi Salim struct xfrm_lifetime_cur *ltime; 3205424f32eSThomas Graf ltime = nla_data(lt); 321d51d081dSJamal Hadi Salim x->curlft.bytes = ltime->bytes; 322d51d081dSJamal Hadi Salim x->curlft.packets = ltime->packets; 323d51d081dSJamal Hadi Salim x->curlft.add_time = ltime->add_time; 324d51d081dSJamal Hadi Salim x->curlft.use_time = ltime->use_time; 325d51d081dSJamal Hadi Salim } 326d51d081dSJamal Hadi Salim 327cf5cb79fSThomas Graf if (et) 3285424f32eSThomas Graf x->replay_maxage = nla_get_u32(et); 329d51d081dSJamal Hadi Salim 330cf5cb79fSThomas Graf if (rt) 3315424f32eSThomas Graf x->replay_maxdiff = nla_get_u32(rt); 332d51d081dSJamal Hadi Salim } 333d51d081dSJamal Hadi Salim 3341da177e4SLinus Torvalds static struct xfrm_state *xfrm_state_construct(struct xfrm_usersa_info *p, 3355424f32eSThomas Graf struct nlattr **attrs, 3361da177e4SLinus Torvalds int *errp) 3371da177e4SLinus Torvalds { 3381da177e4SLinus Torvalds struct xfrm_state *x = xfrm_state_alloc(); 3391da177e4SLinus Torvalds int err = -ENOMEM; 3401da177e4SLinus Torvalds 3411da177e4SLinus Torvalds if (!x) 3421da177e4SLinus Torvalds goto error_no_put; 3431da177e4SLinus Torvalds 3441da177e4SLinus Torvalds copy_from_user_state(x, p); 3451da177e4SLinus Torvalds 3461a6509d9SHerbert Xu if ((err = attach_aead(&x->aead, &x->props.ealgo, 3471a6509d9SHerbert Xu attrs[XFRMA_ALG_AEAD]))) 3481a6509d9SHerbert Xu goto error; 3491da177e4SLinus Torvalds if ((err = attach_one_algo(&x->aalg, &x->props.aalgo, 3501da177e4SLinus Torvalds xfrm_aalg_get_byname, 35135a7aa08SThomas Graf attrs[XFRMA_ALG_AUTH]))) 3521da177e4SLinus Torvalds goto error; 3531da177e4SLinus Torvalds if ((err = attach_one_algo(&x->ealg, &x->props.ealgo, 3541da177e4SLinus Torvalds xfrm_ealg_get_byname, 35535a7aa08SThomas Graf attrs[XFRMA_ALG_CRYPT]))) 3561da177e4SLinus Torvalds goto error; 3571da177e4SLinus Torvalds if ((err = attach_one_algo(&x->calg, &x->props.calgo, 3581da177e4SLinus Torvalds xfrm_calg_get_byname, 35935a7aa08SThomas Graf attrs[XFRMA_ALG_COMP]))) 3601da177e4SLinus Torvalds goto error; 361fd21150aSThomas Graf 362fd21150aSThomas Graf if (attrs[XFRMA_ENCAP]) { 363fd21150aSThomas Graf x->encap = kmemdup(nla_data(attrs[XFRMA_ENCAP]), 364fd21150aSThomas Graf sizeof(*x->encap), GFP_KERNEL); 365fd21150aSThomas Graf if (x->encap == NULL) 3661da177e4SLinus Torvalds goto error; 367fd21150aSThomas Graf } 368fd21150aSThomas Graf 369fd21150aSThomas Graf if (attrs[XFRMA_COADDR]) { 370fd21150aSThomas Graf x->coaddr = kmemdup(nla_data(attrs[XFRMA_COADDR]), 371fd21150aSThomas Graf sizeof(*x->coaddr), GFP_KERNEL); 372fd21150aSThomas Graf if (x->coaddr == NULL) 373060f02a3SNoriaki TAKAMIYA goto error; 374fd21150aSThomas Graf } 375fd21150aSThomas Graf 37672cb6962SHerbert Xu err = xfrm_init_state(x); 3771da177e4SLinus Torvalds if (err) 3781da177e4SLinus Torvalds goto error; 3791da177e4SLinus Torvalds 380fd21150aSThomas Graf if (attrs[XFRMA_SEC_CTX] && 381fd21150aSThomas Graf security_xfrm_state_alloc(x, nla_data(attrs[XFRMA_SEC_CTX]))) 382df71837dSTrent Jaeger goto error; 383df71837dSTrent Jaeger 3841da177e4SLinus Torvalds x->km.seq = p->seq; 385d51d081dSJamal Hadi Salim x->replay_maxdiff = sysctl_xfrm_aevent_rseqth; 386d51d081dSJamal Hadi Salim /* sysctl_xfrm_aevent_etime is in 100ms units */ 387d51d081dSJamal Hadi Salim x->replay_maxage = (sysctl_xfrm_aevent_etime*HZ)/XFRM_AE_ETH_M; 388d51d081dSJamal Hadi Salim x->preplay.bitmap = 0; 389d51d081dSJamal Hadi Salim x->preplay.seq = x->replay.seq+x->replay_maxdiff; 390d51d081dSJamal Hadi Salim x->preplay.oseq = x->replay.oseq +x->replay_maxdiff; 391d51d081dSJamal Hadi Salim 392d51d081dSJamal Hadi Salim /* override default values from above */ 393d51d081dSJamal Hadi Salim 3945424f32eSThomas Graf xfrm_update_ae_params(x, attrs); 3951da177e4SLinus Torvalds 3961da177e4SLinus Torvalds return x; 3971da177e4SLinus Torvalds 3981da177e4SLinus Torvalds error: 3991da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 4001da177e4SLinus Torvalds xfrm_state_put(x); 4011da177e4SLinus Torvalds error_no_put: 4021da177e4SLinus Torvalds *errp = err; 4031da177e4SLinus Torvalds return NULL; 4041da177e4SLinus Torvalds } 4051da177e4SLinus Torvalds 40622e70050SChristoph Hellwig static int xfrm_add_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 4075424f32eSThomas Graf struct nlattr **attrs) 4081da177e4SLinus Torvalds { 4097b67c857SThomas Graf struct xfrm_usersa_info *p = nlmsg_data(nlh); 4101da177e4SLinus Torvalds struct xfrm_state *x; 4111da177e4SLinus Torvalds int err; 41226b15dadSJamal Hadi Salim struct km_event c; 4131da177e4SLinus Torvalds 41435a7aa08SThomas Graf err = verify_newsa_info(p, attrs); 4151da177e4SLinus Torvalds if (err) 4161da177e4SLinus Torvalds return err; 4171da177e4SLinus Torvalds 41835a7aa08SThomas Graf x = xfrm_state_construct(p, attrs, &err); 4191da177e4SLinus Torvalds if (!x) 4201da177e4SLinus Torvalds return err; 4211da177e4SLinus Torvalds 42226b15dadSJamal Hadi Salim xfrm_state_hold(x); 4231da177e4SLinus Torvalds if (nlh->nlmsg_type == XFRM_MSG_NEWSA) 4241da177e4SLinus Torvalds err = xfrm_state_add(x); 4251da177e4SLinus Torvalds else 4261da177e4SLinus Torvalds err = xfrm_state_update(x); 4271da177e4SLinus Torvalds 428ab5f5e8bSJoy Latten xfrm_audit_state_add(x, err ? 0 : 1, NETLINK_CB(skb).loginuid, 429ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 430161a09e7SJoy Latten 4311da177e4SLinus Torvalds if (err < 0) { 4321da177e4SLinus Torvalds x->km.state = XFRM_STATE_DEAD; 43321380b81SHerbert Xu __xfrm_state_put(x); 4347d6dfe1fSPatrick McHardy goto out; 4351da177e4SLinus Torvalds } 4361da177e4SLinus Torvalds 43726b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 43826b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 439f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 44026b15dadSJamal Hadi Salim 44126b15dadSJamal Hadi Salim km_state_notify(x, &c); 4427d6dfe1fSPatrick McHardy out: 44326b15dadSJamal Hadi Salim xfrm_state_put(x); 4441da177e4SLinus Torvalds return err; 4451da177e4SLinus Torvalds } 4461da177e4SLinus Torvalds 447eb2971b6SMasahide NAKAMURA static struct xfrm_state *xfrm_user_state_lookup(struct xfrm_usersa_id *p, 4485424f32eSThomas Graf struct nlattr **attrs, 449eb2971b6SMasahide NAKAMURA int *errp) 450eb2971b6SMasahide NAKAMURA { 451eb2971b6SMasahide NAKAMURA struct xfrm_state *x = NULL; 452eb2971b6SMasahide NAKAMURA int err; 453eb2971b6SMasahide NAKAMURA 454eb2971b6SMasahide NAKAMURA if (xfrm_id_proto_match(p->proto, IPSEC_PROTO_ANY)) { 455eb2971b6SMasahide NAKAMURA err = -ESRCH; 456eb2971b6SMasahide NAKAMURA x = xfrm_state_lookup(&p->daddr, p->spi, p->proto, p->family); 457eb2971b6SMasahide NAKAMURA } else { 458eb2971b6SMasahide NAKAMURA xfrm_address_t *saddr = NULL; 459eb2971b6SMasahide NAKAMURA 46035a7aa08SThomas Graf verify_one_addr(attrs, XFRMA_SRCADDR, &saddr); 461eb2971b6SMasahide NAKAMURA if (!saddr) { 462eb2971b6SMasahide NAKAMURA err = -EINVAL; 463eb2971b6SMasahide NAKAMURA goto out; 464eb2971b6SMasahide NAKAMURA } 465eb2971b6SMasahide NAKAMURA 4669abbffeeSMasahide NAKAMURA err = -ESRCH; 467eb2971b6SMasahide NAKAMURA x = xfrm_state_lookup_byaddr(&p->daddr, saddr, p->proto, 468eb2971b6SMasahide NAKAMURA p->family); 469eb2971b6SMasahide NAKAMURA } 470eb2971b6SMasahide NAKAMURA 471eb2971b6SMasahide NAKAMURA out: 472eb2971b6SMasahide NAKAMURA if (!x && errp) 473eb2971b6SMasahide NAKAMURA *errp = err; 474eb2971b6SMasahide NAKAMURA return x; 475eb2971b6SMasahide NAKAMURA } 476eb2971b6SMasahide NAKAMURA 47722e70050SChristoph Hellwig static int xfrm_del_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 4785424f32eSThomas Graf struct nlattr **attrs) 4791da177e4SLinus Torvalds { 4801da177e4SLinus Torvalds struct xfrm_state *x; 481eb2971b6SMasahide NAKAMURA int err = -ESRCH; 48226b15dadSJamal Hadi Salim struct km_event c; 4837b67c857SThomas Graf struct xfrm_usersa_id *p = nlmsg_data(nlh); 4841da177e4SLinus Torvalds 48535a7aa08SThomas Graf x = xfrm_user_state_lookup(p, attrs, &err); 4861da177e4SLinus Torvalds if (x == NULL) 487eb2971b6SMasahide NAKAMURA return err; 4881da177e4SLinus Torvalds 4896f68dc37SDavid S. Miller if ((err = security_xfrm_state_delete(x)) != 0) 490c8c05a8eSCatherine Zhang goto out; 491c8c05a8eSCatherine Zhang 4921da177e4SLinus Torvalds if (xfrm_state_kern(x)) { 493c8c05a8eSCatherine Zhang err = -EPERM; 494c8c05a8eSCatherine Zhang goto out; 4951da177e4SLinus Torvalds } 4961da177e4SLinus Torvalds 49726b15dadSJamal Hadi Salim err = xfrm_state_delete(x); 498161a09e7SJoy Latten 499c8c05a8eSCatherine Zhang if (err < 0) 500c8c05a8eSCatherine Zhang goto out; 50126b15dadSJamal Hadi Salim 50226b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 50326b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 504f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 50526b15dadSJamal Hadi Salim km_state_notify(x, &c); 5061da177e4SLinus Torvalds 507c8c05a8eSCatherine Zhang out: 508ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, err ? 0 : 1, NETLINK_CB(skb).loginuid, 509ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 510c8c05a8eSCatherine Zhang xfrm_state_put(x); 51126b15dadSJamal Hadi Salim return err; 5121da177e4SLinus Torvalds } 5131da177e4SLinus Torvalds 5141da177e4SLinus Torvalds static void copy_to_user_state(struct xfrm_state *x, struct xfrm_usersa_info *p) 5151da177e4SLinus Torvalds { 5161da177e4SLinus Torvalds memcpy(&p->id, &x->id, sizeof(p->id)); 5171da177e4SLinus Torvalds memcpy(&p->sel, &x->sel, sizeof(p->sel)); 5181da177e4SLinus Torvalds memcpy(&p->lft, &x->lft, sizeof(p->lft)); 5191da177e4SLinus Torvalds memcpy(&p->curlft, &x->curlft, sizeof(p->curlft)); 5201da177e4SLinus Torvalds memcpy(&p->stats, &x->stats, sizeof(p->stats)); 52154489c14SDavid S. Miller memcpy(&p->saddr, &x->props.saddr, sizeof(p->saddr)); 5221da177e4SLinus Torvalds p->mode = x->props.mode; 5231da177e4SLinus Torvalds p->replay_window = x->props.replay_window; 5241da177e4SLinus Torvalds p->reqid = x->props.reqid; 5251da177e4SLinus Torvalds p->family = x->props.family; 5261da177e4SLinus Torvalds p->flags = x->props.flags; 5271da177e4SLinus Torvalds p->seq = x->km.seq; 5281da177e4SLinus Torvalds } 5291da177e4SLinus Torvalds 5301da177e4SLinus Torvalds struct xfrm_dump_info { 5311da177e4SLinus Torvalds struct sk_buff *in_skb; 5321da177e4SLinus Torvalds struct sk_buff *out_skb; 5331da177e4SLinus Torvalds u32 nlmsg_seq; 5341da177e4SLinus Torvalds u16 nlmsg_flags; 5351da177e4SLinus Torvalds }; 5361da177e4SLinus Torvalds 537c0144beaSThomas Graf static int copy_sec_ctx(struct xfrm_sec_ctx *s, struct sk_buff *skb) 538c0144beaSThomas Graf { 539c0144beaSThomas Graf struct xfrm_user_sec_ctx *uctx; 540c0144beaSThomas Graf struct nlattr *attr; 54168325d3bSHerbert Xu int ctx_size = sizeof(*uctx) + s->ctx_len; 542c0144beaSThomas Graf 543c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_SEC_CTX, ctx_size); 544c0144beaSThomas Graf if (attr == NULL) 545c0144beaSThomas Graf return -EMSGSIZE; 546c0144beaSThomas Graf 547c0144beaSThomas Graf uctx = nla_data(attr); 548c0144beaSThomas Graf uctx->exttype = XFRMA_SEC_CTX; 549c0144beaSThomas Graf uctx->len = ctx_size; 550c0144beaSThomas Graf uctx->ctx_doi = s->ctx_doi; 551c0144beaSThomas Graf uctx->ctx_alg = s->ctx_alg; 552c0144beaSThomas Graf uctx->ctx_len = s->ctx_len; 553c0144beaSThomas Graf memcpy(uctx + 1, s->ctx_str, s->ctx_len); 554c0144beaSThomas Graf 555c0144beaSThomas Graf return 0; 556c0144beaSThomas Graf } 557c0144beaSThomas Graf 55868325d3bSHerbert Xu /* Don't change this without updating xfrm_sa_len! */ 55968325d3bSHerbert Xu static int copy_to_user_state_extra(struct xfrm_state *x, 56068325d3bSHerbert Xu struct xfrm_usersa_info *p, 56168325d3bSHerbert Xu struct sk_buff *skb) 5621da177e4SLinus Torvalds { 5631da177e4SLinus Torvalds copy_to_user_state(x, p); 5641da177e4SLinus Torvalds 565050f009eSHerbert Xu if (x->coaddr) 566050f009eSHerbert Xu NLA_PUT(skb, XFRMA_COADDR, sizeof(*x->coaddr), x->coaddr); 567050f009eSHerbert Xu 568050f009eSHerbert Xu if (x->lastused) 569050f009eSHerbert Xu NLA_PUT_U64(skb, XFRMA_LASTUSED, x->lastused); 570050f009eSHerbert Xu 5711a6509d9SHerbert Xu if (x->aead) 5721a6509d9SHerbert Xu NLA_PUT(skb, XFRMA_ALG_AEAD, aead_len(x->aead), x->aead); 5731da177e4SLinus Torvalds if (x->aalg) 5740f99be0dSEric Dumazet NLA_PUT(skb, XFRMA_ALG_AUTH, xfrm_alg_len(x->aalg), x->aalg); 5751da177e4SLinus Torvalds if (x->ealg) 5760f99be0dSEric Dumazet NLA_PUT(skb, XFRMA_ALG_CRYPT, xfrm_alg_len(x->ealg), x->ealg); 5771da177e4SLinus Torvalds if (x->calg) 578c0144beaSThomas Graf NLA_PUT(skb, XFRMA_ALG_COMP, sizeof(*(x->calg)), x->calg); 5791da177e4SLinus Torvalds 5801da177e4SLinus Torvalds if (x->encap) 581c0144beaSThomas Graf NLA_PUT(skb, XFRMA_ENCAP, sizeof(*x->encap), x->encap); 5821da177e4SLinus Torvalds 583c0144beaSThomas Graf if (x->security && copy_sec_ctx(x->security, skb) < 0) 584c0144beaSThomas Graf goto nla_put_failure; 585060f02a3SNoriaki TAKAMIYA 58668325d3bSHerbert Xu return 0; 58768325d3bSHerbert Xu 58868325d3bSHerbert Xu nla_put_failure: 58968325d3bSHerbert Xu return -EMSGSIZE; 59068325d3bSHerbert Xu } 59168325d3bSHerbert Xu 59268325d3bSHerbert Xu static int dump_one_state(struct xfrm_state *x, int count, void *ptr) 59368325d3bSHerbert Xu { 59468325d3bSHerbert Xu struct xfrm_dump_info *sp = ptr; 59568325d3bSHerbert Xu struct sk_buff *in_skb = sp->in_skb; 59668325d3bSHerbert Xu struct sk_buff *skb = sp->out_skb; 59768325d3bSHerbert Xu struct xfrm_usersa_info *p; 59868325d3bSHerbert Xu struct nlmsghdr *nlh; 59968325d3bSHerbert Xu int err; 60068325d3bSHerbert Xu 60168325d3bSHerbert Xu nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 60268325d3bSHerbert Xu XFRM_MSG_NEWSA, sizeof(*p), sp->nlmsg_flags); 60368325d3bSHerbert Xu if (nlh == NULL) 60468325d3bSHerbert Xu return -EMSGSIZE; 60568325d3bSHerbert Xu 60668325d3bSHerbert Xu p = nlmsg_data(nlh); 60768325d3bSHerbert Xu 60868325d3bSHerbert Xu err = copy_to_user_state_extra(x, p, skb); 60968325d3bSHerbert Xu if (err) 61068325d3bSHerbert Xu goto nla_put_failure; 61168325d3bSHerbert Xu 6129825069dSThomas Graf nlmsg_end(skb, nlh); 6131da177e4SLinus Torvalds return 0; 6141da177e4SLinus Torvalds 615c0144beaSThomas Graf nla_put_failure: 6169825069dSThomas Graf nlmsg_cancel(skb, nlh); 61768325d3bSHerbert Xu return err; 6181da177e4SLinus Torvalds } 6191da177e4SLinus Torvalds 620*4c563f76STimo Teras static int xfrm_dump_sa_done(struct netlink_callback *cb) 621*4c563f76STimo Teras { 622*4c563f76STimo Teras struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; 623*4c563f76STimo Teras xfrm_state_walk_done(walk); 624*4c563f76STimo Teras return 0; 625*4c563f76STimo Teras } 626*4c563f76STimo Teras 6271da177e4SLinus Torvalds static int xfrm_dump_sa(struct sk_buff *skb, struct netlink_callback *cb) 6281da177e4SLinus Torvalds { 629*4c563f76STimo Teras struct xfrm_state_walk *walk = (struct xfrm_state_walk *) &cb->args[1]; 6301da177e4SLinus Torvalds struct xfrm_dump_info info; 6311da177e4SLinus Torvalds 632*4c563f76STimo Teras BUILD_BUG_ON(sizeof(struct xfrm_state_walk) > 633*4c563f76STimo Teras sizeof(cb->args) - sizeof(cb->args[0])); 634*4c563f76STimo Teras 6351da177e4SLinus Torvalds info.in_skb = cb->skb; 6361da177e4SLinus Torvalds info.out_skb = skb; 6371da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 6381da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 639*4c563f76STimo Teras 640*4c563f76STimo Teras if (!cb->args[0]) { 641*4c563f76STimo Teras cb->args[0] = 1; 642*4c563f76STimo Teras xfrm_state_walk_init(walk, 0); 643*4c563f76STimo Teras } 644*4c563f76STimo Teras 645*4c563f76STimo Teras (void) xfrm_state_walk(walk, dump_one_state, &info); 6461da177e4SLinus Torvalds 6471da177e4SLinus Torvalds return skb->len; 6481da177e4SLinus Torvalds } 6491da177e4SLinus Torvalds 6501da177e4SLinus Torvalds static struct sk_buff *xfrm_state_netlink(struct sk_buff *in_skb, 6511da177e4SLinus Torvalds struct xfrm_state *x, u32 seq) 6521da177e4SLinus Torvalds { 6531da177e4SLinus Torvalds struct xfrm_dump_info info; 6541da177e4SLinus Torvalds struct sk_buff *skb; 6551da177e4SLinus Torvalds 6567deb2264SThomas Graf skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_ATOMIC); 6571da177e4SLinus Torvalds if (!skb) 6581da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 6591da177e4SLinus Torvalds 6601da177e4SLinus Torvalds info.in_skb = in_skb; 6611da177e4SLinus Torvalds info.out_skb = skb; 6621da177e4SLinus Torvalds info.nlmsg_seq = seq; 6631da177e4SLinus Torvalds info.nlmsg_flags = 0; 6641da177e4SLinus Torvalds 6651da177e4SLinus Torvalds if (dump_one_state(x, 0, &info)) { 6661da177e4SLinus Torvalds kfree_skb(skb); 6671da177e4SLinus Torvalds return NULL; 6681da177e4SLinus Torvalds } 6691da177e4SLinus Torvalds 6701da177e4SLinus Torvalds return skb; 6711da177e4SLinus Torvalds } 6721da177e4SLinus Torvalds 6737deb2264SThomas Graf static inline size_t xfrm_spdinfo_msgsize(void) 6747deb2264SThomas Graf { 6757deb2264SThomas Graf return NLMSG_ALIGN(4) 6767deb2264SThomas Graf + nla_total_size(sizeof(struct xfrmu_spdinfo)) 6777deb2264SThomas Graf + nla_total_size(sizeof(struct xfrmu_spdhinfo)); 6787deb2264SThomas Graf } 6797deb2264SThomas Graf 680ecfd6b18SJamal Hadi Salim static int build_spdinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) 681ecfd6b18SJamal Hadi Salim { 6825a6d3416SJamal Hadi Salim struct xfrmk_spdinfo si; 6835a6d3416SJamal Hadi Salim struct xfrmu_spdinfo spc; 6845a6d3416SJamal Hadi Salim struct xfrmu_spdhinfo sph; 685ecfd6b18SJamal Hadi Salim struct nlmsghdr *nlh; 686ecfd6b18SJamal Hadi Salim u32 *f; 687ecfd6b18SJamal Hadi Salim 688ecfd6b18SJamal Hadi Salim nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSPDINFO, sizeof(u32), 0); 689ecfd6b18SJamal Hadi Salim if (nlh == NULL) /* shouldnt really happen ... */ 690ecfd6b18SJamal Hadi Salim return -EMSGSIZE; 691ecfd6b18SJamal Hadi Salim 692ecfd6b18SJamal Hadi Salim f = nlmsg_data(nlh); 693ecfd6b18SJamal Hadi Salim *f = flags; 694ecfd6b18SJamal Hadi Salim xfrm_spd_getinfo(&si); 6955a6d3416SJamal Hadi Salim spc.incnt = si.incnt; 6965a6d3416SJamal Hadi Salim spc.outcnt = si.outcnt; 6975a6d3416SJamal Hadi Salim spc.fwdcnt = si.fwdcnt; 6985a6d3416SJamal Hadi Salim spc.inscnt = si.inscnt; 6995a6d3416SJamal Hadi Salim spc.outscnt = si.outscnt; 7005a6d3416SJamal Hadi Salim spc.fwdscnt = si.fwdscnt; 7015a6d3416SJamal Hadi Salim sph.spdhcnt = si.spdhcnt; 7025a6d3416SJamal Hadi Salim sph.spdhmcnt = si.spdhmcnt; 703ecfd6b18SJamal Hadi Salim 7045a6d3416SJamal Hadi Salim NLA_PUT(skb, XFRMA_SPD_INFO, sizeof(spc), &spc); 7055a6d3416SJamal Hadi Salim NLA_PUT(skb, XFRMA_SPD_HINFO, sizeof(sph), &sph); 706ecfd6b18SJamal Hadi Salim 707ecfd6b18SJamal Hadi Salim return nlmsg_end(skb, nlh); 708ecfd6b18SJamal Hadi Salim 709ecfd6b18SJamal Hadi Salim nla_put_failure: 710ecfd6b18SJamal Hadi Salim nlmsg_cancel(skb, nlh); 711ecfd6b18SJamal Hadi Salim return -EMSGSIZE; 712ecfd6b18SJamal Hadi Salim } 713ecfd6b18SJamal Hadi Salim 714ecfd6b18SJamal Hadi Salim static int xfrm_get_spdinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 7155424f32eSThomas Graf struct nlattr **attrs) 716ecfd6b18SJamal Hadi Salim { 717ecfd6b18SJamal Hadi Salim struct sk_buff *r_skb; 7187b67c857SThomas Graf u32 *flags = nlmsg_data(nlh); 719ecfd6b18SJamal Hadi Salim u32 spid = NETLINK_CB(skb).pid; 720ecfd6b18SJamal Hadi Salim u32 seq = nlh->nlmsg_seq; 721ecfd6b18SJamal Hadi Salim 7227deb2264SThomas Graf r_skb = nlmsg_new(xfrm_spdinfo_msgsize(), GFP_ATOMIC); 723ecfd6b18SJamal Hadi Salim if (r_skb == NULL) 724ecfd6b18SJamal Hadi Salim return -ENOMEM; 725ecfd6b18SJamal Hadi Salim 726ecfd6b18SJamal Hadi Salim if (build_spdinfo(r_skb, spid, seq, *flags) < 0) 727ecfd6b18SJamal Hadi Salim BUG(); 728ecfd6b18SJamal Hadi Salim 729ecfd6b18SJamal Hadi Salim return nlmsg_unicast(xfrm_nl, r_skb, spid); 730ecfd6b18SJamal Hadi Salim } 731ecfd6b18SJamal Hadi Salim 7327deb2264SThomas Graf static inline size_t xfrm_sadinfo_msgsize(void) 7337deb2264SThomas Graf { 7347deb2264SThomas Graf return NLMSG_ALIGN(4) 7357deb2264SThomas Graf + nla_total_size(sizeof(struct xfrmu_sadhinfo)) 7367deb2264SThomas Graf + nla_total_size(4); /* XFRMA_SAD_CNT */ 7377deb2264SThomas Graf } 7387deb2264SThomas Graf 73928d8909bSJamal Hadi Salim static int build_sadinfo(struct sk_buff *skb, u32 pid, u32 seq, u32 flags) 74028d8909bSJamal Hadi Salim { 741af11e316SJamal Hadi Salim struct xfrmk_sadinfo si; 742af11e316SJamal Hadi Salim struct xfrmu_sadhinfo sh; 74328d8909bSJamal Hadi Salim struct nlmsghdr *nlh; 74428d8909bSJamal Hadi Salim u32 *f; 74528d8909bSJamal Hadi Salim 74628d8909bSJamal Hadi Salim nlh = nlmsg_put(skb, pid, seq, XFRM_MSG_NEWSADINFO, sizeof(u32), 0); 74728d8909bSJamal Hadi Salim if (nlh == NULL) /* shouldnt really happen ... */ 74828d8909bSJamal Hadi Salim return -EMSGSIZE; 74928d8909bSJamal Hadi Salim 75028d8909bSJamal Hadi Salim f = nlmsg_data(nlh); 75128d8909bSJamal Hadi Salim *f = flags; 75228d8909bSJamal Hadi Salim xfrm_sad_getinfo(&si); 75328d8909bSJamal Hadi Salim 754af11e316SJamal Hadi Salim sh.sadhmcnt = si.sadhmcnt; 755af11e316SJamal Hadi Salim sh.sadhcnt = si.sadhcnt; 756af11e316SJamal Hadi Salim 757af11e316SJamal Hadi Salim NLA_PUT_U32(skb, XFRMA_SAD_CNT, si.sadcnt); 758af11e316SJamal Hadi Salim NLA_PUT(skb, XFRMA_SAD_HINFO, sizeof(sh), &sh); 75928d8909bSJamal Hadi Salim 76028d8909bSJamal Hadi Salim return nlmsg_end(skb, nlh); 76128d8909bSJamal Hadi Salim 76228d8909bSJamal Hadi Salim nla_put_failure: 76328d8909bSJamal Hadi Salim nlmsg_cancel(skb, nlh); 76428d8909bSJamal Hadi Salim return -EMSGSIZE; 76528d8909bSJamal Hadi Salim } 76628d8909bSJamal Hadi Salim 76728d8909bSJamal Hadi Salim static int xfrm_get_sadinfo(struct sk_buff *skb, struct nlmsghdr *nlh, 7685424f32eSThomas Graf struct nlattr **attrs) 76928d8909bSJamal Hadi Salim { 77028d8909bSJamal Hadi Salim struct sk_buff *r_skb; 7717b67c857SThomas Graf u32 *flags = nlmsg_data(nlh); 77228d8909bSJamal Hadi Salim u32 spid = NETLINK_CB(skb).pid; 77328d8909bSJamal Hadi Salim u32 seq = nlh->nlmsg_seq; 77428d8909bSJamal Hadi Salim 7757deb2264SThomas Graf r_skb = nlmsg_new(xfrm_sadinfo_msgsize(), GFP_ATOMIC); 77628d8909bSJamal Hadi Salim if (r_skb == NULL) 77728d8909bSJamal Hadi Salim return -ENOMEM; 77828d8909bSJamal Hadi Salim 77928d8909bSJamal Hadi Salim if (build_sadinfo(r_skb, spid, seq, *flags) < 0) 78028d8909bSJamal Hadi Salim BUG(); 78128d8909bSJamal Hadi Salim 78228d8909bSJamal Hadi Salim return nlmsg_unicast(xfrm_nl, r_skb, spid); 78328d8909bSJamal Hadi Salim } 78428d8909bSJamal Hadi Salim 78522e70050SChristoph Hellwig static int xfrm_get_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 7865424f32eSThomas Graf struct nlattr **attrs) 7871da177e4SLinus Torvalds { 7887b67c857SThomas Graf struct xfrm_usersa_id *p = nlmsg_data(nlh); 7891da177e4SLinus Torvalds struct xfrm_state *x; 7901da177e4SLinus Torvalds struct sk_buff *resp_skb; 791eb2971b6SMasahide NAKAMURA int err = -ESRCH; 7921da177e4SLinus Torvalds 79335a7aa08SThomas Graf x = xfrm_user_state_lookup(p, attrs, &err); 7941da177e4SLinus Torvalds if (x == NULL) 7951da177e4SLinus Torvalds goto out_noput; 7961da177e4SLinus Torvalds 7971da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 7981da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 7991da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 8001da177e4SLinus Torvalds } else { 801082a1ad5SThomas Graf err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); 8021da177e4SLinus Torvalds } 8031da177e4SLinus Torvalds xfrm_state_put(x); 8041da177e4SLinus Torvalds out_noput: 8051da177e4SLinus Torvalds return err; 8061da177e4SLinus Torvalds } 8071da177e4SLinus Torvalds 8081da177e4SLinus Torvalds static int verify_userspi_info(struct xfrm_userspi_info *p) 8091da177e4SLinus Torvalds { 8101da177e4SLinus Torvalds switch (p->info.id.proto) { 8111da177e4SLinus Torvalds case IPPROTO_AH: 8121da177e4SLinus Torvalds case IPPROTO_ESP: 8131da177e4SLinus Torvalds break; 8141da177e4SLinus Torvalds 8151da177e4SLinus Torvalds case IPPROTO_COMP: 8161da177e4SLinus Torvalds /* IPCOMP spi is 16-bits. */ 8171da177e4SLinus Torvalds if (p->max >= 0x10000) 8181da177e4SLinus Torvalds return -EINVAL; 8191da177e4SLinus Torvalds break; 8201da177e4SLinus Torvalds 8211da177e4SLinus Torvalds default: 8221da177e4SLinus Torvalds return -EINVAL; 8233ff50b79SStephen Hemminger } 8241da177e4SLinus Torvalds 8251da177e4SLinus Torvalds if (p->min > p->max) 8261da177e4SLinus Torvalds return -EINVAL; 8271da177e4SLinus Torvalds 8281da177e4SLinus Torvalds return 0; 8291da177e4SLinus Torvalds } 8301da177e4SLinus Torvalds 83122e70050SChristoph Hellwig static int xfrm_alloc_userspi(struct sk_buff *skb, struct nlmsghdr *nlh, 8325424f32eSThomas Graf struct nlattr **attrs) 8331da177e4SLinus Torvalds { 8341da177e4SLinus Torvalds struct xfrm_state *x; 8351da177e4SLinus Torvalds struct xfrm_userspi_info *p; 8361da177e4SLinus Torvalds struct sk_buff *resp_skb; 8371da177e4SLinus Torvalds xfrm_address_t *daddr; 8381da177e4SLinus Torvalds int family; 8391da177e4SLinus Torvalds int err; 8401da177e4SLinus Torvalds 8417b67c857SThomas Graf p = nlmsg_data(nlh); 8421da177e4SLinus Torvalds err = verify_userspi_info(p); 8431da177e4SLinus Torvalds if (err) 8441da177e4SLinus Torvalds goto out_noput; 8451da177e4SLinus Torvalds 8461da177e4SLinus Torvalds family = p->info.family; 8471da177e4SLinus Torvalds daddr = &p->info.id.daddr; 8481da177e4SLinus Torvalds 8491da177e4SLinus Torvalds x = NULL; 8501da177e4SLinus Torvalds if (p->info.seq) { 8511da177e4SLinus Torvalds x = xfrm_find_acq_byseq(p->info.seq); 8521da177e4SLinus Torvalds if (x && xfrm_addr_cmp(&x->id.daddr, daddr, family)) { 8531da177e4SLinus Torvalds xfrm_state_put(x); 8541da177e4SLinus Torvalds x = NULL; 8551da177e4SLinus Torvalds } 8561da177e4SLinus Torvalds } 8571da177e4SLinus Torvalds 8581da177e4SLinus Torvalds if (!x) 8591da177e4SLinus Torvalds x = xfrm_find_acq(p->info.mode, p->info.reqid, 8601da177e4SLinus Torvalds p->info.id.proto, daddr, 8611da177e4SLinus Torvalds &p->info.saddr, 1, 8621da177e4SLinus Torvalds family); 8631da177e4SLinus Torvalds err = -ENOENT; 8641da177e4SLinus Torvalds if (x == NULL) 8651da177e4SLinus Torvalds goto out_noput; 8661da177e4SLinus Torvalds 867658b219eSHerbert Xu err = xfrm_alloc_spi(x, p->min, p->max); 868658b219eSHerbert Xu if (err) 869658b219eSHerbert Xu goto out; 8701da177e4SLinus Torvalds 8711da177e4SLinus Torvalds resp_skb = xfrm_state_netlink(skb, x, nlh->nlmsg_seq); 8721da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 8731da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 8741da177e4SLinus Torvalds goto out; 8751da177e4SLinus Torvalds } 8761da177e4SLinus Torvalds 877082a1ad5SThomas Graf err = nlmsg_unicast(xfrm_nl, resp_skb, NETLINK_CB(skb).pid); 8781da177e4SLinus Torvalds 8791da177e4SLinus Torvalds out: 8801da177e4SLinus Torvalds xfrm_state_put(x); 8811da177e4SLinus Torvalds out_noput: 8821da177e4SLinus Torvalds return err; 8831da177e4SLinus Torvalds } 8841da177e4SLinus Torvalds 885b798a9edSJamal Hadi Salim static int verify_policy_dir(u8 dir) 8861da177e4SLinus Torvalds { 8871da177e4SLinus Torvalds switch (dir) { 8881da177e4SLinus Torvalds case XFRM_POLICY_IN: 8891da177e4SLinus Torvalds case XFRM_POLICY_OUT: 8901da177e4SLinus Torvalds case XFRM_POLICY_FWD: 8911da177e4SLinus Torvalds break; 8921da177e4SLinus Torvalds 8931da177e4SLinus Torvalds default: 8941da177e4SLinus Torvalds return -EINVAL; 8953ff50b79SStephen Hemminger } 8961da177e4SLinus Torvalds 8971da177e4SLinus Torvalds return 0; 8981da177e4SLinus Torvalds } 8991da177e4SLinus Torvalds 900b798a9edSJamal Hadi Salim static int verify_policy_type(u8 type) 901f7b6983fSMasahide NAKAMURA { 902f7b6983fSMasahide NAKAMURA switch (type) { 903f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_MAIN: 904f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 905f7b6983fSMasahide NAKAMURA case XFRM_POLICY_TYPE_SUB: 906f7b6983fSMasahide NAKAMURA #endif 907f7b6983fSMasahide NAKAMURA break; 908f7b6983fSMasahide NAKAMURA 909f7b6983fSMasahide NAKAMURA default: 910f7b6983fSMasahide NAKAMURA return -EINVAL; 9113ff50b79SStephen Hemminger } 912f7b6983fSMasahide NAKAMURA 913f7b6983fSMasahide NAKAMURA return 0; 914f7b6983fSMasahide NAKAMURA } 915f7b6983fSMasahide NAKAMURA 9161da177e4SLinus Torvalds static int verify_newpolicy_info(struct xfrm_userpolicy_info *p) 9171da177e4SLinus Torvalds { 9181da177e4SLinus Torvalds switch (p->share) { 9191da177e4SLinus Torvalds case XFRM_SHARE_ANY: 9201da177e4SLinus Torvalds case XFRM_SHARE_SESSION: 9211da177e4SLinus Torvalds case XFRM_SHARE_USER: 9221da177e4SLinus Torvalds case XFRM_SHARE_UNIQUE: 9231da177e4SLinus Torvalds break; 9241da177e4SLinus Torvalds 9251da177e4SLinus Torvalds default: 9261da177e4SLinus Torvalds return -EINVAL; 9273ff50b79SStephen Hemminger } 9281da177e4SLinus Torvalds 9291da177e4SLinus Torvalds switch (p->action) { 9301da177e4SLinus Torvalds case XFRM_POLICY_ALLOW: 9311da177e4SLinus Torvalds case XFRM_POLICY_BLOCK: 9321da177e4SLinus Torvalds break; 9331da177e4SLinus Torvalds 9341da177e4SLinus Torvalds default: 9351da177e4SLinus Torvalds return -EINVAL; 9363ff50b79SStephen Hemminger } 9371da177e4SLinus Torvalds 9381da177e4SLinus Torvalds switch (p->sel.family) { 9391da177e4SLinus Torvalds case AF_INET: 9401da177e4SLinus Torvalds break; 9411da177e4SLinus Torvalds 9421da177e4SLinus Torvalds case AF_INET6: 9431da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 9441da177e4SLinus Torvalds break; 9451da177e4SLinus Torvalds #else 9461da177e4SLinus Torvalds return -EAFNOSUPPORT; 9471da177e4SLinus Torvalds #endif 9481da177e4SLinus Torvalds 9491da177e4SLinus Torvalds default: 9501da177e4SLinus Torvalds return -EINVAL; 9513ff50b79SStephen Hemminger } 9521da177e4SLinus Torvalds 9531da177e4SLinus Torvalds return verify_policy_dir(p->dir); 9541da177e4SLinus Torvalds } 9551da177e4SLinus Torvalds 9565424f32eSThomas Graf static int copy_from_user_sec_ctx(struct xfrm_policy *pol, struct nlattr **attrs) 957df71837dSTrent Jaeger { 9585424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 959df71837dSTrent Jaeger struct xfrm_user_sec_ctx *uctx; 960df71837dSTrent Jaeger 961df71837dSTrent Jaeger if (!rt) 962df71837dSTrent Jaeger return 0; 963df71837dSTrent Jaeger 9645424f32eSThomas Graf uctx = nla_data(rt); 965df71837dSTrent Jaeger return security_xfrm_policy_alloc(pol, uctx); 966df71837dSTrent Jaeger } 967df71837dSTrent Jaeger 9681da177e4SLinus Torvalds static void copy_templates(struct xfrm_policy *xp, struct xfrm_user_tmpl *ut, 9691da177e4SLinus Torvalds int nr) 9701da177e4SLinus Torvalds { 9711da177e4SLinus Torvalds int i; 9721da177e4SLinus Torvalds 9731da177e4SLinus Torvalds xp->xfrm_nr = nr; 9741da177e4SLinus Torvalds for (i = 0; i < nr; i++, ut++) { 9751da177e4SLinus Torvalds struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 9761da177e4SLinus Torvalds 9771da177e4SLinus Torvalds memcpy(&t->id, &ut->id, sizeof(struct xfrm_id)); 9781da177e4SLinus Torvalds memcpy(&t->saddr, &ut->saddr, 9791da177e4SLinus Torvalds sizeof(xfrm_address_t)); 9801da177e4SLinus Torvalds t->reqid = ut->reqid; 9811da177e4SLinus Torvalds t->mode = ut->mode; 9821da177e4SLinus Torvalds t->share = ut->share; 9831da177e4SLinus Torvalds t->optional = ut->optional; 9841da177e4SLinus Torvalds t->aalgos = ut->aalgos; 9851da177e4SLinus Torvalds t->ealgos = ut->ealgos; 9861da177e4SLinus Torvalds t->calgos = ut->calgos; 9878511d01dSMiika Komu t->encap_family = ut->family; 9881da177e4SLinus Torvalds } 9891da177e4SLinus Torvalds } 9901da177e4SLinus Torvalds 991b4ad86bfSDavid S. Miller static int validate_tmpl(int nr, struct xfrm_user_tmpl *ut, u16 family) 992b4ad86bfSDavid S. Miller { 993b4ad86bfSDavid S. Miller int i; 994b4ad86bfSDavid S. Miller 995b4ad86bfSDavid S. Miller if (nr > XFRM_MAX_DEPTH) 996b4ad86bfSDavid S. Miller return -EINVAL; 997b4ad86bfSDavid S. Miller 998b4ad86bfSDavid S. Miller for (i = 0; i < nr; i++) { 999b4ad86bfSDavid S. Miller /* We never validated the ut->family value, so many 1000b4ad86bfSDavid S. Miller * applications simply leave it at zero. The check was 1001b4ad86bfSDavid S. Miller * never made and ut->family was ignored because all 1002b4ad86bfSDavid S. Miller * templates could be assumed to have the same family as 1003b4ad86bfSDavid S. Miller * the policy itself. Now that we will have ipv4-in-ipv6 1004b4ad86bfSDavid S. Miller * and ipv6-in-ipv4 tunnels, this is no longer true. 1005b4ad86bfSDavid S. Miller */ 1006b4ad86bfSDavid S. Miller if (!ut[i].family) 1007b4ad86bfSDavid S. Miller ut[i].family = family; 1008b4ad86bfSDavid S. Miller 1009b4ad86bfSDavid S. Miller switch (ut[i].family) { 1010b4ad86bfSDavid S. Miller case AF_INET: 1011b4ad86bfSDavid S. Miller break; 1012b4ad86bfSDavid S. Miller #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 1013b4ad86bfSDavid S. Miller case AF_INET6: 1014b4ad86bfSDavid S. Miller break; 1015b4ad86bfSDavid S. Miller #endif 1016b4ad86bfSDavid S. Miller default: 1017b4ad86bfSDavid S. Miller return -EINVAL; 10183ff50b79SStephen Hemminger } 1019b4ad86bfSDavid S. Miller } 1020b4ad86bfSDavid S. Miller 1021b4ad86bfSDavid S. Miller return 0; 1022b4ad86bfSDavid S. Miller } 1023b4ad86bfSDavid S. Miller 10245424f32eSThomas Graf static int copy_from_user_tmpl(struct xfrm_policy *pol, struct nlattr **attrs) 10251da177e4SLinus Torvalds { 10265424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_TMPL]; 10271da177e4SLinus Torvalds 10281da177e4SLinus Torvalds if (!rt) { 10291da177e4SLinus Torvalds pol->xfrm_nr = 0; 10301da177e4SLinus Torvalds } else { 10315424f32eSThomas Graf struct xfrm_user_tmpl *utmpl = nla_data(rt); 10325424f32eSThomas Graf int nr = nla_len(rt) / sizeof(*utmpl); 1033b4ad86bfSDavid S. Miller int err; 10341da177e4SLinus Torvalds 1035b4ad86bfSDavid S. Miller err = validate_tmpl(nr, utmpl, pol->family); 1036b4ad86bfSDavid S. Miller if (err) 1037b4ad86bfSDavid S. Miller return err; 10381da177e4SLinus Torvalds 10395424f32eSThomas Graf copy_templates(pol, utmpl, nr); 10401da177e4SLinus Torvalds } 10411da177e4SLinus Torvalds return 0; 10421da177e4SLinus Torvalds } 10431da177e4SLinus Torvalds 10445424f32eSThomas Graf static int copy_from_user_policy_type(u8 *tp, struct nlattr **attrs) 1045f7b6983fSMasahide NAKAMURA { 10465424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_POLICY_TYPE]; 1047f7b6983fSMasahide NAKAMURA struct xfrm_userpolicy_type *upt; 1048b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 1049f7b6983fSMasahide NAKAMURA int err; 1050f7b6983fSMasahide NAKAMURA 1051f7b6983fSMasahide NAKAMURA if (rt) { 10525424f32eSThomas Graf upt = nla_data(rt); 1053f7b6983fSMasahide NAKAMURA type = upt->type; 1054f7b6983fSMasahide NAKAMURA } 1055f7b6983fSMasahide NAKAMURA 1056f7b6983fSMasahide NAKAMURA err = verify_policy_type(type); 1057f7b6983fSMasahide NAKAMURA if (err) 1058f7b6983fSMasahide NAKAMURA return err; 1059f7b6983fSMasahide NAKAMURA 1060f7b6983fSMasahide NAKAMURA *tp = type; 1061f7b6983fSMasahide NAKAMURA return 0; 1062f7b6983fSMasahide NAKAMURA } 1063f7b6983fSMasahide NAKAMURA 10641da177e4SLinus Torvalds static void copy_from_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p) 10651da177e4SLinus Torvalds { 10661da177e4SLinus Torvalds xp->priority = p->priority; 10671da177e4SLinus Torvalds xp->index = p->index; 10681da177e4SLinus Torvalds memcpy(&xp->selector, &p->sel, sizeof(xp->selector)); 10691da177e4SLinus Torvalds memcpy(&xp->lft, &p->lft, sizeof(xp->lft)); 10701da177e4SLinus Torvalds xp->action = p->action; 10711da177e4SLinus Torvalds xp->flags = p->flags; 10721da177e4SLinus Torvalds xp->family = p->sel.family; 10731da177e4SLinus Torvalds /* XXX xp->share = p->share; */ 10741da177e4SLinus Torvalds } 10751da177e4SLinus Torvalds 10761da177e4SLinus Torvalds static void copy_to_user_policy(struct xfrm_policy *xp, struct xfrm_userpolicy_info *p, int dir) 10771da177e4SLinus Torvalds { 10781da177e4SLinus Torvalds memcpy(&p->sel, &xp->selector, sizeof(p->sel)); 10791da177e4SLinus Torvalds memcpy(&p->lft, &xp->lft, sizeof(p->lft)); 10801da177e4SLinus Torvalds memcpy(&p->curlft, &xp->curlft, sizeof(p->curlft)); 10811da177e4SLinus Torvalds p->priority = xp->priority; 10821da177e4SLinus Torvalds p->index = xp->index; 10831da177e4SLinus Torvalds p->sel.family = xp->family; 10841da177e4SLinus Torvalds p->dir = dir; 10851da177e4SLinus Torvalds p->action = xp->action; 10861da177e4SLinus Torvalds p->flags = xp->flags; 10871da177e4SLinus Torvalds p->share = XFRM_SHARE_ANY; /* XXX xp->share */ 10881da177e4SLinus Torvalds } 10891da177e4SLinus Torvalds 10905424f32eSThomas Graf static struct xfrm_policy *xfrm_policy_construct(struct xfrm_userpolicy_info *p, struct nlattr **attrs, int *errp) 10911da177e4SLinus Torvalds { 10921da177e4SLinus Torvalds struct xfrm_policy *xp = xfrm_policy_alloc(GFP_KERNEL); 10931da177e4SLinus Torvalds int err; 10941da177e4SLinus Torvalds 10951da177e4SLinus Torvalds if (!xp) { 10961da177e4SLinus Torvalds *errp = -ENOMEM; 10971da177e4SLinus Torvalds return NULL; 10981da177e4SLinus Torvalds } 10991da177e4SLinus Torvalds 11001da177e4SLinus Torvalds copy_from_user_policy(xp, p); 1101df71837dSTrent Jaeger 110235a7aa08SThomas Graf err = copy_from_user_policy_type(&xp->type, attrs); 1103f7b6983fSMasahide NAKAMURA if (err) 1104f7b6983fSMasahide NAKAMURA goto error; 1105f7b6983fSMasahide NAKAMURA 110635a7aa08SThomas Graf if (!(err = copy_from_user_tmpl(xp, attrs))) 110735a7aa08SThomas Graf err = copy_from_user_sec_ctx(xp, attrs); 1108f7b6983fSMasahide NAKAMURA if (err) 1109f7b6983fSMasahide NAKAMURA goto error; 11101da177e4SLinus Torvalds 11111da177e4SLinus Torvalds return xp; 1112f7b6983fSMasahide NAKAMURA error: 1113f7b6983fSMasahide NAKAMURA *errp = err; 1114073a3719SYOSHIFUJI Hideaki xp->dead = 1; 111564c31b3fSWANG Cong xfrm_policy_destroy(xp); 1116f7b6983fSMasahide NAKAMURA return NULL; 11171da177e4SLinus Torvalds } 11181da177e4SLinus Torvalds 111922e70050SChristoph Hellwig static int xfrm_add_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 11205424f32eSThomas Graf struct nlattr **attrs) 11211da177e4SLinus Torvalds { 11227b67c857SThomas Graf struct xfrm_userpolicy_info *p = nlmsg_data(nlh); 11231da177e4SLinus Torvalds struct xfrm_policy *xp; 112426b15dadSJamal Hadi Salim struct km_event c; 11251da177e4SLinus Torvalds int err; 11261da177e4SLinus Torvalds int excl; 11271da177e4SLinus Torvalds 11281da177e4SLinus Torvalds err = verify_newpolicy_info(p); 11291da177e4SLinus Torvalds if (err) 11301da177e4SLinus Torvalds return err; 113135a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 1132df71837dSTrent Jaeger if (err) 1133df71837dSTrent Jaeger return err; 11341da177e4SLinus Torvalds 113535a7aa08SThomas Graf xp = xfrm_policy_construct(p, attrs, &err); 11361da177e4SLinus Torvalds if (!xp) 11371da177e4SLinus Torvalds return err; 11381da177e4SLinus Torvalds 113926b15dadSJamal Hadi Salim /* shouldnt excl be based on nlh flags?? 114026b15dadSJamal Hadi Salim * Aha! this is anti-netlink really i.e more pfkey derived 114126b15dadSJamal Hadi Salim * in netlink excl is a flag and you wouldnt need 114226b15dadSJamal Hadi Salim * a type XFRM_MSG_UPDPOLICY - JHS */ 11431da177e4SLinus Torvalds excl = nlh->nlmsg_type == XFRM_MSG_NEWPOLICY; 11441da177e4SLinus Torvalds err = xfrm_policy_insert(p->dir, xp, excl); 1145ab5f5e8bSJoy Latten xfrm_audit_policy_add(xp, err ? 0 : 1, NETLINK_CB(skb).loginuid, 1146ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 1147161a09e7SJoy Latten 11481da177e4SLinus Torvalds if (err) { 11495f8ac64bSTrent Jaeger security_xfrm_policy_free(xp); 11501da177e4SLinus Torvalds kfree(xp); 11511da177e4SLinus Torvalds return err; 11521da177e4SLinus Torvalds } 11531da177e4SLinus Torvalds 1154f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 115526b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 115626b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 115726b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 115826b15dadSJamal Hadi Salim 11591da177e4SLinus Torvalds xfrm_pol_put(xp); 11601da177e4SLinus Torvalds 11611da177e4SLinus Torvalds return 0; 11621da177e4SLinus Torvalds } 11631da177e4SLinus Torvalds 11641da177e4SLinus Torvalds static int copy_to_user_tmpl(struct xfrm_policy *xp, struct sk_buff *skb) 11651da177e4SLinus Torvalds { 11661da177e4SLinus Torvalds struct xfrm_user_tmpl vec[XFRM_MAX_DEPTH]; 11671da177e4SLinus Torvalds int i; 11681da177e4SLinus Torvalds 11691da177e4SLinus Torvalds if (xp->xfrm_nr == 0) 11701da177e4SLinus Torvalds return 0; 11711da177e4SLinus Torvalds 11721da177e4SLinus Torvalds for (i = 0; i < xp->xfrm_nr; i++) { 11731da177e4SLinus Torvalds struct xfrm_user_tmpl *up = &vec[i]; 11741da177e4SLinus Torvalds struct xfrm_tmpl *kp = &xp->xfrm_vec[i]; 11751da177e4SLinus Torvalds 11761da177e4SLinus Torvalds memcpy(&up->id, &kp->id, sizeof(up->id)); 11778511d01dSMiika Komu up->family = kp->encap_family; 11781da177e4SLinus Torvalds memcpy(&up->saddr, &kp->saddr, sizeof(up->saddr)); 11791da177e4SLinus Torvalds up->reqid = kp->reqid; 11801da177e4SLinus Torvalds up->mode = kp->mode; 11811da177e4SLinus Torvalds up->share = kp->share; 11821da177e4SLinus Torvalds up->optional = kp->optional; 11831da177e4SLinus Torvalds up->aalgos = kp->aalgos; 11841da177e4SLinus Torvalds up->ealgos = kp->ealgos; 11851da177e4SLinus Torvalds up->calgos = kp->calgos; 11861da177e4SLinus Torvalds } 11871da177e4SLinus Torvalds 1188c0144beaSThomas Graf return nla_put(skb, XFRMA_TMPL, 1189c0144beaSThomas Graf sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr, vec); 1190df71837dSTrent Jaeger } 1191df71837dSTrent Jaeger 11920d681623SSerge Hallyn static inline int copy_to_user_state_sec_ctx(struct xfrm_state *x, struct sk_buff *skb) 11930d681623SSerge Hallyn { 11940d681623SSerge Hallyn if (x->security) { 11950d681623SSerge Hallyn return copy_sec_ctx(x->security, skb); 11960d681623SSerge Hallyn } 11970d681623SSerge Hallyn return 0; 11980d681623SSerge Hallyn } 11990d681623SSerge Hallyn 12000d681623SSerge Hallyn static inline int copy_to_user_sec_ctx(struct xfrm_policy *xp, struct sk_buff *skb) 12010d681623SSerge Hallyn { 12020d681623SSerge Hallyn if (xp->security) { 12030d681623SSerge Hallyn return copy_sec_ctx(xp->security, skb); 12040d681623SSerge Hallyn } 12050d681623SSerge Hallyn return 0; 12060d681623SSerge Hallyn } 1207cfbfd45aSThomas Graf static inline size_t userpolicy_type_attrsize(void) 1208cfbfd45aSThomas Graf { 1209cfbfd45aSThomas Graf #ifdef CONFIG_XFRM_SUB_POLICY 1210cfbfd45aSThomas Graf return nla_total_size(sizeof(struct xfrm_userpolicy_type)); 1211cfbfd45aSThomas Graf #else 1212cfbfd45aSThomas Graf return 0; 1213cfbfd45aSThomas Graf #endif 1214cfbfd45aSThomas Graf } 12150d681623SSerge Hallyn 1216f7b6983fSMasahide NAKAMURA #ifdef CONFIG_XFRM_SUB_POLICY 1217b798a9edSJamal Hadi Salim static int copy_to_user_policy_type(u8 type, struct sk_buff *skb) 1218f7b6983fSMasahide NAKAMURA { 1219c0144beaSThomas Graf struct xfrm_userpolicy_type upt = { 1220c0144beaSThomas Graf .type = type, 1221c0144beaSThomas Graf }; 1222f7b6983fSMasahide NAKAMURA 1223c0144beaSThomas Graf return nla_put(skb, XFRMA_POLICY_TYPE, sizeof(upt), &upt); 1224f7b6983fSMasahide NAKAMURA } 1225f7b6983fSMasahide NAKAMURA 1226f7b6983fSMasahide NAKAMURA #else 1227b798a9edSJamal Hadi Salim static inline int copy_to_user_policy_type(u8 type, struct sk_buff *skb) 1228f7b6983fSMasahide NAKAMURA { 1229f7b6983fSMasahide NAKAMURA return 0; 1230f7b6983fSMasahide NAKAMURA } 1231f7b6983fSMasahide NAKAMURA #endif 1232f7b6983fSMasahide NAKAMURA 12331da177e4SLinus Torvalds static int dump_one_policy(struct xfrm_policy *xp, int dir, int count, void *ptr) 12341da177e4SLinus Torvalds { 12351da177e4SLinus Torvalds struct xfrm_dump_info *sp = ptr; 12361da177e4SLinus Torvalds struct xfrm_userpolicy_info *p; 12371da177e4SLinus Torvalds struct sk_buff *in_skb = sp->in_skb; 12381da177e4SLinus Torvalds struct sk_buff *skb = sp->out_skb; 12391da177e4SLinus Torvalds struct nlmsghdr *nlh; 12401da177e4SLinus Torvalds 124179b8b7f4SThomas Graf nlh = nlmsg_put(skb, NETLINK_CB(in_skb).pid, sp->nlmsg_seq, 124279b8b7f4SThomas Graf XFRM_MSG_NEWPOLICY, sizeof(*p), sp->nlmsg_flags); 124379b8b7f4SThomas Graf if (nlh == NULL) 124479b8b7f4SThomas Graf return -EMSGSIZE; 12451da177e4SLinus Torvalds 12467b67c857SThomas Graf p = nlmsg_data(nlh); 12471da177e4SLinus Torvalds copy_to_user_policy(xp, p, dir); 12481da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 12491da177e4SLinus Torvalds goto nlmsg_failure; 1250df71837dSTrent Jaeger if (copy_to_user_sec_ctx(xp, skb)) 1251df71837dSTrent Jaeger goto nlmsg_failure; 12521459bb36SJamal Hadi Salim if (copy_to_user_policy_type(xp->type, skb) < 0) 1253f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 12541da177e4SLinus Torvalds 12559825069dSThomas Graf nlmsg_end(skb, nlh); 12561da177e4SLinus Torvalds return 0; 12571da177e4SLinus Torvalds 12581da177e4SLinus Torvalds nlmsg_failure: 12599825069dSThomas Graf nlmsg_cancel(skb, nlh); 12609825069dSThomas Graf return -EMSGSIZE; 12611da177e4SLinus Torvalds } 12621da177e4SLinus Torvalds 1263*4c563f76STimo Teras static int xfrm_dump_policy_done(struct netlink_callback *cb) 1264*4c563f76STimo Teras { 1265*4c563f76STimo Teras struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; 1266*4c563f76STimo Teras 1267*4c563f76STimo Teras xfrm_policy_walk_done(walk); 1268*4c563f76STimo Teras return 0; 1269*4c563f76STimo Teras } 1270*4c563f76STimo Teras 12711da177e4SLinus Torvalds static int xfrm_dump_policy(struct sk_buff *skb, struct netlink_callback *cb) 12721da177e4SLinus Torvalds { 1273*4c563f76STimo Teras struct xfrm_policy_walk *walk = (struct xfrm_policy_walk *) &cb->args[1]; 12741da177e4SLinus Torvalds struct xfrm_dump_info info; 12751da177e4SLinus Torvalds 1276*4c563f76STimo Teras BUILD_BUG_ON(sizeof(struct xfrm_policy_walk) > 1277*4c563f76STimo Teras sizeof(cb->args) - sizeof(cb->args[0])); 1278*4c563f76STimo Teras 12791da177e4SLinus Torvalds info.in_skb = cb->skb; 12801da177e4SLinus Torvalds info.out_skb = skb; 12811da177e4SLinus Torvalds info.nlmsg_seq = cb->nlh->nlmsg_seq; 12821da177e4SLinus Torvalds info.nlmsg_flags = NLM_F_MULTI; 1283*4c563f76STimo Teras 1284*4c563f76STimo Teras if (!cb->args[0]) { 1285*4c563f76STimo Teras cb->args[0] = 1; 1286*4c563f76STimo Teras xfrm_policy_walk_init(walk, XFRM_POLICY_TYPE_ANY); 1287*4c563f76STimo Teras } 1288*4c563f76STimo Teras 1289*4c563f76STimo Teras (void) xfrm_policy_walk(walk, dump_one_policy, &info); 12901da177e4SLinus Torvalds 12911da177e4SLinus Torvalds return skb->len; 12921da177e4SLinus Torvalds } 12931da177e4SLinus Torvalds 12941da177e4SLinus Torvalds static struct sk_buff *xfrm_policy_netlink(struct sk_buff *in_skb, 12951da177e4SLinus Torvalds struct xfrm_policy *xp, 12961da177e4SLinus Torvalds int dir, u32 seq) 12971da177e4SLinus Torvalds { 12981da177e4SLinus Torvalds struct xfrm_dump_info info; 12991da177e4SLinus Torvalds struct sk_buff *skb; 13001da177e4SLinus Torvalds 13017deb2264SThomas Graf skb = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL); 13021da177e4SLinus Torvalds if (!skb) 13031da177e4SLinus Torvalds return ERR_PTR(-ENOMEM); 13041da177e4SLinus Torvalds 13051da177e4SLinus Torvalds info.in_skb = in_skb; 13061da177e4SLinus Torvalds info.out_skb = skb; 13071da177e4SLinus Torvalds info.nlmsg_seq = seq; 13081da177e4SLinus Torvalds info.nlmsg_flags = 0; 13091da177e4SLinus Torvalds 13101da177e4SLinus Torvalds if (dump_one_policy(xp, dir, 0, &info) < 0) { 13111da177e4SLinus Torvalds kfree_skb(skb); 13121da177e4SLinus Torvalds return NULL; 13131da177e4SLinus Torvalds } 13141da177e4SLinus Torvalds 13151da177e4SLinus Torvalds return skb; 13161da177e4SLinus Torvalds } 13171da177e4SLinus Torvalds 131822e70050SChristoph Hellwig static int xfrm_get_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 13195424f32eSThomas Graf struct nlattr **attrs) 13201da177e4SLinus Torvalds { 13211da177e4SLinus Torvalds struct xfrm_policy *xp; 13221da177e4SLinus Torvalds struct xfrm_userpolicy_id *p; 1323b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 13241da177e4SLinus Torvalds int err; 132526b15dadSJamal Hadi Salim struct km_event c; 13261da177e4SLinus Torvalds int delete; 13271da177e4SLinus Torvalds 13287b67c857SThomas Graf p = nlmsg_data(nlh); 13291da177e4SLinus Torvalds delete = nlh->nlmsg_type == XFRM_MSG_DELPOLICY; 13301da177e4SLinus Torvalds 133135a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 1332f7b6983fSMasahide NAKAMURA if (err) 1333f7b6983fSMasahide NAKAMURA return err; 1334f7b6983fSMasahide NAKAMURA 13351da177e4SLinus Torvalds err = verify_policy_dir(p->dir); 13361da177e4SLinus Torvalds if (err) 13371da177e4SLinus Torvalds return err; 13381da177e4SLinus Torvalds 13391da177e4SLinus Torvalds if (p->index) 1340ef41aaa0SEric Paris xp = xfrm_policy_byid(type, p->dir, p->index, delete, &err); 1341df71837dSTrent Jaeger else { 13425424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 1343df71837dSTrent Jaeger struct xfrm_policy tmp; 1344df71837dSTrent Jaeger 134535a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 1346df71837dSTrent Jaeger if (err) 1347df71837dSTrent Jaeger return err; 1348df71837dSTrent Jaeger 1349df71837dSTrent Jaeger memset(&tmp, 0, sizeof(struct xfrm_policy)); 1350df71837dSTrent Jaeger if (rt) { 13515424f32eSThomas Graf struct xfrm_user_sec_ctx *uctx = nla_data(rt); 1352df71837dSTrent Jaeger 1353df71837dSTrent Jaeger if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 1354df71837dSTrent Jaeger return err; 1355df71837dSTrent Jaeger } 1356ef41aaa0SEric Paris xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 1357ef41aaa0SEric Paris delete, &err); 1358df71837dSTrent Jaeger security_xfrm_policy_free(&tmp); 1359df71837dSTrent Jaeger } 13601da177e4SLinus Torvalds if (xp == NULL) 13611da177e4SLinus Torvalds return -ENOENT; 13621da177e4SLinus Torvalds 13631da177e4SLinus Torvalds if (!delete) { 13641da177e4SLinus Torvalds struct sk_buff *resp_skb; 13651da177e4SLinus Torvalds 13661da177e4SLinus Torvalds resp_skb = xfrm_policy_netlink(skb, xp, p->dir, nlh->nlmsg_seq); 13671da177e4SLinus Torvalds if (IS_ERR(resp_skb)) { 13681da177e4SLinus Torvalds err = PTR_ERR(resp_skb); 13691da177e4SLinus Torvalds } else { 1370082a1ad5SThomas Graf err = nlmsg_unicast(xfrm_nl, resp_skb, 1371082a1ad5SThomas Graf NETLINK_CB(skb).pid); 13721da177e4SLinus Torvalds } 137326b15dadSJamal Hadi Salim } else { 1374ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, err ? 0 : 1, 1375ab5f5e8bSJoy Latten NETLINK_CB(skb).loginuid, 1376ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 137713fcfbb0SDavid S. Miller 137813fcfbb0SDavid S. Miller if (err != 0) 1379c8c05a8eSCatherine Zhang goto out; 138013fcfbb0SDavid S. Miller 1381e7443892SHerbert Xu c.data.byid = p->index; 1382f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 138326b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 138426b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 138526b15dadSJamal Hadi Salim km_policy_notify(xp, p->dir, &c); 13861da177e4SLinus Torvalds } 13871da177e4SLinus Torvalds 1388c8c05a8eSCatherine Zhang out: 1389ef41aaa0SEric Paris xfrm_pol_put(xp); 13901da177e4SLinus Torvalds return err; 13911da177e4SLinus Torvalds } 13921da177e4SLinus Torvalds 139322e70050SChristoph Hellwig static int xfrm_flush_sa(struct sk_buff *skb, struct nlmsghdr *nlh, 13945424f32eSThomas Graf struct nlattr **attrs) 13951da177e4SLinus Torvalds { 139626b15dadSJamal Hadi Salim struct km_event c; 13977b67c857SThomas Graf struct xfrm_usersa_flush *p = nlmsg_data(nlh); 1398161a09e7SJoy Latten struct xfrm_audit audit_info; 13994aa2e62cSJoy Latten int err; 14001da177e4SLinus Torvalds 1401161a09e7SJoy Latten audit_info.loginuid = NETLINK_CB(skb).loginuid; 1402161a09e7SJoy Latten audit_info.secid = NETLINK_CB(skb).sid; 14034aa2e62cSJoy Latten err = xfrm_state_flush(p->proto, &audit_info); 14044aa2e62cSJoy Latten if (err) 14054aa2e62cSJoy Latten return err; 1406bf08867fSHerbert Xu c.data.proto = p->proto; 1407f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 140826b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 140926b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 141026b15dadSJamal Hadi Salim km_state_notify(NULL, &c); 141126b15dadSJamal Hadi Salim 14121da177e4SLinus Torvalds return 0; 14131da177e4SLinus Torvalds } 14141da177e4SLinus Torvalds 14157deb2264SThomas Graf static inline size_t xfrm_aevent_msgsize(void) 14167deb2264SThomas Graf { 14177deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_aevent_id)) 14187deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_replay_state)) 14197deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_lifetime_cur)) 14207deb2264SThomas Graf + nla_total_size(4) /* XFRM_AE_RTHR */ 14217deb2264SThomas Graf + nla_total_size(4); /* XFRM_AE_ETHR */ 14227deb2264SThomas Graf } 1423d51d081dSJamal Hadi Salim 1424d51d081dSJamal Hadi Salim static int build_aevent(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) 1425d51d081dSJamal Hadi Salim { 1426d51d081dSJamal Hadi Salim struct xfrm_aevent_id *id; 1427d51d081dSJamal Hadi Salim struct nlmsghdr *nlh; 1428d51d081dSJamal Hadi Salim 142979b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_NEWAE, sizeof(*id), 0); 143079b8b7f4SThomas Graf if (nlh == NULL) 143179b8b7f4SThomas Graf return -EMSGSIZE; 1432d51d081dSJamal Hadi Salim 14337b67c857SThomas Graf id = nlmsg_data(nlh); 14342b5f6dccSJamal Hadi Salim memcpy(&id->sa_id.daddr, &x->id.daddr,sizeof(x->id.daddr)); 1435d51d081dSJamal Hadi Salim id->sa_id.spi = x->id.spi; 1436d51d081dSJamal Hadi Salim id->sa_id.family = x->props.family; 1437d51d081dSJamal Hadi Salim id->sa_id.proto = x->id.proto; 14382b5f6dccSJamal Hadi Salim memcpy(&id->saddr, &x->props.saddr,sizeof(x->props.saddr)); 14392b5f6dccSJamal Hadi Salim id->reqid = x->props.reqid; 1440d51d081dSJamal Hadi Salim id->flags = c->data.aevent; 1441d51d081dSJamal Hadi Salim 1442c0144beaSThomas Graf NLA_PUT(skb, XFRMA_REPLAY_VAL, sizeof(x->replay), &x->replay); 1443c0144beaSThomas Graf NLA_PUT(skb, XFRMA_LTIME_VAL, sizeof(x->curlft), &x->curlft); 1444d51d081dSJamal Hadi Salim 1445c0144beaSThomas Graf if (id->flags & XFRM_AE_RTHR) 1446c0144beaSThomas Graf NLA_PUT_U32(skb, XFRMA_REPLAY_THRESH, x->replay_maxdiff); 1447d51d081dSJamal Hadi Salim 1448c0144beaSThomas Graf if (id->flags & XFRM_AE_ETHR) 1449c0144beaSThomas Graf NLA_PUT_U32(skb, XFRMA_ETIMER_THRESH, 1450c0144beaSThomas Graf x->replay_maxage * 10 / HZ); 1451d51d081dSJamal Hadi Salim 14529825069dSThomas Graf return nlmsg_end(skb, nlh); 1453d51d081dSJamal Hadi Salim 1454c0144beaSThomas Graf nla_put_failure: 14559825069dSThomas Graf nlmsg_cancel(skb, nlh); 14569825069dSThomas Graf return -EMSGSIZE; 1457d51d081dSJamal Hadi Salim } 1458d51d081dSJamal Hadi Salim 145922e70050SChristoph Hellwig static int xfrm_get_ae(struct sk_buff *skb, struct nlmsghdr *nlh, 14605424f32eSThomas Graf struct nlattr **attrs) 1461d51d081dSJamal Hadi Salim { 1462d51d081dSJamal Hadi Salim struct xfrm_state *x; 1463d51d081dSJamal Hadi Salim struct sk_buff *r_skb; 1464d51d081dSJamal Hadi Salim int err; 1465d51d081dSJamal Hadi Salim struct km_event c; 14667b67c857SThomas Graf struct xfrm_aevent_id *p = nlmsg_data(nlh); 1467d51d081dSJamal Hadi Salim struct xfrm_usersa_id *id = &p->sa_id; 1468d51d081dSJamal Hadi Salim 14697deb2264SThomas Graf r_skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); 1470d51d081dSJamal Hadi Salim if (r_skb == NULL) 1471d51d081dSJamal Hadi Salim return -ENOMEM; 1472d51d081dSJamal Hadi Salim 1473d51d081dSJamal Hadi Salim x = xfrm_state_lookup(&id->daddr, id->spi, id->proto, id->family); 1474d51d081dSJamal Hadi Salim if (x == NULL) { 1475b08d5840SPatrick McHardy kfree_skb(r_skb); 1476d51d081dSJamal Hadi Salim return -ESRCH; 1477d51d081dSJamal Hadi Salim } 1478d51d081dSJamal Hadi Salim 1479d51d081dSJamal Hadi Salim /* 1480d51d081dSJamal Hadi Salim * XXX: is this lock really needed - none of the other 1481d51d081dSJamal Hadi Salim * gets lock (the concern is things getting updated 1482d51d081dSJamal Hadi Salim * while we are still reading) - jhs 1483d51d081dSJamal Hadi Salim */ 1484d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 1485d51d081dSJamal Hadi Salim c.data.aevent = p->flags; 1486d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 1487d51d081dSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 1488d51d081dSJamal Hadi Salim 1489d51d081dSJamal Hadi Salim if (build_aevent(r_skb, x, &c) < 0) 1490d51d081dSJamal Hadi Salim BUG(); 1491082a1ad5SThomas Graf err = nlmsg_unicast(xfrm_nl, r_skb, NETLINK_CB(skb).pid); 1492d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1493d51d081dSJamal Hadi Salim xfrm_state_put(x); 1494d51d081dSJamal Hadi Salim return err; 1495d51d081dSJamal Hadi Salim } 1496d51d081dSJamal Hadi Salim 149722e70050SChristoph Hellwig static int xfrm_new_ae(struct sk_buff *skb, struct nlmsghdr *nlh, 14985424f32eSThomas Graf struct nlattr **attrs) 1499d51d081dSJamal Hadi Salim { 1500d51d081dSJamal Hadi Salim struct xfrm_state *x; 1501d51d081dSJamal Hadi Salim struct km_event c; 1502d51d081dSJamal Hadi Salim int err = - EINVAL; 15037b67c857SThomas Graf struct xfrm_aevent_id *p = nlmsg_data(nlh); 15045424f32eSThomas Graf struct nlattr *rp = attrs[XFRMA_REPLAY_VAL]; 15055424f32eSThomas Graf struct nlattr *lt = attrs[XFRMA_LTIME_VAL]; 1506d51d081dSJamal Hadi Salim 1507d51d081dSJamal Hadi Salim if (!lt && !rp) 1508d51d081dSJamal Hadi Salim return err; 1509d51d081dSJamal Hadi Salim 1510d51d081dSJamal Hadi Salim /* pedantic mode - thou shalt sayeth replaceth */ 1511d51d081dSJamal Hadi Salim if (!(nlh->nlmsg_flags&NLM_F_REPLACE)) 1512d51d081dSJamal Hadi Salim return err; 1513d51d081dSJamal Hadi Salim 1514d51d081dSJamal Hadi Salim x = xfrm_state_lookup(&p->sa_id.daddr, p->sa_id.spi, p->sa_id.proto, p->sa_id.family); 1515d51d081dSJamal Hadi Salim if (x == NULL) 1516d51d081dSJamal Hadi Salim return -ESRCH; 1517d51d081dSJamal Hadi Salim 1518d51d081dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 1519d51d081dSJamal Hadi Salim goto out; 1520d51d081dSJamal Hadi Salim 1521d51d081dSJamal Hadi Salim spin_lock_bh(&x->lock); 152235a7aa08SThomas Graf xfrm_update_ae_params(x, attrs); 1523d51d081dSJamal Hadi Salim spin_unlock_bh(&x->lock); 1524d51d081dSJamal Hadi Salim 1525d51d081dSJamal Hadi Salim c.event = nlh->nlmsg_type; 1526d51d081dSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 1527d51d081dSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 1528d51d081dSJamal Hadi Salim c.data.aevent = XFRM_AE_CU; 1529d51d081dSJamal Hadi Salim km_state_notify(x, &c); 1530d51d081dSJamal Hadi Salim err = 0; 1531d51d081dSJamal Hadi Salim out: 1532d51d081dSJamal Hadi Salim xfrm_state_put(x); 1533d51d081dSJamal Hadi Salim return err; 1534d51d081dSJamal Hadi Salim } 1535d51d081dSJamal Hadi Salim 153622e70050SChristoph Hellwig static int xfrm_flush_policy(struct sk_buff *skb, struct nlmsghdr *nlh, 15375424f32eSThomas Graf struct nlattr **attrs) 15381da177e4SLinus Torvalds { 153926b15dadSJamal Hadi Salim struct km_event c; 1540b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 1541f7b6983fSMasahide NAKAMURA int err; 1542161a09e7SJoy Latten struct xfrm_audit audit_info; 154326b15dadSJamal Hadi Salim 154435a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 1545f7b6983fSMasahide NAKAMURA if (err) 1546f7b6983fSMasahide NAKAMURA return err; 1547f7b6983fSMasahide NAKAMURA 1548161a09e7SJoy Latten audit_info.loginuid = NETLINK_CB(skb).loginuid; 1549161a09e7SJoy Latten audit_info.secid = NETLINK_CB(skb).sid; 15504aa2e62cSJoy Latten err = xfrm_policy_flush(type, &audit_info); 15514aa2e62cSJoy Latten if (err) 15524aa2e62cSJoy Latten return err; 1553f7b6983fSMasahide NAKAMURA c.data.type = type; 1554f60f6b8fSHerbert Xu c.event = nlh->nlmsg_type; 155526b15dadSJamal Hadi Salim c.seq = nlh->nlmsg_seq; 155626b15dadSJamal Hadi Salim c.pid = nlh->nlmsg_pid; 155726b15dadSJamal Hadi Salim km_policy_notify(NULL, 0, &c); 15581da177e4SLinus Torvalds return 0; 15591da177e4SLinus Torvalds } 15601da177e4SLinus Torvalds 156122e70050SChristoph Hellwig static int xfrm_add_pol_expire(struct sk_buff *skb, struct nlmsghdr *nlh, 15625424f32eSThomas Graf struct nlattr **attrs) 15636c5c8ca7SJamal Hadi Salim { 15646c5c8ca7SJamal Hadi Salim struct xfrm_policy *xp; 15657b67c857SThomas Graf struct xfrm_user_polexpire *up = nlmsg_data(nlh); 15666c5c8ca7SJamal Hadi Salim struct xfrm_userpolicy_info *p = &up->pol; 1567b798a9edSJamal Hadi Salim u8 type = XFRM_POLICY_TYPE_MAIN; 15686c5c8ca7SJamal Hadi Salim int err = -ENOENT; 15696c5c8ca7SJamal Hadi Salim 157035a7aa08SThomas Graf err = copy_from_user_policy_type(&type, attrs); 1571f7b6983fSMasahide NAKAMURA if (err) 1572f7b6983fSMasahide NAKAMURA return err; 1573f7b6983fSMasahide NAKAMURA 15746c5c8ca7SJamal Hadi Salim if (p->index) 1575ef41aaa0SEric Paris xp = xfrm_policy_byid(type, p->dir, p->index, 0, &err); 15766c5c8ca7SJamal Hadi Salim else { 15775424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_SEC_CTX]; 15786c5c8ca7SJamal Hadi Salim struct xfrm_policy tmp; 15796c5c8ca7SJamal Hadi Salim 158035a7aa08SThomas Graf err = verify_sec_ctx_len(attrs); 15816c5c8ca7SJamal Hadi Salim if (err) 15826c5c8ca7SJamal Hadi Salim return err; 15836c5c8ca7SJamal Hadi Salim 15846c5c8ca7SJamal Hadi Salim memset(&tmp, 0, sizeof(struct xfrm_policy)); 15856c5c8ca7SJamal Hadi Salim if (rt) { 15865424f32eSThomas Graf struct xfrm_user_sec_ctx *uctx = nla_data(rt); 15876c5c8ca7SJamal Hadi Salim 15886c5c8ca7SJamal Hadi Salim if ((err = security_xfrm_policy_alloc(&tmp, uctx))) 15896c5c8ca7SJamal Hadi Salim return err; 15906c5c8ca7SJamal Hadi Salim } 1591ef41aaa0SEric Paris xp = xfrm_policy_bysel_ctx(type, p->dir, &p->sel, tmp.security, 1592ef41aaa0SEric Paris 0, &err); 15936c5c8ca7SJamal Hadi Salim security_xfrm_policy_free(&tmp); 15946c5c8ca7SJamal Hadi Salim } 15956c5c8ca7SJamal Hadi Salim 15966c5c8ca7SJamal Hadi Salim if (xp == NULL) 1597ef41aaa0SEric Paris return -ENOENT; 15986c5c8ca7SJamal Hadi Salim read_lock(&xp->lock); 15996c5c8ca7SJamal Hadi Salim if (xp->dead) { 16006c5c8ca7SJamal Hadi Salim read_unlock(&xp->lock); 16016c5c8ca7SJamal Hadi Salim goto out; 16026c5c8ca7SJamal Hadi Salim } 16036c5c8ca7SJamal Hadi Salim 16046c5c8ca7SJamal Hadi Salim read_unlock(&xp->lock); 16056c5c8ca7SJamal Hadi Salim err = 0; 16066c5c8ca7SJamal Hadi Salim if (up->hard) { 16076c5c8ca7SJamal Hadi Salim xfrm_policy_delete(xp, p->dir); 1608ab5f5e8bSJoy Latten xfrm_audit_policy_delete(xp, 1, NETLINK_CB(skb).loginuid, 1609ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 1610161a09e7SJoy Latten 16116c5c8ca7SJamal Hadi Salim } else { 16126c5c8ca7SJamal Hadi Salim // reset the timers here? 16136c5c8ca7SJamal Hadi Salim printk("Dont know what to do with soft policy expire\n"); 16146c5c8ca7SJamal Hadi Salim } 16156c5c8ca7SJamal Hadi Salim km_policy_expired(xp, p->dir, up->hard, current->pid); 16166c5c8ca7SJamal Hadi Salim 16176c5c8ca7SJamal Hadi Salim out: 16186c5c8ca7SJamal Hadi Salim xfrm_pol_put(xp); 16196c5c8ca7SJamal Hadi Salim return err; 16206c5c8ca7SJamal Hadi Salim } 16216c5c8ca7SJamal Hadi Salim 162222e70050SChristoph Hellwig static int xfrm_add_sa_expire(struct sk_buff *skb, struct nlmsghdr *nlh, 16235424f32eSThomas Graf struct nlattr **attrs) 162453bc6b4dSJamal Hadi Salim { 162553bc6b4dSJamal Hadi Salim struct xfrm_state *x; 162653bc6b4dSJamal Hadi Salim int err; 16277b67c857SThomas Graf struct xfrm_user_expire *ue = nlmsg_data(nlh); 162853bc6b4dSJamal Hadi Salim struct xfrm_usersa_info *p = &ue->state; 162953bc6b4dSJamal Hadi Salim 163053bc6b4dSJamal Hadi Salim x = xfrm_state_lookup(&p->id.daddr, p->id.spi, p->id.proto, p->family); 163153bc6b4dSJamal Hadi Salim 16323a765aa5SDavid S. Miller err = -ENOENT; 163353bc6b4dSJamal Hadi Salim if (x == NULL) 163453bc6b4dSJamal Hadi Salim return err; 163553bc6b4dSJamal Hadi Salim 163653bc6b4dSJamal Hadi Salim spin_lock_bh(&x->lock); 16373a765aa5SDavid S. Miller err = -EINVAL; 163853bc6b4dSJamal Hadi Salim if (x->km.state != XFRM_STATE_VALID) 163953bc6b4dSJamal Hadi Salim goto out; 164053bc6b4dSJamal Hadi Salim km_state_expired(x, ue->hard, current->pid); 164153bc6b4dSJamal Hadi Salim 1642161a09e7SJoy Latten if (ue->hard) { 164353bc6b4dSJamal Hadi Salim __xfrm_state_delete(x); 1644ab5f5e8bSJoy Latten xfrm_audit_state_delete(x, 1, NETLINK_CB(skb).loginuid, 1645ab5f5e8bSJoy Latten NETLINK_CB(skb).sid); 1646161a09e7SJoy Latten } 16473a765aa5SDavid S. Miller err = 0; 164853bc6b4dSJamal Hadi Salim out: 164953bc6b4dSJamal Hadi Salim spin_unlock_bh(&x->lock); 165053bc6b4dSJamal Hadi Salim xfrm_state_put(x); 165153bc6b4dSJamal Hadi Salim return err; 165253bc6b4dSJamal Hadi Salim } 165353bc6b4dSJamal Hadi Salim 165422e70050SChristoph Hellwig static int xfrm_add_acquire(struct sk_buff *skb, struct nlmsghdr *nlh, 16555424f32eSThomas Graf struct nlattr **attrs) 1656980ebd25SJamal Hadi Salim { 1657980ebd25SJamal Hadi Salim struct xfrm_policy *xp; 1658980ebd25SJamal Hadi Salim struct xfrm_user_tmpl *ut; 1659980ebd25SJamal Hadi Salim int i; 16605424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_TMPL]; 1661980ebd25SJamal Hadi Salim 16627b67c857SThomas Graf struct xfrm_user_acquire *ua = nlmsg_data(nlh); 1663980ebd25SJamal Hadi Salim struct xfrm_state *x = xfrm_state_alloc(); 1664980ebd25SJamal Hadi Salim int err = -ENOMEM; 1665980ebd25SJamal Hadi Salim 1666980ebd25SJamal Hadi Salim if (!x) 1667980ebd25SJamal Hadi Salim return err; 1668980ebd25SJamal Hadi Salim 1669980ebd25SJamal Hadi Salim err = verify_newpolicy_info(&ua->policy); 1670980ebd25SJamal Hadi Salim if (err) { 1671980ebd25SJamal Hadi Salim printk("BAD policy passed\n"); 1672980ebd25SJamal Hadi Salim kfree(x); 1673980ebd25SJamal Hadi Salim return err; 1674980ebd25SJamal Hadi Salim } 1675980ebd25SJamal Hadi Salim 1676980ebd25SJamal Hadi Salim /* build an XP */ 16775424f32eSThomas Graf xp = xfrm_policy_construct(&ua->policy, attrs, &err); 1678b4ad86bfSDavid S. Miller if (!xp) { 1679980ebd25SJamal Hadi Salim kfree(x); 1680980ebd25SJamal Hadi Salim return err; 1681980ebd25SJamal Hadi Salim } 1682980ebd25SJamal Hadi Salim 1683980ebd25SJamal Hadi Salim memcpy(&x->id, &ua->id, sizeof(ua->id)); 1684980ebd25SJamal Hadi Salim memcpy(&x->props.saddr, &ua->saddr, sizeof(ua->saddr)); 1685980ebd25SJamal Hadi Salim memcpy(&x->sel, &ua->sel, sizeof(ua->sel)); 1686980ebd25SJamal Hadi Salim 16875424f32eSThomas Graf ut = nla_data(rt); 1688980ebd25SJamal Hadi Salim /* extract the templates and for each call km_key */ 1689980ebd25SJamal Hadi Salim for (i = 0; i < xp->xfrm_nr; i++, ut++) { 1690980ebd25SJamal Hadi Salim struct xfrm_tmpl *t = &xp->xfrm_vec[i]; 1691980ebd25SJamal Hadi Salim memcpy(&x->id, &t->id, sizeof(x->id)); 1692980ebd25SJamal Hadi Salim x->props.mode = t->mode; 1693980ebd25SJamal Hadi Salim x->props.reqid = t->reqid; 1694980ebd25SJamal Hadi Salim x->props.family = ut->family; 1695980ebd25SJamal Hadi Salim t->aalgos = ua->aalgos; 1696980ebd25SJamal Hadi Salim t->ealgos = ua->ealgos; 1697980ebd25SJamal Hadi Salim t->calgos = ua->calgos; 1698980ebd25SJamal Hadi Salim err = km_query(x, t, xp); 1699980ebd25SJamal Hadi Salim 1700980ebd25SJamal Hadi Salim } 1701980ebd25SJamal Hadi Salim 1702980ebd25SJamal Hadi Salim kfree(x); 1703980ebd25SJamal Hadi Salim kfree(xp); 1704980ebd25SJamal Hadi Salim 1705980ebd25SJamal Hadi Salim return 0; 1706980ebd25SJamal Hadi Salim } 1707980ebd25SJamal Hadi Salim 17085c79de6eSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 17095c79de6eSShinta Sugimoto static int copy_from_user_migrate(struct xfrm_migrate *ma, 17105424f32eSThomas Graf struct nlattr **attrs, int *num) 17115c79de6eSShinta Sugimoto { 17125424f32eSThomas Graf struct nlattr *rt = attrs[XFRMA_MIGRATE]; 17135c79de6eSShinta Sugimoto struct xfrm_user_migrate *um; 17145c79de6eSShinta Sugimoto int i, num_migrate; 17155c79de6eSShinta Sugimoto 17165424f32eSThomas Graf um = nla_data(rt); 17175424f32eSThomas Graf num_migrate = nla_len(rt) / sizeof(*um); 17185c79de6eSShinta Sugimoto 17195c79de6eSShinta Sugimoto if (num_migrate <= 0 || num_migrate > XFRM_MAX_DEPTH) 17205c79de6eSShinta Sugimoto return -EINVAL; 17215c79de6eSShinta Sugimoto 17225c79de6eSShinta Sugimoto for (i = 0; i < num_migrate; i++, um++, ma++) { 17235c79de6eSShinta Sugimoto memcpy(&ma->old_daddr, &um->old_daddr, sizeof(ma->old_daddr)); 17245c79de6eSShinta Sugimoto memcpy(&ma->old_saddr, &um->old_saddr, sizeof(ma->old_saddr)); 17255c79de6eSShinta Sugimoto memcpy(&ma->new_daddr, &um->new_daddr, sizeof(ma->new_daddr)); 17265c79de6eSShinta Sugimoto memcpy(&ma->new_saddr, &um->new_saddr, sizeof(ma->new_saddr)); 17275c79de6eSShinta Sugimoto 17285c79de6eSShinta Sugimoto ma->proto = um->proto; 17295c79de6eSShinta Sugimoto ma->mode = um->mode; 17305c79de6eSShinta Sugimoto ma->reqid = um->reqid; 17315c79de6eSShinta Sugimoto 17325c79de6eSShinta Sugimoto ma->old_family = um->old_family; 17335c79de6eSShinta Sugimoto ma->new_family = um->new_family; 17345c79de6eSShinta Sugimoto } 17355c79de6eSShinta Sugimoto 17365c79de6eSShinta Sugimoto *num = i; 17375c79de6eSShinta Sugimoto return 0; 17385c79de6eSShinta Sugimoto } 17395c79de6eSShinta Sugimoto 17405c79de6eSShinta Sugimoto static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, 17415424f32eSThomas Graf struct nlattr **attrs) 17425c79de6eSShinta Sugimoto { 17437b67c857SThomas Graf struct xfrm_userpolicy_id *pi = nlmsg_data(nlh); 17445c79de6eSShinta Sugimoto struct xfrm_migrate m[XFRM_MAX_DEPTH]; 17455c79de6eSShinta Sugimoto u8 type; 17465c79de6eSShinta Sugimoto int err; 17475c79de6eSShinta Sugimoto int n = 0; 17485c79de6eSShinta Sugimoto 174935a7aa08SThomas Graf if (attrs[XFRMA_MIGRATE] == NULL) 1750cf5cb79fSThomas Graf return -EINVAL; 17515c79de6eSShinta Sugimoto 17525424f32eSThomas Graf err = copy_from_user_policy_type(&type, attrs); 17535c79de6eSShinta Sugimoto if (err) 17545c79de6eSShinta Sugimoto return err; 17555c79de6eSShinta Sugimoto 17565c79de6eSShinta Sugimoto err = copy_from_user_migrate((struct xfrm_migrate *)m, 17575424f32eSThomas Graf attrs, &n); 17585c79de6eSShinta Sugimoto if (err) 17595c79de6eSShinta Sugimoto return err; 17605c79de6eSShinta Sugimoto 17615c79de6eSShinta Sugimoto if (!n) 17625c79de6eSShinta Sugimoto return 0; 17635c79de6eSShinta Sugimoto 17645c79de6eSShinta Sugimoto xfrm_migrate(&pi->sel, pi->dir, type, m, n); 17655c79de6eSShinta Sugimoto 17665c79de6eSShinta Sugimoto return 0; 17675c79de6eSShinta Sugimoto } 17685c79de6eSShinta Sugimoto #else 17695c79de6eSShinta Sugimoto static int xfrm_do_migrate(struct sk_buff *skb, struct nlmsghdr *nlh, 17705424f32eSThomas Graf struct nlattr **attrs) 17715c79de6eSShinta Sugimoto { 17725c79de6eSShinta Sugimoto return -ENOPROTOOPT; 17735c79de6eSShinta Sugimoto } 17745c79de6eSShinta Sugimoto #endif 17755c79de6eSShinta Sugimoto 17765c79de6eSShinta Sugimoto #ifdef CONFIG_XFRM_MIGRATE 17775c79de6eSShinta Sugimoto static int copy_to_user_migrate(struct xfrm_migrate *m, struct sk_buff *skb) 17785c79de6eSShinta Sugimoto { 17795c79de6eSShinta Sugimoto struct xfrm_user_migrate um; 17805c79de6eSShinta Sugimoto 17815c79de6eSShinta Sugimoto memset(&um, 0, sizeof(um)); 17825c79de6eSShinta Sugimoto um.proto = m->proto; 17835c79de6eSShinta Sugimoto um.mode = m->mode; 17845c79de6eSShinta Sugimoto um.reqid = m->reqid; 17855c79de6eSShinta Sugimoto um.old_family = m->old_family; 17865c79de6eSShinta Sugimoto memcpy(&um.old_daddr, &m->old_daddr, sizeof(um.old_daddr)); 17875c79de6eSShinta Sugimoto memcpy(&um.old_saddr, &m->old_saddr, sizeof(um.old_saddr)); 17885c79de6eSShinta Sugimoto um.new_family = m->new_family; 17895c79de6eSShinta Sugimoto memcpy(&um.new_daddr, &m->new_daddr, sizeof(um.new_daddr)); 17905c79de6eSShinta Sugimoto memcpy(&um.new_saddr, &m->new_saddr, sizeof(um.new_saddr)); 17915c79de6eSShinta Sugimoto 1792c0144beaSThomas Graf return nla_put(skb, XFRMA_MIGRATE, sizeof(um), &um); 17935c79de6eSShinta Sugimoto } 17945c79de6eSShinta Sugimoto 17957deb2264SThomas Graf static inline size_t xfrm_migrate_msgsize(int num_migrate) 17967deb2264SThomas Graf { 17977deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_userpolicy_id)) 17987deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_migrate) * num_migrate) 17997deb2264SThomas Graf + userpolicy_type_attrsize(); 18007deb2264SThomas Graf } 18017deb2264SThomas Graf 18025c79de6eSShinta Sugimoto static int build_migrate(struct sk_buff *skb, struct xfrm_migrate *m, 18035c79de6eSShinta Sugimoto int num_migrate, struct xfrm_selector *sel, 18045c79de6eSShinta Sugimoto u8 dir, u8 type) 18055c79de6eSShinta Sugimoto { 18065c79de6eSShinta Sugimoto struct xfrm_migrate *mp; 18075c79de6eSShinta Sugimoto struct xfrm_userpolicy_id *pol_id; 18085c79de6eSShinta Sugimoto struct nlmsghdr *nlh; 18095c79de6eSShinta Sugimoto int i; 18105c79de6eSShinta Sugimoto 181179b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_MIGRATE, sizeof(*pol_id), 0); 181279b8b7f4SThomas Graf if (nlh == NULL) 181379b8b7f4SThomas Graf return -EMSGSIZE; 18145c79de6eSShinta Sugimoto 18157b67c857SThomas Graf pol_id = nlmsg_data(nlh); 18165c79de6eSShinta Sugimoto /* copy data from selector, dir, and type to the pol_id */ 18175c79de6eSShinta Sugimoto memset(pol_id, 0, sizeof(*pol_id)); 18185c79de6eSShinta Sugimoto memcpy(&pol_id->sel, sel, sizeof(pol_id->sel)); 18195c79de6eSShinta Sugimoto pol_id->dir = dir; 18205c79de6eSShinta Sugimoto 18215c79de6eSShinta Sugimoto if (copy_to_user_policy_type(type, skb) < 0) 18225c79de6eSShinta Sugimoto goto nlmsg_failure; 18235c79de6eSShinta Sugimoto 18245c79de6eSShinta Sugimoto for (i = 0, mp = m ; i < num_migrate; i++, mp++) { 18255c79de6eSShinta Sugimoto if (copy_to_user_migrate(mp, skb) < 0) 18265c79de6eSShinta Sugimoto goto nlmsg_failure; 18275c79de6eSShinta Sugimoto } 18285c79de6eSShinta Sugimoto 18299825069dSThomas Graf return nlmsg_end(skb, nlh); 18305c79de6eSShinta Sugimoto nlmsg_failure: 18319825069dSThomas Graf nlmsg_cancel(skb, nlh); 18329825069dSThomas Graf return -EMSGSIZE; 18335c79de6eSShinta Sugimoto } 18345c79de6eSShinta Sugimoto 18355c79de6eSShinta Sugimoto static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 18365c79de6eSShinta Sugimoto struct xfrm_migrate *m, int num_migrate) 18375c79de6eSShinta Sugimoto { 18385c79de6eSShinta Sugimoto struct sk_buff *skb; 18395c79de6eSShinta Sugimoto 18407deb2264SThomas Graf skb = nlmsg_new(xfrm_migrate_msgsize(num_migrate), GFP_ATOMIC); 18415c79de6eSShinta Sugimoto if (skb == NULL) 18425c79de6eSShinta Sugimoto return -ENOMEM; 18435c79de6eSShinta Sugimoto 18445c79de6eSShinta Sugimoto /* build migrate */ 18455c79de6eSShinta Sugimoto if (build_migrate(skb, m, num_migrate, sel, dir, type) < 0) 18465c79de6eSShinta Sugimoto BUG(); 18475c79de6eSShinta Sugimoto 1848082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_MIGRATE, GFP_ATOMIC); 18495c79de6eSShinta Sugimoto } 18505c79de6eSShinta Sugimoto #else 18515c79de6eSShinta Sugimoto static int xfrm_send_migrate(struct xfrm_selector *sel, u8 dir, u8 type, 18525c79de6eSShinta Sugimoto struct xfrm_migrate *m, int num_migrate) 18535c79de6eSShinta Sugimoto { 18545c79de6eSShinta Sugimoto return -ENOPROTOOPT; 18555c79de6eSShinta Sugimoto } 18565c79de6eSShinta Sugimoto #endif 1857d51d081dSJamal Hadi Salim 1858a7bd9a45SThomas Graf #define XMSGSIZE(type) sizeof(struct type) 1859492b558bSThomas Graf 1860492b558bSThomas Graf static const int xfrm_msg_min[XFRM_NR_MSGTYPES] = { 1861492b558bSThomas Graf [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 1862492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 1863492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 1864492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 1865492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 1866492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 1867492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userspi_info), 1868980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_acquire), 186953bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_expire), 1870492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_info), 1871492b558bSThomas Graf [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_info), 18726c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_polexpire), 1873492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), 1874a7bd9a45SThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0, 1875d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 1876d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 187797a64b45SMasahide NAKAMURA [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 18785c79de6eSShinta Sugimoto [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 1879a7bd9a45SThomas Graf [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), 1880a7bd9a45SThomas Graf [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 18811da177e4SLinus Torvalds }; 18821da177e4SLinus Torvalds 1883492b558bSThomas Graf #undef XMSGSIZE 1884492b558bSThomas Graf 1885cf5cb79fSThomas Graf static const struct nla_policy xfrma_policy[XFRMA_MAX+1] = { 18861a6509d9SHerbert Xu [XFRMA_ALG_AEAD] = { .len = sizeof(struct xfrm_algo_aead) }, 1887cf5cb79fSThomas Graf [XFRMA_ALG_AUTH] = { .len = sizeof(struct xfrm_algo) }, 1888cf5cb79fSThomas Graf [XFRMA_ALG_CRYPT] = { .len = sizeof(struct xfrm_algo) }, 1889cf5cb79fSThomas Graf [XFRMA_ALG_COMP] = { .len = sizeof(struct xfrm_algo) }, 1890cf5cb79fSThomas Graf [XFRMA_ENCAP] = { .len = sizeof(struct xfrm_encap_tmpl) }, 1891cf5cb79fSThomas Graf [XFRMA_TMPL] = { .len = sizeof(struct xfrm_user_tmpl) }, 1892cf5cb79fSThomas Graf [XFRMA_SEC_CTX] = { .len = sizeof(struct xfrm_sec_ctx) }, 1893cf5cb79fSThomas Graf [XFRMA_LTIME_VAL] = { .len = sizeof(struct xfrm_lifetime_cur) }, 1894cf5cb79fSThomas Graf [XFRMA_REPLAY_VAL] = { .len = sizeof(struct xfrm_replay_state) }, 1895cf5cb79fSThomas Graf [XFRMA_REPLAY_THRESH] = { .type = NLA_U32 }, 1896cf5cb79fSThomas Graf [XFRMA_ETIMER_THRESH] = { .type = NLA_U32 }, 1897cf5cb79fSThomas Graf [XFRMA_SRCADDR] = { .len = sizeof(xfrm_address_t) }, 1898cf5cb79fSThomas Graf [XFRMA_COADDR] = { .len = sizeof(xfrm_address_t) }, 1899cf5cb79fSThomas Graf [XFRMA_POLICY_TYPE] = { .len = sizeof(struct xfrm_userpolicy_type)}, 1900cf5cb79fSThomas Graf [XFRMA_MIGRATE] = { .len = sizeof(struct xfrm_user_migrate) }, 1901cf5cb79fSThomas Graf }; 1902cf5cb79fSThomas Graf 19031da177e4SLinus Torvalds static struct xfrm_link { 19045424f32eSThomas Graf int (*doit)(struct sk_buff *, struct nlmsghdr *, struct nlattr **); 19051da177e4SLinus Torvalds int (*dump)(struct sk_buff *, struct netlink_callback *); 1906*4c563f76STimo Teras int (*done)(struct netlink_callback *); 1907492b558bSThomas Graf } xfrm_dispatch[XFRM_NR_MSGTYPES] = { 1908492b558bSThomas Graf [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 1909492b558bSThomas Graf [XFRM_MSG_DELSA - XFRM_MSG_BASE] = { .doit = xfrm_del_sa }, 1910492b558bSThomas Graf [XFRM_MSG_GETSA - XFRM_MSG_BASE] = { .doit = xfrm_get_sa, 1911*4c563f76STimo Teras .dump = xfrm_dump_sa, 1912*4c563f76STimo Teras .done = xfrm_dump_sa_done }, 1913492b558bSThomas Graf [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1914492b558bSThomas Graf [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy }, 1915492b558bSThomas Graf [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_get_policy, 1916*4c563f76STimo Teras .dump = xfrm_dump_policy, 1917*4c563f76STimo Teras .done = xfrm_dump_policy_done }, 1918492b558bSThomas Graf [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = { .doit = xfrm_alloc_userspi }, 1919980ebd25SJamal Hadi Salim [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_acquire }, 192053bc6b4dSJamal Hadi Salim [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_sa_expire }, 1921492b558bSThomas Graf [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_add_policy }, 1922492b558bSThomas Graf [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = { .doit = xfrm_add_sa }, 19236c5c8ca7SJamal Hadi Salim [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = { .doit = xfrm_add_pol_expire}, 1924492b558bSThomas Graf [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = { .doit = xfrm_flush_sa }, 1925492b558bSThomas Graf [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = { .doit = xfrm_flush_policy }, 1926d51d081dSJamal Hadi Salim [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = { .doit = xfrm_new_ae }, 1927d51d081dSJamal Hadi Salim [XFRM_MSG_GETAE - XFRM_MSG_BASE] = { .doit = xfrm_get_ae }, 19285c79de6eSShinta Sugimoto [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = { .doit = xfrm_do_migrate }, 192928d8909bSJamal Hadi Salim [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_sadinfo }, 1930ecfd6b18SJamal Hadi Salim [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = { .doit = xfrm_get_spdinfo }, 19311da177e4SLinus Torvalds }; 19321da177e4SLinus Torvalds 19331d00a4ebSThomas Graf static int xfrm_user_rcv_msg(struct sk_buff *skb, struct nlmsghdr *nlh) 19341da177e4SLinus Torvalds { 193535a7aa08SThomas Graf struct nlattr *attrs[XFRMA_MAX+1]; 19361da177e4SLinus Torvalds struct xfrm_link *link; 1937a7bd9a45SThomas Graf int type, err; 19381da177e4SLinus Torvalds 19391da177e4SLinus Torvalds type = nlh->nlmsg_type; 19401da177e4SLinus Torvalds if (type > XFRM_MSG_MAX) 19411d00a4ebSThomas Graf return -EINVAL; 19421da177e4SLinus Torvalds 19431da177e4SLinus Torvalds type -= XFRM_MSG_BASE; 19441da177e4SLinus Torvalds link = &xfrm_dispatch[type]; 19451da177e4SLinus Torvalds 19461da177e4SLinus Torvalds /* All operations require privileges, even GET */ 19471d00a4ebSThomas Graf if (security_netlink_recv(skb, CAP_NET_ADMIN)) 19481d00a4ebSThomas Graf return -EPERM; 19491da177e4SLinus Torvalds 1950492b558bSThomas Graf if ((type == (XFRM_MSG_GETSA - XFRM_MSG_BASE) || 1951492b558bSThomas Graf type == (XFRM_MSG_GETPOLICY - XFRM_MSG_BASE)) && 1952492b558bSThomas Graf (nlh->nlmsg_flags & NLM_F_DUMP)) { 19531da177e4SLinus Torvalds if (link->dump == NULL) 19541d00a4ebSThomas Graf return -EINVAL; 19551da177e4SLinus Torvalds 1956*4c563f76STimo Teras return netlink_dump_start(xfrm_nl, skb, nlh, link->dump, link->done); 19571da177e4SLinus Torvalds } 19581da177e4SLinus Torvalds 195935a7aa08SThomas Graf err = nlmsg_parse(nlh, xfrm_msg_min[type], attrs, XFRMA_MAX, 1960cf5cb79fSThomas Graf xfrma_policy); 1961a7bd9a45SThomas Graf if (err < 0) 1962a7bd9a45SThomas Graf return err; 19631da177e4SLinus Torvalds 19641da177e4SLinus Torvalds if (link->doit == NULL) 19651d00a4ebSThomas Graf return -EINVAL; 19661da177e4SLinus Torvalds 19675424f32eSThomas Graf return link->doit(skb, nlh, attrs); 19681da177e4SLinus Torvalds } 19691da177e4SLinus Torvalds 1970cd40b7d3SDenis V. Lunev static void xfrm_netlink_rcv(struct sk_buff *skb) 19711da177e4SLinus Torvalds { 19724a3e2f71SArjan van de Ven mutex_lock(&xfrm_cfg_mutex); 1973cd40b7d3SDenis V. Lunev netlink_rcv_skb(skb, &xfrm_user_rcv_msg); 19744a3e2f71SArjan van de Ven mutex_unlock(&xfrm_cfg_mutex); 19751da177e4SLinus Torvalds } 19761da177e4SLinus Torvalds 19777deb2264SThomas Graf static inline size_t xfrm_expire_msgsize(void) 19787deb2264SThomas Graf { 19797deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_expire)); 19807deb2264SThomas Graf } 19817deb2264SThomas Graf 1982d51d081dSJamal Hadi Salim static int build_expire(struct sk_buff *skb, struct xfrm_state *x, struct km_event *c) 19831da177e4SLinus Torvalds { 19841da177e4SLinus Torvalds struct xfrm_user_expire *ue; 19851da177e4SLinus Torvalds struct nlmsghdr *nlh; 19861da177e4SLinus Torvalds 198779b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_EXPIRE, sizeof(*ue), 0); 198879b8b7f4SThomas Graf if (nlh == NULL) 198979b8b7f4SThomas Graf return -EMSGSIZE; 19901da177e4SLinus Torvalds 19917b67c857SThomas Graf ue = nlmsg_data(nlh); 19921da177e4SLinus Torvalds copy_to_user_state(x, &ue->state); 1993d51d081dSJamal Hadi Salim ue->hard = (c->data.hard != 0) ? 1 : 0; 19941da177e4SLinus Torvalds 19959825069dSThomas Graf return nlmsg_end(skb, nlh); 19961da177e4SLinus Torvalds } 19971da177e4SLinus Torvalds 199826b15dadSJamal Hadi Salim static int xfrm_exp_state_notify(struct xfrm_state *x, struct km_event *c) 19991da177e4SLinus Torvalds { 20001da177e4SLinus Torvalds struct sk_buff *skb; 20011da177e4SLinus Torvalds 20027deb2264SThomas Graf skb = nlmsg_new(xfrm_expire_msgsize(), GFP_ATOMIC); 20031da177e4SLinus Torvalds if (skb == NULL) 20041da177e4SLinus Torvalds return -ENOMEM; 20051da177e4SLinus Torvalds 2006d51d081dSJamal Hadi Salim if (build_expire(skb, x, c) < 0) 20071da177e4SLinus Torvalds BUG(); 20081da177e4SLinus Torvalds 2009082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); 20101da177e4SLinus Torvalds } 20111da177e4SLinus Torvalds 2012d51d081dSJamal Hadi Salim static int xfrm_aevent_state_notify(struct xfrm_state *x, struct km_event *c) 2013d51d081dSJamal Hadi Salim { 2014d51d081dSJamal Hadi Salim struct sk_buff *skb; 2015d51d081dSJamal Hadi Salim 20167deb2264SThomas Graf skb = nlmsg_new(xfrm_aevent_msgsize(), GFP_ATOMIC); 2017d51d081dSJamal Hadi Salim if (skb == NULL) 2018d51d081dSJamal Hadi Salim return -ENOMEM; 2019d51d081dSJamal Hadi Salim 2020d51d081dSJamal Hadi Salim if (build_aevent(skb, x, c) < 0) 2021d51d081dSJamal Hadi Salim BUG(); 2022d51d081dSJamal Hadi Salim 2023082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_AEVENTS, GFP_ATOMIC); 2024d51d081dSJamal Hadi Salim } 2025d51d081dSJamal Hadi Salim 202626b15dadSJamal Hadi Salim static int xfrm_notify_sa_flush(struct km_event *c) 202726b15dadSJamal Hadi Salim { 202826b15dadSJamal Hadi Salim struct xfrm_usersa_flush *p; 202926b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 203026b15dadSJamal Hadi Salim struct sk_buff *skb; 20317deb2264SThomas Graf int len = NLMSG_ALIGN(sizeof(struct xfrm_usersa_flush)); 203226b15dadSJamal Hadi Salim 20337deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 203426b15dadSJamal Hadi Salim if (skb == NULL) 203526b15dadSJamal Hadi Salim return -ENOMEM; 203626b15dadSJamal Hadi Salim 203779b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHSA, sizeof(*p), 0); 203879b8b7f4SThomas Graf if (nlh == NULL) { 203979b8b7f4SThomas Graf kfree_skb(skb); 204079b8b7f4SThomas Graf return -EMSGSIZE; 204179b8b7f4SThomas Graf } 204226b15dadSJamal Hadi Salim 20437b67c857SThomas Graf p = nlmsg_data(nlh); 2044bf08867fSHerbert Xu p->proto = c->data.proto; 204526b15dadSJamal Hadi Salim 20469825069dSThomas Graf nlmsg_end(skb, nlh); 204726b15dadSJamal Hadi Salim 2048082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); 204926b15dadSJamal Hadi Salim } 205026b15dadSJamal Hadi Salim 20517deb2264SThomas Graf static inline size_t xfrm_sa_len(struct xfrm_state *x) 205226b15dadSJamal Hadi Salim { 20537deb2264SThomas Graf size_t l = 0; 20541a6509d9SHerbert Xu if (x->aead) 20551a6509d9SHerbert Xu l += nla_total_size(aead_len(x->aead)); 205626b15dadSJamal Hadi Salim if (x->aalg) 20570f99be0dSEric Dumazet l += nla_total_size(xfrm_alg_len(x->aalg)); 205826b15dadSJamal Hadi Salim if (x->ealg) 20590f99be0dSEric Dumazet l += nla_total_size(xfrm_alg_len(x->ealg)); 206026b15dadSJamal Hadi Salim if (x->calg) 20617deb2264SThomas Graf l += nla_total_size(sizeof(*x->calg)); 206226b15dadSJamal Hadi Salim if (x->encap) 20637deb2264SThomas Graf l += nla_total_size(sizeof(*x->encap)); 206468325d3bSHerbert Xu if (x->security) 206568325d3bSHerbert Xu l += nla_total_size(sizeof(struct xfrm_user_sec_ctx) + 206668325d3bSHerbert Xu x->security->ctx_len); 206768325d3bSHerbert Xu if (x->coaddr) 206868325d3bSHerbert Xu l += nla_total_size(sizeof(*x->coaddr)); 206968325d3bSHerbert Xu 2070d26f3984SHerbert Xu /* Must count x->lastused as it may become non-zero behind our back. */ 2071d26f3984SHerbert Xu l += nla_total_size(sizeof(u64)); 207226b15dadSJamal Hadi Salim 207326b15dadSJamal Hadi Salim return l; 207426b15dadSJamal Hadi Salim } 207526b15dadSJamal Hadi Salim 207626b15dadSJamal Hadi Salim static int xfrm_notify_sa(struct xfrm_state *x, struct km_event *c) 207726b15dadSJamal Hadi Salim { 207826b15dadSJamal Hadi Salim struct xfrm_usersa_info *p; 20790603eac0SHerbert Xu struct xfrm_usersa_id *id; 208026b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 208126b15dadSJamal Hadi Salim struct sk_buff *skb; 208226b15dadSJamal Hadi Salim int len = xfrm_sa_len(x); 20830603eac0SHerbert Xu int headlen; 20840603eac0SHerbert Xu 20850603eac0SHerbert Xu headlen = sizeof(*p); 20860603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 20877deb2264SThomas Graf len += nla_total_size(headlen); 20880603eac0SHerbert Xu headlen = sizeof(*id); 20890603eac0SHerbert Xu } 20907deb2264SThomas Graf len += NLMSG_ALIGN(headlen); 209126b15dadSJamal Hadi Salim 20927deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 209326b15dadSJamal Hadi Salim if (skb == NULL) 209426b15dadSJamal Hadi Salim return -ENOMEM; 209526b15dadSJamal Hadi Salim 209679b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); 209779b8b7f4SThomas Graf if (nlh == NULL) 2098c0144beaSThomas Graf goto nla_put_failure; 209926b15dadSJamal Hadi Salim 21007b67c857SThomas Graf p = nlmsg_data(nlh); 21010603eac0SHerbert Xu if (c->event == XFRM_MSG_DELSA) { 2102c0144beaSThomas Graf struct nlattr *attr; 2103c0144beaSThomas Graf 21047b67c857SThomas Graf id = nlmsg_data(nlh); 21050603eac0SHerbert Xu memcpy(&id->daddr, &x->id.daddr, sizeof(id->daddr)); 21060603eac0SHerbert Xu id->spi = x->id.spi; 21070603eac0SHerbert Xu id->family = x->props.family; 21080603eac0SHerbert Xu id->proto = x->id.proto; 21090603eac0SHerbert Xu 2110c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_SA, sizeof(*p)); 2111c0144beaSThomas Graf if (attr == NULL) 2112c0144beaSThomas Graf goto nla_put_failure; 2113c0144beaSThomas Graf 2114c0144beaSThomas Graf p = nla_data(attr); 21150603eac0SHerbert Xu } 21160603eac0SHerbert Xu 211768325d3bSHerbert Xu if (copy_to_user_state_extra(x, p, skb)) 211868325d3bSHerbert Xu goto nla_put_failure; 211926b15dadSJamal Hadi Salim 21209825069dSThomas Graf nlmsg_end(skb, nlh); 212126b15dadSJamal Hadi Salim 2122082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_SA, GFP_ATOMIC); 212326b15dadSJamal Hadi Salim 2124c0144beaSThomas Graf nla_put_failure: 212568325d3bSHerbert Xu /* Somebody screwed up with xfrm_sa_len! */ 212668325d3bSHerbert Xu WARN_ON(1); 212726b15dadSJamal Hadi Salim kfree_skb(skb); 212826b15dadSJamal Hadi Salim return -1; 212926b15dadSJamal Hadi Salim } 213026b15dadSJamal Hadi Salim 213126b15dadSJamal Hadi Salim static int xfrm_send_state_notify(struct xfrm_state *x, struct km_event *c) 213226b15dadSJamal Hadi Salim { 213326b15dadSJamal Hadi Salim 213426b15dadSJamal Hadi Salim switch (c->event) { 2135f60f6b8fSHerbert Xu case XFRM_MSG_EXPIRE: 213626b15dadSJamal Hadi Salim return xfrm_exp_state_notify(x, c); 2137d51d081dSJamal Hadi Salim case XFRM_MSG_NEWAE: 2138d51d081dSJamal Hadi Salim return xfrm_aevent_state_notify(x, c); 2139f60f6b8fSHerbert Xu case XFRM_MSG_DELSA: 2140f60f6b8fSHerbert Xu case XFRM_MSG_UPDSA: 2141f60f6b8fSHerbert Xu case XFRM_MSG_NEWSA: 214226b15dadSJamal Hadi Salim return xfrm_notify_sa(x, c); 2143f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHSA: 214426b15dadSJamal Hadi Salim return xfrm_notify_sa_flush(c); 214526b15dadSJamal Hadi Salim default: 214626b15dadSJamal Hadi Salim printk("xfrm_user: Unknown SA event %d\n", c->event); 214726b15dadSJamal Hadi Salim break; 214826b15dadSJamal Hadi Salim } 214926b15dadSJamal Hadi Salim 215026b15dadSJamal Hadi Salim return 0; 215126b15dadSJamal Hadi Salim 215226b15dadSJamal Hadi Salim } 215326b15dadSJamal Hadi Salim 21547deb2264SThomas Graf static inline size_t xfrm_acquire_msgsize(struct xfrm_state *x, 21557deb2264SThomas Graf struct xfrm_policy *xp) 21567deb2264SThomas Graf { 21577deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_acquire)) 21587deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) 21597deb2264SThomas Graf + nla_total_size(xfrm_user_sec_ctx_size(x->security)) 21607deb2264SThomas Graf + userpolicy_type_attrsize(); 21617deb2264SThomas Graf } 21627deb2264SThomas Graf 21631da177e4SLinus Torvalds static int build_acquire(struct sk_buff *skb, struct xfrm_state *x, 21641da177e4SLinus Torvalds struct xfrm_tmpl *xt, struct xfrm_policy *xp, 21651da177e4SLinus Torvalds int dir) 21661da177e4SLinus Torvalds { 21671da177e4SLinus Torvalds struct xfrm_user_acquire *ua; 21681da177e4SLinus Torvalds struct nlmsghdr *nlh; 21691da177e4SLinus Torvalds __u32 seq = xfrm_get_acqseq(); 21701da177e4SLinus Torvalds 217179b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_ACQUIRE, sizeof(*ua), 0); 217279b8b7f4SThomas Graf if (nlh == NULL) 217379b8b7f4SThomas Graf return -EMSGSIZE; 21741da177e4SLinus Torvalds 21757b67c857SThomas Graf ua = nlmsg_data(nlh); 21761da177e4SLinus Torvalds memcpy(&ua->id, &x->id, sizeof(ua->id)); 21771da177e4SLinus Torvalds memcpy(&ua->saddr, &x->props.saddr, sizeof(ua->saddr)); 21781da177e4SLinus Torvalds memcpy(&ua->sel, &x->sel, sizeof(ua->sel)); 21791da177e4SLinus Torvalds copy_to_user_policy(xp, &ua->policy, dir); 21801da177e4SLinus Torvalds ua->aalgos = xt->aalgos; 21811da177e4SLinus Torvalds ua->ealgos = xt->ealgos; 21821da177e4SLinus Torvalds ua->calgos = xt->calgos; 21831da177e4SLinus Torvalds ua->seq = x->km.seq = seq; 21841da177e4SLinus Torvalds 21851da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 21861da177e4SLinus Torvalds goto nlmsg_failure; 21870d681623SSerge Hallyn if (copy_to_user_state_sec_ctx(x, skb)) 2188df71837dSTrent Jaeger goto nlmsg_failure; 21891459bb36SJamal Hadi Salim if (copy_to_user_policy_type(xp->type, skb) < 0) 2190f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 21911da177e4SLinus Torvalds 21929825069dSThomas Graf return nlmsg_end(skb, nlh); 21931da177e4SLinus Torvalds 21941da177e4SLinus Torvalds nlmsg_failure: 21959825069dSThomas Graf nlmsg_cancel(skb, nlh); 21969825069dSThomas Graf return -EMSGSIZE; 21971da177e4SLinus Torvalds } 21981da177e4SLinus Torvalds 21991da177e4SLinus Torvalds static int xfrm_send_acquire(struct xfrm_state *x, struct xfrm_tmpl *xt, 22001da177e4SLinus Torvalds struct xfrm_policy *xp, int dir) 22011da177e4SLinus Torvalds { 22021da177e4SLinus Torvalds struct sk_buff *skb; 22031da177e4SLinus Torvalds 22047deb2264SThomas Graf skb = nlmsg_new(xfrm_acquire_msgsize(x, xp), GFP_ATOMIC); 22051da177e4SLinus Torvalds if (skb == NULL) 22061da177e4SLinus Torvalds return -ENOMEM; 22071da177e4SLinus Torvalds 22081da177e4SLinus Torvalds if (build_acquire(skb, x, xt, xp, dir) < 0) 22091da177e4SLinus Torvalds BUG(); 22101da177e4SLinus Torvalds 2211082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_ACQUIRE, GFP_ATOMIC); 22121da177e4SLinus Torvalds } 22131da177e4SLinus Torvalds 22141da177e4SLinus Torvalds /* User gives us xfrm_user_policy_info followed by an array of 0 22151da177e4SLinus Torvalds * or more templates. 22161da177e4SLinus Torvalds */ 2217cb969f07SVenkat Yekkirala static struct xfrm_policy *xfrm_compile_policy(struct sock *sk, int opt, 22181da177e4SLinus Torvalds u8 *data, int len, int *dir) 22191da177e4SLinus Torvalds { 22201da177e4SLinus Torvalds struct xfrm_userpolicy_info *p = (struct xfrm_userpolicy_info *)data; 22211da177e4SLinus Torvalds struct xfrm_user_tmpl *ut = (struct xfrm_user_tmpl *) (p + 1); 22221da177e4SLinus Torvalds struct xfrm_policy *xp; 22231da177e4SLinus Torvalds int nr; 22241da177e4SLinus Torvalds 2225cb969f07SVenkat Yekkirala switch (sk->sk_family) { 22261da177e4SLinus Torvalds case AF_INET: 22271da177e4SLinus Torvalds if (opt != IP_XFRM_POLICY) { 22281da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 22291da177e4SLinus Torvalds return NULL; 22301da177e4SLinus Torvalds } 22311da177e4SLinus Torvalds break; 22321da177e4SLinus Torvalds #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) 22331da177e4SLinus Torvalds case AF_INET6: 22341da177e4SLinus Torvalds if (opt != IPV6_XFRM_POLICY) { 22351da177e4SLinus Torvalds *dir = -EOPNOTSUPP; 22361da177e4SLinus Torvalds return NULL; 22371da177e4SLinus Torvalds } 22381da177e4SLinus Torvalds break; 22391da177e4SLinus Torvalds #endif 22401da177e4SLinus Torvalds default: 22411da177e4SLinus Torvalds *dir = -EINVAL; 22421da177e4SLinus Torvalds return NULL; 22431da177e4SLinus Torvalds } 22441da177e4SLinus Torvalds 22451da177e4SLinus Torvalds *dir = -EINVAL; 22461da177e4SLinus Torvalds 22471da177e4SLinus Torvalds if (len < sizeof(*p) || 22481da177e4SLinus Torvalds verify_newpolicy_info(p)) 22491da177e4SLinus Torvalds return NULL; 22501da177e4SLinus Torvalds 22511da177e4SLinus Torvalds nr = ((len - sizeof(*p)) / sizeof(*ut)); 2252b4ad86bfSDavid S. Miller if (validate_tmpl(nr, ut, p->sel.family)) 22531da177e4SLinus Torvalds return NULL; 22541da177e4SLinus Torvalds 2255a4f1bac6SHerbert Xu if (p->dir > XFRM_POLICY_OUT) 2256a4f1bac6SHerbert Xu return NULL; 2257a4f1bac6SHerbert Xu 22581da177e4SLinus Torvalds xp = xfrm_policy_alloc(GFP_KERNEL); 22591da177e4SLinus Torvalds if (xp == NULL) { 22601da177e4SLinus Torvalds *dir = -ENOBUFS; 22611da177e4SLinus Torvalds return NULL; 22621da177e4SLinus Torvalds } 22631da177e4SLinus Torvalds 22641da177e4SLinus Torvalds copy_from_user_policy(xp, p); 2265f7b6983fSMasahide NAKAMURA xp->type = XFRM_POLICY_TYPE_MAIN; 22661da177e4SLinus Torvalds copy_templates(xp, ut, nr); 22671da177e4SLinus Torvalds 22681da177e4SLinus Torvalds *dir = p->dir; 22691da177e4SLinus Torvalds 22701da177e4SLinus Torvalds return xp; 22711da177e4SLinus Torvalds } 22721da177e4SLinus Torvalds 22737deb2264SThomas Graf static inline size_t xfrm_polexpire_msgsize(struct xfrm_policy *xp) 22747deb2264SThomas Graf { 22757deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_polexpire)) 22767deb2264SThomas Graf + nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr) 22777deb2264SThomas Graf + nla_total_size(xfrm_user_sec_ctx_size(xp->security)) 22787deb2264SThomas Graf + userpolicy_type_attrsize(); 22797deb2264SThomas Graf } 22807deb2264SThomas Graf 22811da177e4SLinus Torvalds static int build_polexpire(struct sk_buff *skb, struct xfrm_policy *xp, 2282d51d081dSJamal Hadi Salim int dir, struct km_event *c) 22831da177e4SLinus Torvalds { 22841da177e4SLinus Torvalds struct xfrm_user_polexpire *upe; 22851da177e4SLinus Torvalds struct nlmsghdr *nlh; 2286d51d081dSJamal Hadi Salim int hard = c->data.hard; 22871da177e4SLinus Torvalds 228879b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, 0, XFRM_MSG_POLEXPIRE, sizeof(*upe), 0); 228979b8b7f4SThomas Graf if (nlh == NULL) 229079b8b7f4SThomas Graf return -EMSGSIZE; 22911da177e4SLinus Torvalds 22927b67c857SThomas Graf upe = nlmsg_data(nlh); 22931da177e4SLinus Torvalds copy_to_user_policy(xp, &upe->pol, dir); 22941da177e4SLinus Torvalds if (copy_to_user_tmpl(xp, skb) < 0) 22951da177e4SLinus Torvalds goto nlmsg_failure; 2296df71837dSTrent Jaeger if (copy_to_user_sec_ctx(xp, skb)) 2297df71837dSTrent Jaeger goto nlmsg_failure; 22981459bb36SJamal Hadi Salim if (copy_to_user_policy_type(xp->type, skb) < 0) 2299f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 23001da177e4SLinus Torvalds upe->hard = !!hard; 23011da177e4SLinus Torvalds 23029825069dSThomas Graf return nlmsg_end(skb, nlh); 23031da177e4SLinus Torvalds 23041da177e4SLinus Torvalds nlmsg_failure: 23059825069dSThomas Graf nlmsg_cancel(skb, nlh); 23069825069dSThomas Graf return -EMSGSIZE; 23071da177e4SLinus Torvalds } 23081da177e4SLinus Torvalds 230926b15dadSJamal Hadi Salim static int xfrm_exp_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 23101da177e4SLinus Torvalds { 23111da177e4SLinus Torvalds struct sk_buff *skb; 23121da177e4SLinus Torvalds 23137deb2264SThomas Graf skb = nlmsg_new(xfrm_polexpire_msgsize(xp), GFP_ATOMIC); 23141da177e4SLinus Torvalds if (skb == NULL) 23151da177e4SLinus Torvalds return -ENOMEM; 23161da177e4SLinus Torvalds 2317d51d081dSJamal Hadi Salim if (build_polexpire(skb, xp, dir, c) < 0) 23181da177e4SLinus Torvalds BUG(); 23191da177e4SLinus Torvalds 2320082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_EXPIRE, GFP_ATOMIC); 23211da177e4SLinus Torvalds } 23221da177e4SLinus Torvalds 232326b15dadSJamal Hadi Salim static int xfrm_notify_policy(struct xfrm_policy *xp, int dir, struct km_event *c) 232426b15dadSJamal Hadi Salim { 232526b15dadSJamal Hadi Salim struct xfrm_userpolicy_info *p; 23260603eac0SHerbert Xu struct xfrm_userpolicy_id *id; 232726b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 232826b15dadSJamal Hadi Salim struct sk_buff *skb; 23297deb2264SThomas Graf int len = nla_total_size(sizeof(struct xfrm_user_tmpl) * xp->xfrm_nr); 23300603eac0SHerbert Xu int headlen; 23310603eac0SHerbert Xu 23320603eac0SHerbert Xu headlen = sizeof(*p); 23330603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 23347deb2264SThomas Graf len += nla_total_size(headlen); 23350603eac0SHerbert Xu headlen = sizeof(*id); 23360603eac0SHerbert Xu } 2337cfbfd45aSThomas Graf len += userpolicy_type_attrsize(); 23387deb2264SThomas Graf len += NLMSG_ALIGN(headlen); 233926b15dadSJamal Hadi Salim 23407deb2264SThomas Graf skb = nlmsg_new(len, GFP_ATOMIC); 234126b15dadSJamal Hadi Salim if (skb == NULL) 234226b15dadSJamal Hadi Salim return -ENOMEM; 234326b15dadSJamal Hadi Salim 234479b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, c->seq, c->event, headlen, 0); 234579b8b7f4SThomas Graf if (nlh == NULL) 234679b8b7f4SThomas Graf goto nlmsg_failure; 234726b15dadSJamal Hadi Salim 23487b67c857SThomas Graf p = nlmsg_data(nlh); 23490603eac0SHerbert Xu if (c->event == XFRM_MSG_DELPOLICY) { 2350c0144beaSThomas Graf struct nlattr *attr; 2351c0144beaSThomas Graf 23527b67c857SThomas Graf id = nlmsg_data(nlh); 23530603eac0SHerbert Xu memset(id, 0, sizeof(*id)); 23540603eac0SHerbert Xu id->dir = dir; 23550603eac0SHerbert Xu if (c->data.byid) 23560603eac0SHerbert Xu id->index = xp->index; 23570603eac0SHerbert Xu else 23580603eac0SHerbert Xu memcpy(&id->sel, &xp->selector, sizeof(id->sel)); 23590603eac0SHerbert Xu 2360c0144beaSThomas Graf attr = nla_reserve(skb, XFRMA_POLICY, sizeof(*p)); 2361c0144beaSThomas Graf if (attr == NULL) 2362c0144beaSThomas Graf goto nlmsg_failure; 2363c0144beaSThomas Graf 2364c0144beaSThomas Graf p = nla_data(attr); 23650603eac0SHerbert Xu } 236626b15dadSJamal Hadi Salim 236726b15dadSJamal Hadi Salim copy_to_user_policy(xp, p, dir); 236826b15dadSJamal Hadi Salim if (copy_to_user_tmpl(xp, skb) < 0) 236926b15dadSJamal Hadi Salim goto nlmsg_failure; 23701459bb36SJamal Hadi Salim if (copy_to_user_policy_type(xp->type, skb) < 0) 2371f7b6983fSMasahide NAKAMURA goto nlmsg_failure; 237226b15dadSJamal Hadi Salim 23739825069dSThomas Graf nlmsg_end(skb, nlh); 237426b15dadSJamal Hadi Salim 2375082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); 237626b15dadSJamal Hadi Salim 237726b15dadSJamal Hadi Salim nlmsg_failure: 237826b15dadSJamal Hadi Salim kfree_skb(skb); 237926b15dadSJamal Hadi Salim return -1; 238026b15dadSJamal Hadi Salim } 238126b15dadSJamal Hadi Salim 238226b15dadSJamal Hadi Salim static int xfrm_notify_policy_flush(struct km_event *c) 238326b15dadSJamal Hadi Salim { 238426b15dadSJamal Hadi Salim struct nlmsghdr *nlh; 238526b15dadSJamal Hadi Salim struct sk_buff *skb; 238626b15dadSJamal Hadi Salim 23877deb2264SThomas Graf skb = nlmsg_new(userpolicy_type_attrsize(), GFP_ATOMIC); 238826b15dadSJamal Hadi Salim if (skb == NULL) 238926b15dadSJamal Hadi Salim return -ENOMEM; 239026b15dadSJamal Hadi Salim 239179b8b7f4SThomas Graf nlh = nlmsg_put(skb, c->pid, c->seq, XFRM_MSG_FLUSHPOLICY, 0, 0); 239279b8b7f4SThomas Graf if (nlh == NULL) 239379b8b7f4SThomas Graf goto nlmsg_failure; 23940c51f53cSJamal Hadi Salim if (copy_to_user_policy_type(c->data.type, skb) < 0) 23950c51f53cSJamal Hadi Salim goto nlmsg_failure; 239626b15dadSJamal Hadi Salim 23979825069dSThomas Graf nlmsg_end(skb, nlh); 239826b15dadSJamal Hadi Salim 2399082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_POLICY, GFP_ATOMIC); 240026b15dadSJamal Hadi Salim 240126b15dadSJamal Hadi Salim nlmsg_failure: 240226b15dadSJamal Hadi Salim kfree_skb(skb); 240326b15dadSJamal Hadi Salim return -1; 240426b15dadSJamal Hadi Salim } 240526b15dadSJamal Hadi Salim 240626b15dadSJamal Hadi Salim static int xfrm_send_policy_notify(struct xfrm_policy *xp, int dir, struct km_event *c) 240726b15dadSJamal Hadi Salim { 240826b15dadSJamal Hadi Salim 240926b15dadSJamal Hadi Salim switch (c->event) { 2410f60f6b8fSHerbert Xu case XFRM_MSG_NEWPOLICY: 2411f60f6b8fSHerbert Xu case XFRM_MSG_UPDPOLICY: 2412f60f6b8fSHerbert Xu case XFRM_MSG_DELPOLICY: 241326b15dadSJamal Hadi Salim return xfrm_notify_policy(xp, dir, c); 2414f60f6b8fSHerbert Xu case XFRM_MSG_FLUSHPOLICY: 241526b15dadSJamal Hadi Salim return xfrm_notify_policy_flush(c); 2416f60f6b8fSHerbert Xu case XFRM_MSG_POLEXPIRE: 241726b15dadSJamal Hadi Salim return xfrm_exp_policy_notify(xp, dir, c); 241826b15dadSJamal Hadi Salim default: 241926b15dadSJamal Hadi Salim printk("xfrm_user: Unknown Policy event %d\n", c->event); 242026b15dadSJamal Hadi Salim } 242126b15dadSJamal Hadi Salim 242226b15dadSJamal Hadi Salim return 0; 242326b15dadSJamal Hadi Salim 242426b15dadSJamal Hadi Salim } 242526b15dadSJamal Hadi Salim 24267deb2264SThomas Graf static inline size_t xfrm_report_msgsize(void) 24277deb2264SThomas Graf { 24287deb2264SThomas Graf return NLMSG_ALIGN(sizeof(struct xfrm_user_report)); 24297deb2264SThomas Graf } 24307deb2264SThomas Graf 243197a64b45SMasahide NAKAMURA static int build_report(struct sk_buff *skb, u8 proto, 243297a64b45SMasahide NAKAMURA struct xfrm_selector *sel, xfrm_address_t *addr) 243397a64b45SMasahide NAKAMURA { 243497a64b45SMasahide NAKAMURA struct xfrm_user_report *ur; 243597a64b45SMasahide NAKAMURA struct nlmsghdr *nlh; 243697a64b45SMasahide NAKAMURA 243779b8b7f4SThomas Graf nlh = nlmsg_put(skb, 0, 0, XFRM_MSG_REPORT, sizeof(*ur), 0); 243879b8b7f4SThomas Graf if (nlh == NULL) 243979b8b7f4SThomas Graf return -EMSGSIZE; 244097a64b45SMasahide NAKAMURA 24417b67c857SThomas Graf ur = nlmsg_data(nlh); 244297a64b45SMasahide NAKAMURA ur->proto = proto; 244397a64b45SMasahide NAKAMURA memcpy(&ur->sel, sel, sizeof(ur->sel)); 244497a64b45SMasahide NAKAMURA 244597a64b45SMasahide NAKAMURA if (addr) 2446c0144beaSThomas Graf NLA_PUT(skb, XFRMA_COADDR, sizeof(*addr), addr); 244797a64b45SMasahide NAKAMURA 24489825069dSThomas Graf return nlmsg_end(skb, nlh); 244997a64b45SMasahide NAKAMURA 2450c0144beaSThomas Graf nla_put_failure: 24519825069dSThomas Graf nlmsg_cancel(skb, nlh); 24529825069dSThomas Graf return -EMSGSIZE; 245397a64b45SMasahide NAKAMURA } 245497a64b45SMasahide NAKAMURA 245597a64b45SMasahide NAKAMURA static int xfrm_send_report(u8 proto, struct xfrm_selector *sel, 245697a64b45SMasahide NAKAMURA xfrm_address_t *addr) 245797a64b45SMasahide NAKAMURA { 245897a64b45SMasahide NAKAMURA struct sk_buff *skb; 245997a64b45SMasahide NAKAMURA 24607deb2264SThomas Graf skb = nlmsg_new(xfrm_report_msgsize(), GFP_ATOMIC); 246197a64b45SMasahide NAKAMURA if (skb == NULL) 246297a64b45SMasahide NAKAMURA return -ENOMEM; 246397a64b45SMasahide NAKAMURA 246497a64b45SMasahide NAKAMURA if (build_report(skb, proto, sel, addr) < 0) 246597a64b45SMasahide NAKAMURA BUG(); 246697a64b45SMasahide NAKAMURA 2467082a1ad5SThomas Graf return nlmsg_multicast(xfrm_nl, skb, 0, XFRMNLGRP_REPORT, GFP_ATOMIC); 246897a64b45SMasahide NAKAMURA } 246997a64b45SMasahide NAKAMURA 24701da177e4SLinus Torvalds static struct xfrm_mgr netlink_mgr = { 24711da177e4SLinus Torvalds .id = "netlink", 24721da177e4SLinus Torvalds .notify = xfrm_send_state_notify, 24731da177e4SLinus Torvalds .acquire = xfrm_send_acquire, 24741da177e4SLinus Torvalds .compile_policy = xfrm_compile_policy, 24751da177e4SLinus Torvalds .notify_policy = xfrm_send_policy_notify, 247697a64b45SMasahide NAKAMURA .report = xfrm_send_report, 24775c79de6eSShinta Sugimoto .migrate = xfrm_send_migrate, 24781da177e4SLinus Torvalds }; 24791da177e4SLinus Torvalds 24801da177e4SLinus Torvalds static int __init xfrm_user_init(void) 24811da177e4SLinus Torvalds { 2482be33690dSPatrick McHardy struct sock *nlsk; 2483be33690dSPatrick McHardy 2484654b32c6SMasahide NAKAMURA printk(KERN_INFO "Initializing XFRM netlink socket\n"); 24851da177e4SLinus Torvalds 2486b4b51029SEric W. Biederman nlsk = netlink_kernel_create(&init_net, NETLINK_XFRM, XFRMNLGRP_MAX, 2487af65bdfcSPatrick McHardy xfrm_netlink_rcv, NULL, THIS_MODULE); 2488be33690dSPatrick McHardy if (nlsk == NULL) 24891da177e4SLinus Torvalds return -ENOMEM; 2490be33690dSPatrick McHardy rcu_assign_pointer(xfrm_nl, nlsk); 24911da177e4SLinus Torvalds 24921da177e4SLinus Torvalds xfrm_register_km(&netlink_mgr); 24931da177e4SLinus Torvalds 24941da177e4SLinus Torvalds return 0; 24951da177e4SLinus Torvalds } 24961da177e4SLinus Torvalds 24971da177e4SLinus Torvalds static void __exit xfrm_user_exit(void) 24981da177e4SLinus Torvalds { 2499be33690dSPatrick McHardy struct sock *nlsk = xfrm_nl; 2500be33690dSPatrick McHardy 25011da177e4SLinus Torvalds xfrm_unregister_km(&netlink_mgr); 2502be33690dSPatrick McHardy rcu_assign_pointer(xfrm_nl, NULL); 2503be33690dSPatrick McHardy synchronize_rcu(); 2504b7c6ba6eSDenis V. Lunev netlink_kernel_release(nlsk); 25051da177e4SLinus Torvalds } 25061da177e4SLinus Torvalds 25071da177e4SLinus Torvalds module_init(xfrm_user_init); 25081da177e4SLinus Torvalds module_exit(xfrm_user_exit); 25091da177e4SLinus Torvalds MODULE_LICENSE("GPL"); 25104fdb3bb7SHarald Welte MODULE_ALIAS_NET_PF_PROTO(PF_NETLINK, NETLINK_XFRM); 2511f8cd5488SJamal Hadi Salim 2512