11da177e4SLinus Torvalds /* 21da177e4SLinus Torvalds * xfrm4_policy.c 31da177e4SLinus Torvalds * 41da177e4SLinus Torvalds * Changes: 51da177e4SLinus Torvalds * Kazunori MIYAZAWA @USAGI 61da177e4SLinus Torvalds * YOSHIFUJI Hideaki @USAGI 71da177e4SLinus Torvalds * Split up af-specific portion 81da177e4SLinus Torvalds * 91da177e4SLinus Torvalds */ 101da177e4SLinus Torvalds 1166cdb3caSHerbert Xu #include <linux/err.h> 1266cdb3caSHerbert Xu #include <linux/kernel.h> 13aabc9761SHerbert Xu #include <linux/inetdevice.h> 14cc9ff19dSTimo Teräs #include <linux/if_tunnel.h> 1545ff5a3fSHerbert Xu #include <net/dst.h> 161da177e4SLinus Torvalds #include <net/xfrm.h> 171da177e4SLinus Torvalds #include <net/ip.h> 18385add90SDavid Ahern #include <net/l3mdev.h> 191da177e4SLinus Torvalds 208f01cb08SDavid S. Miller static struct dst_entry *__xfrm4_dst_lookup(struct net *net, struct flowi4 *fl4, 2142a7b32bSDavid Ahern int tos, int oif, 225e6b930fSDavid S. Miller const xfrm_address_t *saddr, 23*077fbac4SLorenzo Colitti const xfrm_address_t *daddr, 24*077fbac4SLorenzo Colitti u32 mark) 251da177e4SLinus Torvalds { 2666cdb3caSHerbert Xu struct rtable *rt; 27a1e59abfSPatrick McHardy 288f01cb08SDavid S. Miller memset(fl4, 0, sizeof(*fl4)); 298f01cb08SDavid S. Miller fl4->daddr = daddr->a4; 308f01cb08SDavid S. Miller fl4->flowi4_tos = tos; 3111d7a0bbSDavid Ahern fl4->flowi4_oif = l3mdev_master_ifindex_by_index(net, oif); 32*077fbac4SLorenzo Colitti fl4->flowi4_mark = mark; 3366cdb3caSHerbert Xu if (saddr) 348f01cb08SDavid S. Miller fl4->saddr = saddr->a4; 3566cdb3caSHerbert Xu 3658189ca7SDavid Ahern fl4->flowi4_flags = FLOWI_FLAG_SKIP_NH_OIF; 3758189ca7SDavid Ahern 388f01cb08SDavid S. Miller rt = __ip_route_output_key(net, fl4); 39b23dd4feSDavid S. Miller if (!IS_ERR(rt)) 40b23dd4feSDavid S. Miller return &rt->dst; 41b23dd4feSDavid S. Miller 42b23dd4feSDavid S. Miller return ERR_CAST(rt); 43a1e59abfSPatrick McHardy } 4466cdb3caSHerbert Xu 4542a7b32bSDavid Ahern static struct dst_entry *xfrm4_dst_lookup(struct net *net, int tos, int oif, 468f01cb08SDavid S. Miller const xfrm_address_t *saddr, 47*077fbac4SLorenzo Colitti const xfrm_address_t *daddr, 48*077fbac4SLorenzo Colitti u32 mark) 498f01cb08SDavid S. Miller { 508f01cb08SDavid S. Miller struct flowi4 fl4; 518f01cb08SDavid S. Miller 52*077fbac4SLorenzo Colitti return __xfrm4_dst_lookup(net, &fl4, tos, oif, saddr, daddr, mark); 538f01cb08SDavid S. Miller } 548f01cb08SDavid S. Miller 5542a7b32bSDavid Ahern static int xfrm4_get_saddr(struct net *net, int oif, 56*077fbac4SLorenzo Colitti xfrm_address_t *saddr, xfrm_address_t *daddr, 57*077fbac4SLorenzo Colitti u32 mark) 5866cdb3caSHerbert Xu { 5966cdb3caSHerbert Xu struct dst_entry *dst; 608f01cb08SDavid S. Miller struct flowi4 fl4; 6166cdb3caSHerbert Xu 62*077fbac4SLorenzo Colitti dst = __xfrm4_dst_lookup(net, &fl4, 0, oif, NULL, daddr, mark); 6366cdb3caSHerbert Xu if (IS_ERR(dst)) 64a1e59abfSPatrick McHardy return -EHOSTUNREACH; 6566cdb3caSHerbert Xu 668f01cb08SDavid S. Miller saddr->a4 = fl4.saddr; 6766cdb3caSHerbert Xu dst_release(dst); 6866cdb3caSHerbert Xu return 0; 69a1e59abfSPatrick McHardy } 70a1e59abfSPatrick McHardy 7105d84025SDavid S. Miller static int xfrm4_get_tos(const struct flowi *fl) 721da177e4SLinus Torvalds { 737e1dc7b6SDavid S. Miller return IPTOS_RT_MASK & fl->u.ip4.flowi4_tos; /* Strip ECN bits */ 741da177e4SLinus Torvalds } 751da177e4SLinus Torvalds 76a1b05140SMasahide NAKAMURA static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, 77a1b05140SMasahide NAKAMURA int nfheader_len) 78a1b05140SMasahide NAKAMURA { 79a1b05140SMasahide NAKAMURA return 0; 80a1b05140SMasahide NAKAMURA } 81a1b05140SMasahide NAKAMURA 8287c1e12bSHerbert Xu static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev, 830c7b3eefSDavid S. Miller const struct flowi *fl) 8425ee3286SHerbert Xu { 8525ee3286SHerbert Xu struct rtable *rt = (struct rtable *)xdst->route; 867e1dc7b6SDavid S. Miller const struct flowi4 *fl4 = &fl->u.ip4; 871da177e4SLinus Torvalds 88b7323396SYan, Zheng xdst->u.rt.rt_iif = fl4->flowi4_iif; 891da177e4SLinus Torvalds 9025ee3286SHerbert Xu xdst->u.dst.dev = dev; 9125ee3286SHerbert Xu dev_hold(dev); 9243372262SMiika Komu 931da177e4SLinus Torvalds /* Sheit... I remember I did this right. Apparently, 941da177e4SLinus Torvalds * it was magically lost, so this code needs audit */ 959917e1e8SDavid S. Miller xdst->u.rt.rt_is_input = rt->rt_is_input; 9625ee3286SHerbert Xu xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | 9725ee3286SHerbert Xu RTCF_LOCAL); 9825ee3286SHerbert Xu xdst->u.rt.rt_type = rt->rt_type; 9925ee3286SHerbert Xu xdst->u.rt.rt_gateway = rt->rt_gateway; 100155e8336SJulian Anastasov xdst->u.rt.rt_uses_gateway = rt->rt_uses_gateway; 1015943634fSDavid S. Miller xdst->u.rt.rt_pmtu = rt->rt_pmtu; 102b7503e0cSDavid Ahern xdst->u.rt.rt_table_id = rt->rt_table_id; 103caacf05eSDavid S. Miller INIT_LIST_HEAD(&xdst->u.rt.rt_uncached); 1041da177e4SLinus Torvalds 1051da177e4SLinus Torvalds return 0; 1061da177e4SLinus Torvalds } 1071da177e4SLinus Torvalds 1081da177e4SLinus Torvalds static void 109d5422efeSHerbert Xu _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) 1101da177e4SLinus Torvalds { 111b71d1d42SEric Dumazet const struct iphdr *iph = ip_hdr(skb); 112d56f90a7SArnaldo Carvalho de Melo u8 *xprth = skb_network_header(skb) + iph->ihl * 4; 1137e1dc7b6SDavid S. Miller struct flowi4 *fl4 = &fl->u.ip4; 11484502b5eSSteffen Klassert int oif = 0; 11584502b5eSSteffen Klassert 116385add90SDavid Ahern if (skb_dst(skb)) 117e0d56fddSDavid Ahern oif = skb_dst(skb)->dev->ifindex; 1181da177e4SLinus Torvalds 1197e1dc7b6SDavid S. Miller memset(fl4, 0, sizeof(struct flowi4)); 1207e1dc7b6SDavid S. Miller fl4->flowi4_mark = skb->mark; 12184502b5eSSteffen Klassert fl4->flowi4_oif = reverse ? skb->skb_iif : oif; 12244b451f1SPeter Kosyh 12356f8a75cSPaul Gortmaker if (!ip_is_fragment(iph)) { 1241da177e4SLinus Torvalds switch (iph->protocol) { 1251da177e4SLinus Torvalds case IPPROTO_UDP: 126ba4e58ecSGerrit Renker case IPPROTO_UDPLITE: 1271da177e4SLinus Torvalds case IPPROTO_TCP: 1281da177e4SLinus Torvalds case IPPROTO_SCTP: 1299e999993SPatrick McHardy case IPPROTO_DCCP: 130c615c9f3SWei Yongjun if (xprth + 4 < skb->data || 131c615c9f3SWei Yongjun pskb_may_pull(skb, xprth + 4 - skb->data)) { 132ea673a4dSSteffen Klassert __be16 *ports; 133ea673a4dSSteffen Klassert 134ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 135ea673a4dSSteffen Klassert ports = (__be16 *)xprth; 1361da177e4SLinus Torvalds 1379cce96dfSDavid S. Miller fl4->fl4_sport = ports[!!reverse]; 1389cce96dfSDavid S. Miller fl4->fl4_dport = ports[!reverse]; 1391da177e4SLinus Torvalds } 1401da177e4SLinus Torvalds break; 1411da177e4SLinus Torvalds 1421da177e4SLinus Torvalds case IPPROTO_ICMP: 1431a14f1e5SSteffen Klassert if (xprth + 2 < skb->data || 1441a14f1e5SSteffen Klassert pskb_may_pull(skb, xprth + 2 - skb->data)) { 145ea673a4dSSteffen Klassert u8 *icmp; 146ea673a4dSSteffen Klassert 147ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 148ea673a4dSSteffen Klassert icmp = xprth; 1491da177e4SLinus Torvalds 1509cce96dfSDavid S. Miller fl4->fl4_icmp_type = icmp[0]; 1519cce96dfSDavid S. Miller fl4->fl4_icmp_code = icmp[1]; 1521da177e4SLinus Torvalds } 1531da177e4SLinus Torvalds break; 1541da177e4SLinus Torvalds 1551da177e4SLinus Torvalds case IPPROTO_ESP: 1561a14f1e5SSteffen Klassert if (xprth + 4 < skb->data || 1571a14f1e5SSteffen Klassert pskb_may_pull(skb, xprth + 4 - skb->data)) { 158ea673a4dSSteffen Klassert __be32 *ehdr; 159ea673a4dSSteffen Klassert 160ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 161ea673a4dSSteffen Klassert ehdr = (__be32 *)xprth; 1621da177e4SLinus Torvalds 1639cce96dfSDavid S. Miller fl4->fl4_ipsec_spi = ehdr[0]; 1641da177e4SLinus Torvalds } 1651da177e4SLinus Torvalds break; 1661da177e4SLinus Torvalds 1671da177e4SLinus Torvalds case IPPROTO_AH: 1681a14f1e5SSteffen Klassert if (xprth + 8 < skb->data || 1691a14f1e5SSteffen Klassert pskb_may_pull(skb, xprth + 8 - skb->data)) { 170ea673a4dSSteffen Klassert __be32 *ah_hdr; 171ea673a4dSSteffen Klassert 172ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 173ea673a4dSSteffen Klassert ah_hdr = (__be32 *)xprth; 1741da177e4SLinus Torvalds 1759cce96dfSDavid S. Miller fl4->fl4_ipsec_spi = ah_hdr[1]; 1761da177e4SLinus Torvalds } 1771da177e4SLinus Torvalds break; 1781da177e4SLinus Torvalds 1791da177e4SLinus Torvalds case IPPROTO_COMP: 1801a14f1e5SSteffen Klassert if (xprth + 4 < skb->data || 1811a14f1e5SSteffen Klassert pskb_may_pull(skb, xprth + 4 - skb->data)) { 182ea673a4dSSteffen Klassert __be16 *ipcomp_hdr; 183ea673a4dSSteffen Klassert 184ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 185ea673a4dSSteffen Klassert ipcomp_hdr = (__be16 *)xprth; 1861da177e4SLinus Torvalds 1879cce96dfSDavid S. Miller fl4->fl4_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); 1881da177e4SLinus Torvalds } 1891da177e4SLinus Torvalds break; 190cc9ff19dSTimo Teräs 191cc9ff19dSTimo Teräs case IPPROTO_GRE: 1921a14f1e5SSteffen Klassert if (xprth + 12 < skb->data || 1931a14f1e5SSteffen Klassert pskb_may_pull(skb, xprth + 12 - skb->data)) { 194ea673a4dSSteffen Klassert __be16 *greflags; 195ea673a4dSSteffen Klassert __be32 *gre_hdr; 196ea673a4dSSteffen Klassert 197ea673a4dSSteffen Klassert xprth = skb_network_header(skb) + iph->ihl * 4; 198ea673a4dSSteffen Klassert greflags = (__be16 *)xprth; 199ea673a4dSSteffen Klassert gre_hdr = (__be32 *)xprth; 200cc9ff19dSTimo Teräs 201cc9ff19dSTimo Teräs if (greflags[0] & GRE_KEY) { 202cc9ff19dSTimo Teräs if (greflags[0] & GRE_CSUM) 203cc9ff19dSTimo Teräs gre_hdr++; 2049cce96dfSDavid S. Miller fl4->fl4_gre_key = gre_hdr[1]; 205cc9ff19dSTimo Teräs } 206cc9ff19dSTimo Teräs } 207cc9ff19dSTimo Teräs break; 208cc9ff19dSTimo Teräs 2091da177e4SLinus Torvalds default: 2109cce96dfSDavid S. Miller fl4->fl4_ipsec_spi = 0; 2111da177e4SLinus Torvalds break; 2123ff50b79SStephen Hemminger } 2131da177e4SLinus Torvalds } 2147e1dc7b6SDavid S. Miller fl4->flowi4_proto = iph->protocol; 2157e1dc7b6SDavid S. Miller fl4->daddr = reverse ? iph->saddr : iph->daddr; 2167e1dc7b6SDavid S. Miller fl4->saddr = reverse ? iph->daddr : iph->saddr; 2177e1dc7b6SDavid S. Miller fl4->flowi4_tos = iph->tos; 2181da177e4SLinus Torvalds } 2191da177e4SLinus Torvalds 2206700c270SDavid S. Miller static void xfrm4_update_pmtu(struct dst_entry *dst, struct sock *sk, 2216700c270SDavid S. Miller struct sk_buff *skb, u32 mtu) 2221da177e4SLinus Torvalds { 2231da177e4SLinus Torvalds struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 2241da177e4SLinus Torvalds struct dst_entry *path = xdst->route; 2251da177e4SLinus Torvalds 2266700c270SDavid S. Miller path->ops->update_pmtu(path, sk, skb, mtu); 2271da177e4SLinus Torvalds } 2281da177e4SLinus Torvalds 2296700c270SDavid S. Miller static void xfrm4_redirect(struct dst_entry *dst, struct sock *sk, 2306700c270SDavid S. Miller struct sk_buff *skb) 23155be7a9cSDavid S. Miller { 23255be7a9cSDavid S. Miller struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 23355be7a9cSDavid S. Miller struct dst_entry *path = xdst->route; 23455be7a9cSDavid S. Miller 2356700c270SDavid S. Miller path->ops->redirect(path, sk, skb); 23655be7a9cSDavid S. Miller } 23755be7a9cSDavid S. Miller 238aabc9761SHerbert Xu static void xfrm4_dst_destroy(struct dst_entry *dst) 239aabc9761SHerbert Xu { 240aabc9761SHerbert Xu struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 241aabc9761SHerbert Xu 24262fa8a84SDavid S. Miller dst_destroy_metrics_generic(dst); 24362fa8a84SDavid S. Miller 244aabc9761SHerbert Xu xfrm_dst_destroy(xdst); 245aabc9761SHerbert Xu } 246aabc9761SHerbert Xu 247aabc9761SHerbert Xu static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 248aabc9761SHerbert Xu int unregister) 249aabc9761SHerbert Xu { 250aabc9761SHerbert Xu if (!unregister) 251aabc9761SHerbert Xu return; 252aabc9761SHerbert Xu 253aabc9761SHerbert Xu xfrm_dst_ifdown(dst, dev); 254aabc9761SHerbert Xu } 255aabc9761SHerbert Xu 256a8a572a6SDan Streetman static struct dst_ops xfrm4_dst_ops_template = { 2571da177e4SLinus Torvalds .family = AF_INET, 2581da177e4SLinus Torvalds .update_pmtu = xfrm4_update_pmtu, 25955be7a9cSDavid S. Miller .redirect = xfrm4_redirect, 26062fa8a84SDavid S. Miller .cow_metrics = dst_cow_metrics_generic, 261aabc9761SHerbert Xu .destroy = xfrm4_dst_destroy, 262aabc9761SHerbert Xu .ifdown = xfrm4_dst_ifdown, 263862b82c6SHerbert Xu .local_out = __ip_local_out, 2643c2a89ddSFlorian Westphal .gc_thresh = 32768, 2651da177e4SLinus Torvalds }; 2661da177e4SLinus Torvalds 26737b10383SFlorian Westphal static const struct xfrm_policy_afinfo xfrm4_policy_afinfo = { 268a8a572a6SDan Streetman .dst_ops = &xfrm4_dst_ops_template, 2691da177e4SLinus Torvalds .dst_lookup = xfrm4_dst_lookup, 270a1e59abfSPatrick McHardy .get_saddr = xfrm4_get_saddr, 2711da177e4SLinus Torvalds .decode_session = _decode_session4, 27225ee3286SHerbert Xu .get_tos = xfrm4_get_tos, 273a1b05140SMasahide NAKAMURA .init_path = xfrm4_init_path, 27425ee3286SHerbert Xu .fill_dst = xfrm4_fill_dst, 2752774c131SDavid S. Miller .blackhole_route = ipv4_blackhole_route, 2761da177e4SLinus Torvalds }; 2771da177e4SLinus Torvalds 278f816700aSRandy Dunlap #ifdef CONFIG_SYSCTL 279a44a4a00SNeil Horman static struct ctl_table xfrm4_policy_table[] = { 280a44a4a00SNeil Horman { 281a44a4a00SNeil Horman .procname = "xfrm4_gc_thresh", 282d7c7544cSAlexey Dobriyan .data = &init_net.xfrm.xfrm4_dst_ops.gc_thresh, 283a44a4a00SNeil Horman .maxlen = sizeof(int), 284a44a4a00SNeil Horman .mode = 0644, 285a44a4a00SNeil Horman .proc_handler = proc_dointvec, 286a44a4a00SNeil Horman }, 287a44a4a00SNeil Horman { } 288a44a4a00SNeil Horman }; 289a44a4a00SNeil Horman 290318d3cc0SArnd Bergmann static __net_init int xfrm4_net_sysctl_init(struct net *net) 2918d068875SMichal Kubecek { 2928d068875SMichal Kubecek struct ctl_table *table; 2938d068875SMichal Kubecek struct ctl_table_header *hdr; 2948d068875SMichal Kubecek 2958d068875SMichal Kubecek table = xfrm4_policy_table; 2968d068875SMichal Kubecek if (!net_eq(net, &init_net)) { 2978d068875SMichal Kubecek table = kmemdup(table, sizeof(xfrm4_policy_table), GFP_KERNEL); 2988d068875SMichal Kubecek if (!table) 2998d068875SMichal Kubecek goto err_alloc; 3008d068875SMichal Kubecek 3018d068875SMichal Kubecek table[0].data = &net->xfrm.xfrm4_dst_ops.gc_thresh; 3028d068875SMichal Kubecek } 3038d068875SMichal Kubecek 3048d068875SMichal Kubecek hdr = register_net_sysctl(net, "net/ipv4", table); 3058d068875SMichal Kubecek if (!hdr) 3068d068875SMichal Kubecek goto err_reg; 3078d068875SMichal Kubecek 3088d068875SMichal Kubecek net->ipv4.xfrm4_hdr = hdr; 3098d068875SMichal Kubecek return 0; 3108d068875SMichal Kubecek 3118d068875SMichal Kubecek err_reg: 3128d068875SMichal Kubecek if (!net_eq(net, &init_net)) 3138d068875SMichal Kubecek kfree(table); 3148d068875SMichal Kubecek err_alloc: 3158d068875SMichal Kubecek return -ENOMEM; 3168d068875SMichal Kubecek } 3178d068875SMichal Kubecek 318318d3cc0SArnd Bergmann static __net_exit void xfrm4_net_sysctl_exit(struct net *net) 3198d068875SMichal Kubecek { 3208d068875SMichal Kubecek struct ctl_table *table; 3218d068875SMichal Kubecek 32251456b29SIan Morris if (!net->ipv4.xfrm4_hdr) 3238d068875SMichal Kubecek return; 3248d068875SMichal Kubecek 3258d068875SMichal Kubecek table = net->ipv4.xfrm4_hdr->ctl_table_arg; 3268d068875SMichal Kubecek unregister_net_sysctl_table(net->ipv4.xfrm4_hdr); 3278d068875SMichal Kubecek if (!net_eq(net, &init_net)) 3288d068875SMichal Kubecek kfree(table); 3298d068875SMichal Kubecek } 330a8a572a6SDan Streetman #else /* CONFIG_SYSCTL */ 331318d3cc0SArnd Bergmann static inline int xfrm4_net_sysctl_init(struct net *net) 332a8a572a6SDan Streetman { 333a8a572a6SDan Streetman return 0; 334a8a572a6SDan Streetman } 335a8a572a6SDan Streetman 336318d3cc0SArnd Bergmann static inline void xfrm4_net_sysctl_exit(struct net *net) 337a8a572a6SDan Streetman { 338a8a572a6SDan Streetman } 339a8a572a6SDan Streetman #endif 340a8a572a6SDan Streetman 341a8a572a6SDan Streetman static int __net_init xfrm4_net_init(struct net *net) 342a8a572a6SDan Streetman { 343a8a572a6SDan Streetman int ret; 344a8a572a6SDan Streetman 345a8a572a6SDan Streetman memcpy(&net->xfrm.xfrm4_dst_ops, &xfrm4_dst_ops_template, 346a8a572a6SDan Streetman sizeof(xfrm4_dst_ops_template)); 347a8a572a6SDan Streetman ret = dst_entries_init(&net->xfrm.xfrm4_dst_ops); 348a8a572a6SDan Streetman if (ret) 349a8a572a6SDan Streetman return ret; 350a8a572a6SDan Streetman 351a8a572a6SDan Streetman ret = xfrm4_net_sysctl_init(net); 352a8a572a6SDan Streetman if (ret) 353a8a572a6SDan Streetman dst_entries_destroy(&net->xfrm.xfrm4_dst_ops); 354a8a572a6SDan Streetman 355a8a572a6SDan Streetman return ret; 356a8a572a6SDan Streetman } 357a8a572a6SDan Streetman 358a8a572a6SDan Streetman static void __net_exit xfrm4_net_exit(struct net *net) 359a8a572a6SDan Streetman { 360a8a572a6SDan Streetman xfrm4_net_sysctl_exit(net); 361a8a572a6SDan Streetman dst_entries_destroy(&net->xfrm.xfrm4_dst_ops); 362a8a572a6SDan Streetman } 3638d068875SMichal Kubecek 3648d068875SMichal Kubecek static struct pernet_operations __net_initdata xfrm4_net_ops = { 3658d068875SMichal Kubecek .init = xfrm4_net_init, 3668d068875SMichal Kubecek .exit = xfrm4_net_exit, 3678d068875SMichal Kubecek }; 368a44a4a00SNeil Horman 3691da177e4SLinus Torvalds static void __init xfrm4_policy_init(void) 3701da177e4SLinus Torvalds { 371a2817d8bSFlorian Westphal xfrm_policy_register_afinfo(&xfrm4_policy_afinfo, AF_INET); 3721da177e4SLinus Torvalds } 3731da177e4SLinus Torvalds 374703fb94eSSteffen Klassert void __init xfrm4_init(void) 3751da177e4SLinus Torvalds { 376d7c7544cSAlexey Dobriyan xfrm4_state_init(); 377d7c7544cSAlexey Dobriyan xfrm4_policy_init(); 3782f32b51bSSteffen Klassert xfrm4_protocol_init(); 3798d068875SMichal Kubecek register_pernet_subsys(&xfrm4_net_ops); 3801da177e4SLinus Torvalds } 3811da177e4SLinus Torvalds 382