1c9e7c76dSDmitry Safonov // SPDX-License-Identifier: GPL-2.0 2c9e7c76dSDmitry Safonov /* 3c9e7c76dSDmitry Safonov * XFRM compat layer 4c9e7c76dSDmitry Safonov * Author: Dmitry Safonov <dima@arista.com> 5c9e7c76dSDmitry Safonov * Based on code and translator idea by: Florian Westphal <fw@strlen.de> 6c9e7c76dSDmitry Safonov */ 7c9e7c76dSDmitry Safonov #include <linux/compat.h> 8c9e7c76dSDmitry Safonov #include <linux/xfrm.h> 9c9e7c76dSDmitry Safonov #include <net/xfrm.h> 10c9e7c76dSDmitry Safonov 11*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg { 12*5461fc0cSDmitry Safonov compat_u64 soft_byte_limit, hard_byte_limit; 13*5461fc0cSDmitry Safonov compat_u64 soft_packet_limit, hard_packet_limit; 14*5461fc0cSDmitry Safonov compat_u64 soft_add_expires_seconds, hard_add_expires_seconds; 15*5461fc0cSDmitry Safonov compat_u64 soft_use_expires_seconds, hard_use_expires_seconds; 16*5461fc0cSDmitry Safonov }; /* same size on 32bit, but only 4 byte alignment required */ 17*5461fc0cSDmitry Safonov 18*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur { 19*5461fc0cSDmitry Safonov compat_u64 bytes, packets, add_time, use_time; 20*5461fc0cSDmitry Safonov }; /* same size on 32bit, but only 4 byte alignment required */ 21*5461fc0cSDmitry Safonov 22*5461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info { 23*5461fc0cSDmitry Safonov struct xfrm_selector sel; 24*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg lft; 25*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur curlft; 26*5461fc0cSDmitry Safonov __u32 priority, index; 27*5461fc0cSDmitry Safonov u8 dir, action, flags, share; 28*5461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 29*5461fc0cSDmitry Safonov }; 30*5461fc0cSDmitry Safonov 31*5461fc0cSDmitry Safonov struct compat_xfrm_usersa_info { 32*5461fc0cSDmitry Safonov struct xfrm_selector sel; 33*5461fc0cSDmitry Safonov struct xfrm_id id; 34*5461fc0cSDmitry Safonov xfrm_address_t saddr; 35*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cfg lft; 36*5461fc0cSDmitry Safonov struct compat_xfrm_lifetime_cur curlft; 37*5461fc0cSDmitry Safonov struct xfrm_stats stats; 38*5461fc0cSDmitry Safonov __u32 seq, reqid; 39*5461fc0cSDmitry Safonov u16 family; 40*5461fc0cSDmitry Safonov u8 mode, replay_window, flags; 41*5461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 42*5461fc0cSDmitry Safonov }; 43*5461fc0cSDmitry Safonov 44*5461fc0cSDmitry Safonov struct compat_xfrm_user_acquire { 45*5461fc0cSDmitry Safonov struct xfrm_id id; 46*5461fc0cSDmitry Safonov xfrm_address_t saddr; 47*5461fc0cSDmitry Safonov struct xfrm_selector sel; 48*5461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info policy; 49*5461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 50*5461fc0cSDmitry Safonov __u32 aalgos, ealgos, calgos, seq; 51*5461fc0cSDmitry Safonov }; 52*5461fc0cSDmitry Safonov 53*5461fc0cSDmitry Safonov struct compat_xfrm_userspi_info { 54*5461fc0cSDmitry Safonov struct compat_xfrm_usersa_info info; 55*5461fc0cSDmitry Safonov /* 4 bytes additional padding on 64bit */ 56*5461fc0cSDmitry Safonov __u32 min, max; 57*5461fc0cSDmitry Safonov }; 58*5461fc0cSDmitry Safonov 59*5461fc0cSDmitry Safonov struct compat_xfrm_user_expire { 60*5461fc0cSDmitry Safonov struct compat_xfrm_usersa_info state; 61*5461fc0cSDmitry Safonov /* 8 bytes additional padding on 64bit */ 62*5461fc0cSDmitry Safonov u8 hard; 63*5461fc0cSDmitry Safonov }; 64*5461fc0cSDmitry Safonov 65*5461fc0cSDmitry Safonov struct compat_xfrm_user_polexpire { 66*5461fc0cSDmitry Safonov struct compat_xfrm_userpolicy_info pol; 67*5461fc0cSDmitry Safonov /* 8 bytes additional padding on 64bit */ 68*5461fc0cSDmitry Safonov u8 hard; 69*5461fc0cSDmitry Safonov }; 70*5461fc0cSDmitry Safonov 71*5461fc0cSDmitry Safonov #define XMSGSIZE(type) sizeof(struct type) 72*5461fc0cSDmitry Safonov 73*5461fc0cSDmitry Safonov static const int compat_msg_min[XFRM_NR_MSGTYPES] = { 74*5461fc0cSDmitry Safonov [XFRM_MSG_NEWSA - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info), 75*5461fc0cSDmitry Safonov [XFRM_MSG_DELSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 76*5461fc0cSDmitry Safonov [XFRM_MSG_GETSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_id), 77*5461fc0cSDmitry Safonov [XFRM_MSG_NEWPOLICY - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info), 78*5461fc0cSDmitry Safonov [XFRM_MSG_DELPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 79*5461fc0cSDmitry Safonov [XFRM_MSG_GETPOLICY - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 80*5461fc0cSDmitry Safonov [XFRM_MSG_ALLOCSPI - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userspi_info), 81*5461fc0cSDmitry Safonov [XFRM_MSG_ACQUIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_acquire), 82*5461fc0cSDmitry Safonov [XFRM_MSG_EXPIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_expire), 83*5461fc0cSDmitry Safonov [XFRM_MSG_UPDPOLICY - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_userpolicy_info), 84*5461fc0cSDmitry Safonov [XFRM_MSG_UPDSA - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_usersa_info), 85*5461fc0cSDmitry Safonov [XFRM_MSG_POLEXPIRE - XFRM_MSG_BASE] = XMSGSIZE(compat_xfrm_user_polexpire), 86*5461fc0cSDmitry Safonov [XFRM_MSG_FLUSHSA - XFRM_MSG_BASE] = XMSGSIZE(xfrm_usersa_flush), 87*5461fc0cSDmitry Safonov [XFRM_MSG_FLUSHPOLICY - XFRM_MSG_BASE] = 0, 88*5461fc0cSDmitry Safonov [XFRM_MSG_NEWAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 89*5461fc0cSDmitry Safonov [XFRM_MSG_GETAE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_aevent_id), 90*5461fc0cSDmitry Safonov [XFRM_MSG_REPORT - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_report), 91*5461fc0cSDmitry Safonov [XFRM_MSG_MIGRATE - XFRM_MSG_BASE] = XMSGSIZE(xfrm_userpolicy_id), 92*5461fc0cSDmitry Safonov [XFRM_MSG_NEWSADINFO - XFRM_MSG_BASE] = sizeof(u32), 93*5461fc0cSDmitry Safonov [XFRM_MSG_GETSADINFO - XFRM_MSG_BASE] = sizeof(u32), 94*5461fc0cSDmitry Safonov [XFRM_MSG_NEWSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 95*5461fc0cSDmitry Safonov [XFRM_MSG_GETSPDINFO - XFRM_MSG_BASE] = sizeof(u32), 96*5461fc0cSDmitry Safonov [XFRM_MSG_MAPPING - XFRM_MSG_BASE] = XMSGSIZE(xfrm_user_mapping) 97*5461fc0cSDmitry Safonov }; 98*5461fc0cSDmitry Safonov 99*5461fc0cSDmitry Safonov static struct nlmsghdr *xfrm_nlmsg_put_compat(struct sk_buff *skb, 100*5461fc0cSDmitry Safonov const struct nlmsghdr *nlh_src, u16 type) 101*5461fc0cSDmitry Safonov { 102*5461fc0cSDmitry Safonov int payload = compat_msg_min[type]; 103*5461fc0cSDmitry Safonov int src_len = xfrm_msg_min[type]; 104*5461fc0cSDmitry Safonov struct nlmsghdr *nlh_dst; 105*5461fc0cSDmitry Safonov 106*5461fc0cSDmitry Safonov /* Compat messages are shorter or equal to native (+padding) */ 107*5461fc0cSDmitry Safonov if (WARN_ON_ONCE(src_len < payload)) 108*5461fc0cSDmitry Safonov return ERR_PTR(-EMSGSIZE); 109*5461fc0cSDmitry Safonov 110*5461fc0cSDmitry Safonov nlh_dst = nlmsg_put(skb, nlh_src->nlmsg_pid, nlh_src->nlmsg_seq, 111*5461fc0cSDmitry Safonov nlh_src->nlmsg_type, payload, nlh_src->nlmsg_flags); 112*5461fc0cSDmitry Safonov if (!nlh_dst) 113*5461fc0cSDmitry Safonov return ERR_PTR(-EMSGSIZE); 114*5461fc0cSDmitry Safonov 115*5461fc0cSDmitry Safonov memset(nlmsg_data(nlh_dst), 0, payload); 116*5461fc0cSDmitry Safonov 117*5461fc0cSDmitry Safonov switch (nlh_src->nlmsg_type) { 118*5461fc0cSDmitry Safonov /* Compat message has the same layout as native */ 119*5461fc0cSDmitry Safonov case XFRM_MSG_DELSA: 120*5461fc0cSDmitry Safonov case XFRM_MSG_DELPOLICY: 121*5461fc0cSDmitry Safonov case XFRM_MSG_FLUSHSA: 122*5461fc0cSDmitry Safonov case XFRM_MSG_FLUSHPOLICY: 123*5461fc0cSDmitry Safonov case XFRM_MSG_NEWAE: 124*5461fc0cSDmitry Safonov case XFRM_MSG_REPORT: 125*5461fc0cSDmitry Safonov case XFRM_MSG_MIGRATE: 126*5461fc0cSDmitry Safonov case XFRM_MSG_NEWSADINFO: 127*5461fc0cSDmitry Safonov case XFRM_MSG_NEWSPDINFO: 128*5461fc0cSDmitry Safonov case XFRM_MSG_MAPPING: 129*5461fc0cSDmitry Safonov WARN_ON_ONCE(src_len != payload); 130*5461fc0cSDmitry Safonov memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), src_len); 131*5461fc0cSDmitry Safonov break; 132*5461fc0cSDmitry Safonov /* 4 byte alignment for trailing u64 on native, but not on compat */ 133*5461fc0cSDmitry Safonov case XFRM_MSG_NEWSA: 134*5461fc0cSDmitry Safonov case XFRM_MSG_NEWPOLICY: 135*5461fc0cSDmitry Safonov case XFRM_MSG_UPDSA: 136*5461fc0cSDmitry Safonov case XFRM_MSG_UPDPOLICY: 137*5461fc0cSDmitry Safonov WARN_ON_ONCE(src_len != payload + 4); 138*5461fc0cSDmitry Safonov memcpy(nlmsg_data(nlh_dst), nlmsg_data(nlh_src), payload); 139*5461fc0cSDmitry Safonov break; 140*5461fc0cSDmitry Safonov case XFRM_MSG_EXPIRE: { 141*5461fc0cSDmitry Safonov const struct xfrm_user_expire *src_ue = nlmsg_data(nlh_src); 142*5461fc0cSDmitry Safonov struct compat_xfrm_user_expire *dst_ue = nlmsg_data(nlh_dst); 143*5461fc0cSDmitry Safonov 144*5461fc0cSDmitry Safonov /* compat_xfrm_user_expire has 4-byte smaller state */ 145*5461fc0cSDmitry Safonov memcpy(dst_ue, src_ue, sizeof(dst_ue->state)); 146*5461fc0cSDmitry Safonov dst_ue->hard = src_ue->hard; 147*5461fc0cSDmitry Safonov break; 148*5461fc0cSDmitry Safonov } 149*5461fc0cSDmitry Safonov case XFRM_MSG_ACQUIRE: { 150*5461fc0cSDmitry Safonov const struct xfrm_user_acquire *src_ua = nlmsg_data(nlh_src); 151*5461fc0cSDmitry Safonov struct compat_xfrm_user_acquire *dst_ua = nlmsg_data(nlh_dst); 152*5461fc0cSDmitry Safonov 153*5461fc0cSDmitry Safonov memcpy(dst_ua, src_ua, offsetof(struct compat_xfrm_user_acquire, aalgos)); 154*5461fc0cSDmitry Safonov dst_ua->aalgos = src_ua->aalgos; 155*5461fc0cSDmitry Safonov dst_ua->ealgos = src_ua->ealgos; 156*5461fc0cSDmitry Safonov dst_ua->calgos = src_ua->calgos; 157*5461fc0cSDmitry Safonov dst_ua->seq = src_ua->seq; 158*5461fc0cSDmitry Safonov break; 159*5461fc0cSDmitry Safonov } 160*5461fc0cSDmitry Safonov case XFRM_MSG_POLEXPIRE: { 161*5461fc0cSDmitry Safonov const struct xfrm_user_polexpire *src_upe = nlmsg_data(nlh_src); 162*5461fc0cSDmitry Safonov struct compat_xfrm_user_polexpire *dst_upe = nlmsg_data(nlh_dst); 163*5461fc0cSDmitry Safonov 164*5461fc0cSDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 165*5461fc0cSDmitry Safonov memcpy(dst_upe, src_upe, sizeof(dst_upe->pol)); 166*5461fc0cSDmitry Safonov dst_upe->hard = src_upe->hard; 167*5461fc0cSDmitry Safonov break; 168*5461fc0cSDmitry Safonov } 169*5461fc0cSDmitry Safonov case XFRM_MSG_ALLOCSPI: { 170*5461fc0cSDmitry Safonov const struct xfrm_userspi_info *src_usi = nlmsg_data(nlh_src); 171*5461fc0cSDmitry Safonov struct compat_xfrm_userspi_info *dst_usi = nlmsg_data(nlh_dst); 172*5461fc0cSDmitry Safonov 173*5461fc0cSDmitry Safonov /* compat_xfrm_user_polexpire has 4-byte smaller state */ 174*5461fc0cSDmitry Safonov memcpy(dst_usi, src_usi, sizeof(src_usi->info)); 175*5461fc0cSDmitry Safonov dst_usi->min = src_usi->min; 176*5461fc0cSDmitry Safonov dst_usi->max = src_usi->max; 177*5461fc0cSDmitry Safonov break; 178*5461fc0cSDmitry Safonov } 179*5461fc0cSDmitry Safonov /* Not being sent by kernel */ 180*5461fc0cSDmitry Safonov case XFRM_MSG_GETSA: 181*5461fc0cSDmitry Safonov case XFRM_MSG_GETPOLICY: 182*5461fc0cSDmitry Safonov case XFRM_MSG_GETAE: 183*5461fc0cSDmitry Safonov case XFRM_MSG_GETSADINFO: 184*5461fc0cSDmitry Safonov case XFRM_MSG_GETSPDINFO: 185*5461fc0cSDmitry Safonov default: 186*5461fc0cSDmitry Safonov WARN_ONCE(1, "unsupported nlmsg_type %d", nlh_src->nlmsg_type); 187*5461fc0cSDmitry Safonov return ERR_PTR(-EOPNOTSUPP); 188*5461fc0cSDmitry Safonov } 189*5461fc0cSDmitry Safonov 190*5461fc0cSDmitry Safonov return nlh_dst; 191*5461fc0cSDmitry Safonov } 192*5461fc0cSDmitry Safonov 193*5461fc0cSDmitry Safonov static int xfrm_nla_cpy(struct sk_buff *dst, const struct nlattr *src, int len) 194*5461fc0cSDmitry Safonov { 195*5461fc0cSDmitry Safonov return nla_put(dst, src->nla_type, len, nla_data(src)); 196*5461fc0cSDmitry Safonov } 197*5461fc0cSDmitry Safonov 198*5461fc0cSDmitry Safonov static int xfrm_xlate64_attr(struct sk_buff *dst, const struct nlattr *src) 199*5461fc0cSDmitry Safonov { 200*5461fc0cSDmitry Safonov switch (src->nla_type) { 201*5461fc0cSDmitry Safonov case XFRMA_PAD: 202*5461fc0cSDmitry Safonov /* Ignore */ 203*5461fc0cSDmitry Safonov return 0; 204*5461fc0cSDmitry Safonov case XFRMA_ALG_AUTH: 205*5461fc0cSDmitry Safonov case XFRMA_ALG_CRYPT: 206*5461fc0cSDmitry Safonov case XFRMA_ALG_COMP: 207*5461fc0cSDmitry Safonov case XFRMA_ENCAP: 208*5461fc0cSDmitry Safonov case XFRMA_TMPL: 209*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 210*5461fc0cSDmitry Safonov case XFRMA_SA: 211*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_usersa_info)); 212*5461fc0cSDmitry Safonov case XFRMA_POLICY: 213*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, XMSGSIZE(compat_xfrm_userpolicy_info)); 214*5461fc0cSDmitry Safonov case XFRMA_SEC_CTX: 215*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 216*5461fc0cSDmitry Safonov case XFRMA_LTIME_VAL: 217*5461fc0cSDmitry Safonov return nla_put_64bit(dst, src->nla_type, nla_len(src), 218*5461fc0cSDmitry Safonov nla_data(src), XFRMA_PAD); 219*5461fc0cSDmitry Safonov case XFRMA_REPLAY_VAL: 220*5461fc0cSDmitry Safonov case XFRMA_REPLAY_THRESH: 221*5461fc0cSDmitry Safonov case XFRMA_ETIMER_THRESH: 222*5461fc0cSDmitry Safonov case XFRMA_SRCADDR: 223*5461fc0cSDmitry Safonov case XFRMA_COADDR: 224*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 225*5461fc0cSDmitry Safonov case XFRMA_LASTUSED: 226*5461fc0cSDmitry Safonov return nla_put_64bit(dst, src->nla_type, nla_len(src), 227*5461fc0cSDmitry Safonov nla_data(src), XFRMA_PAD); 228*5461fc0cSDmitry Safonov case XFRMA_POLICY_TYPE: 229*5461fc0cSDmitry Safonov case XFRMA_MIGRATE: 230*5461fc0cSDmitry Safonov case XFRMA_ALG_AEAD: 231*5461fc0cSDmitry Safonov case XFRMA_KMADDRESS: 232*5461fc0cSDmitry Safonov case XFRMA_ALG_AUTH_TRUNC: 233*5461fc0cSDmitry Safonov case XFRMA_MARK: 234*5461fc0cSDmitry Safonov case XFRMA_TFCPAD: 235*5461fc0cSDmitry Safonov case XFRMA_REPLAY_ESN_VAL: 236*5461fc0cSDmitry Safonov case XFRMA_SA_EXTRA_FLAGS: 237*5461fc0cSDmitry Safonov case XFRMA_PROTO: 238*5461fc0cSDmitry Safonov case XFRMA_ADDRESS_FILTER: 239*5461fc0cSDmitry Safonov case XFRMA_OFFLOAD_DEV: 240*5461fc0cSDmitry Safonov case XFRMA_SET_MARK: 241*5461fc0cSDmitry Safonov case XFRMA_SET_MARK_MASK: 242*5461fc0cSDmitry Safonov case XFRMA_IF_ID: 243*5461fc0cSDmitry Safonov return xfrm_nla_cpy(dst, src, nla_len(src)); 244*5461fc0cSDmitry Safonov default: 245*5461fc0cSDmitry Safonov BUILD_BUG_ON(XFRMA_MAX != XFRMA_IF_ID); 246*5461fc0cSDmitry Safonov WARN_ONCE(1, "unsupported nla_type %d", src->nla_type); 247*5461fc0cSDmitry Safonov return -EOPNOTSUPP; 248*5461fc0cSDmitry Safonov } 249*5461fc0cSDmitry Safonov } 250*5461fc0cSDmitry Safonov 251*5461fc0cSDmitry Safonov /* Take kernel-built (64bit layout) and create 32bit layout for userspace */ 252*5461fc0cSDmitry Safonov static int xfrm_xlate64(struct sk_buff *dst, const struct nlmsghdr *nlh_src) 253*5461fc0cSDmitry Safonov { 254*5461fc0cSDmitry Safonov u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE; 255*5461fc0cSDmitry Safonov const struct nlattr *nla, *attrs; 256*5461fc0cSDmitry Safonov struct nlmsghdr *nlh_dst; 257*5461fc0cSDmitry Safonov int len, remaining; 258*5461fc0cSDmitry Safonov 259*5461fc0cSDmitry Safonov nlh_dst = xfrm_nlmsg_put_compat(dst, nlh_src, type); 260*5461fc0cSDmitry Safonov if (IS_ERR(nlh_dst)) 261*5461fc0cSDmitry Safonov return PTR_ERR(nlh_dst); 262*5461fc0cSDmitry Safonov 263*5461fc0cSDmitry Safonov attrs = nlmsg_attrdata(nlh_src, xfrm_msg_min[type]); 264*5461fc0cSDmitry Safonov len = nlmsg_attrlen(nlh_src, xfrm_msg_min[type]); 265*5461fc0cSDmitry Safonov 266*5461fc0cSDmitry Safonov nla_for_each_attr(nla, attrs, len, remaining) { 267*5461fc0cSDmitry Safonov int err = xfrm_xlate64_attr(dst, nla); 268*5461fc0cSDmitry Safonov 269*5461fc0cSDmitry Safonov if (err) 270*5461fc0cSDmitry Safonov return err; 271*5461fc0cSDmitry Safonov } 272*5461fc0cSDmitry Safonov 273*5461fc0cSDmitry Safonov nlmsg_end(dst, nlh_dst); 274*5461fc0cSDmitry Safonov 275*5461fc0cSDmitry Safonov return 0; 276*5461fc0cSDmitry Safonov } 277*5461fc0cSDmitry Safonov 278*5461fc0cSDmitry Safonov static int xfrm_alloc_compat(struct sk_buff *skb, const struct nlmsghdr *nlh_src) 279*5461fc0cSDmitry Safonov { 280*5461fc0cSDmitry Safonov u16 type = nlh_src->nlmsg_type - XFRM_MSG_BASE; 281*5461fc0cSDmitry Safonov struct sk_buff *new = NULL; 282*5461fc0cSDmitry Safonov int err; 283*5461fc0cSDmitry Safonov 284*5461fc0cSDmitry Safonov if (WARN_ON_ONCE(type >= ARRAY_SIZE(xfrm_msg_min))) 285*5461fc0cSDmitry Safonov return -EOPNOTSUPP; 286*5461fc0cSDmitry Safonov 287*5461fc0cSDmitry Safonov if (skb_shinfo(skb)->frag_list == NULL) { 288*5461fc0cSDmitry Safonov new = alloc_skb(skb->len + skb_tailroom(skb), GFP_ATOMIC); 289*5461fc0cSDmitry Safonov if (!new) 290*5461fc0cSDmitry Safonov return -ENOMEM; 291*5461fc0cSDmitry Safonov skb_shinfo(skb)->frag_list = new; 292*5461fc0cSDmitry Safonov } 293*5461fc0cSDmitry Safonov 294*5461fc0cSDmitry Safonov err = xfrm_xlate64(skb_shinfo(skb)->frag_list, nlh_src); 295*5461fc0cSDmitry Safonov if (err) { 296*5461fc0cSDmitry Safonov if (new) { 297*5461fc0cSDmitry Safonov kfree_skb(new); 298*5461fc0cSDmitry Safonov skb_shinfo(skb)->frag_list = NULL; 299*5461fc0cSDmitry Safonov } 300*5461fc0cSDmitry Safonov return err; 301*5461fc0cSDmitry Safonov } 302*5461fc0cSDmitry Safonov 303*5461fc0cSDmitry Safonov return 0; 304*5461fc0cSDmitry Safonov } 305*5461fc0cSDmitry Safonov 306c9e7c76dSDmitry Safonov static struct xfrm_translator xfrm_translator = { 307c9e7c76dSDmitry Safonov .owner = THIS_MODULE, 308*5461fc0cSDmitry Safonov .alloc_compat = xfrm_alloc_compat, 309c9e7c76dSDmitry Safonov }; 310c9e7c76dSDmitry Safonov 311c9e7c76dSDmitry Safonov static int __init xfrm_compat_init(void) 312c9e7c76dSDmitry Safonov { 313c9e7c76dSDmitry Safonov return xfrm_register_translator(&xfrm_translator); 314c9e7c76dSDmitry Safonov } 315c9e7c76dSDmitry Safonov 316c9e7c76dSDmitry Safonov static void __exit xfrm_compat_exit(void) 317c9e7c76dSDmitry Safonov { 318c9e7c76dSDmitry Safonov xfrm_unregister_translator(&xfrm_translator); 319c9e7c76dSDmitry Safonov } 320c9e7c76dSDmitry Safonov 321c9e7c76dSDmitry Safonov module_init(xfrm_compat_init); 322c9e7c76dSDmitry Safonov module_exit(xfrm_compat_exit); 323c9e7c76dSDmitry Safonov MODULE_LICENSE("GPL"); 324c9e7c76dSDmitry Safonov MODULE_AUTHOR("Dmitry Safonov"); 325c9e7c76dSDmitry Safonov MODULE_DESCRIPTION("XFRM 32-bit compatibility layer"); 326