1 /* 2 * xfrm4_policy.c 3 * 4 * Changes: 5 * Kazunori MIYAZAWA @USAGI 6 * YOSHIFUJI Hideaki @USAGI 7 * Split up af-specific portion 8 * 9 */ 10 11 #include <linux/err.h> 12 #include <linux/kernel.h> 13 #include <linux/inetdevice.h> 14 #include <net/dst.h> 15 #include <net/xfrm.h> 16 #include <net/ip.h> 17 18 static struct dst_ops xfrm4_dst_ops; 19 static struct xfrm_policy_afinfo xfrm4_policy_afinfo; 20 21 static struct dst_entry *xfrm4_dst_lookup(int tos, xfrm_address_t *saddr, 22 xfrm_address_t *daddr) 23 { 24 struct flowi fl = { 25 .nl_u = { 26 .ip4_u = { 27 .tos = tos, 28 .daddr = daddr->a4, 29 }, 30 }, 31 }; 32 struct dst_entry *dst; 33 struct rtable *rt; 34 int err; 35 36 if (saddr) 37 fl.fl4_src = saddr->a4; 38 39 err = __ip_route_output_key(&init_net, &rt, &fl); 40 dst = &rt->u.dst; 41 if (err) 42 dst = ERR_PTR(err); 43 return dst; 44 } 45 46 static int xfrm4_get_saddr(xfrm_address_t *saddr, xfrm_address_t *daddr) 47 { 48 struct dst_entry *dst; 49 struct rtable *rt; 50 51 dst = xfrm4_dst_lookup(0, NULL, daddr); 52 if (IS_ERR(dst)) 53 return -EHOSTUNREACH; 54 55 rt = (struct rtable *)dst; 56 saddr->a4 = rt->rt_src; 57 dst_release(dst); 58 return 0; 59 } 60 61 static struct dst_entry * 62 __xfrm4_find_bundle(struct flowi *fl, struct xfrm_policy *policy) 63 { 64 struct dst_entry *dst; 65 66 read_lock_bh(&policy->lock); 67 for (dst = policy->bundles; dst; dst = dst->next) { 68 struct xfrm_dst *xdst = (struct xfrm_dst*)dst; 69 if (xdst->u.rt.fl.oif == fl->oif && /*XXX*/ 70 xdst->u.rt.fl.fl4_dst == fl->fl4_dst && 71 xdst->u.rt.fl.fl4_src == fl->fl4_src && 72 xdst->u.rt.fl.fl4_tos == fl->fl4_tos && 73 xfrm_bundle_ok(policy, xdst, fl, AF_INET, 0)) { 74 dst_clone(dst); 75 break; 76 } 77 } 78 read_unlock_bh(&policy->lock); 79 return dst; 80 } 81 82 static int xfrm4_get_tos(struct flowi *fl) 83 { 84 return fl->fl4_tos; 85 } 86 87 static int xfrm4_init_path(struct xfrm_dst *path, struct dst_entry *dst, 88 int nfheader_len) 89 { 90 return 0; 91 } 92 93 static int xfrm4_fill_dst(struct xfrm_dst *xdst, struct net_device *dev) 94 { 95 struct rtable *rt = (struct rtable *)xdst->route; 96 97 xdst->u.rt.fl = rt->fl; 98 99 xdst->u.dst.dev = dev; 100 dev_hold(dev); 101 102 xdst->u.rt.idev = in_dev_get(dev); 103 if (!xdst->u.rt.idev) 104 return -ENODEV; 105 106 xdst->u.rt.peer = rt->peer; 107 if (rt->peer) 108 atomic_inc(&rt->peer->refcnt); 109 110 /* Sheit... I remember I did this right. Apparently, 111 * it was magically lost, so this code needs audit */ 112 xdst->u.rt.rt_flags = rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST | 113 RTCF_LOCAL); 114 xdst->u.rt.rt_type = rt->rt_type; 115 xdst->u.rt.rt_src = rt->rt_src; 116 xdst->u.rt.rt_dst = rt->rt_dst; 117 xdst->u.rt.rt_gateway = rt->rt_gateway; 118 xdst->u.rt.rt_spec_dst = rt->rt_spec_dst; 119 120 return 0; 121 } 122 123 static void 124 _decode_session4(struct sk_buff *skb, struct flowi *fl, int reverse) 125 { 126 struct iphdr *iph = ip_hdr(skb); 127 u8 *xprth = skb_network_header(skb) + iph->ihl * 4; 128 129 memset(fl, 0, sizeof(struct flowi)); 130 if (!(iph->frag_off & htons(IP_MF | IP_OFFSET))) { 131 switch (iph->protocol) { 132 case IPPROTO_UDP: 133 case IPPROTO_UDPLITE: 134 case IPPROTO_TCP: 135 case IPPROTO_SCTP: 136 case IPPROTO_DCCP: 137 if (pskb_may_pull(skb, xprth + 4 - skb->data)) { 138 __be16 *ports = (__be16 *)xprth; 139 140 fl->fl_ip_sport = ports[!!reverse]; 141 fl->fl_ip_dport = ports[!reverse]; 142 } 143 break; 144 145 case IPPROTO_ICMP: 146 if (pskb_may_pull(skb, xprth + 2 - skb->data)) { 147 u8 *icmp = xprth; 148 149 fl->fl_icmp_type = icmp[0]; 150 fl->fl_icmp_code = icmp[1]; 151 } 152 break; 153 154 case IPPROTO_ESP: 155 if (pskb_may_pull(skb, xprth + 4 - skb->data)) { 156 __be32 *ehdr = (__be32 *)xprth; 157 158 fl->fl_ipsec_spi = ehdr[0]; 159 } 160 break; 161 162 case IPPROTO_AH: 163 if (pskb_may_pull(skb, xprth + 8 - skb->data)) { 164 __be32 *ah_hdr = (__be32*)xprth; 165 166 fl->fl_ipsec_spi = ah_hdr[1]; 167 } 168 break; 169 170 case IPPROTO_COMP: 171 if (pskb_may_pull(skb, xprth + 4 - skb->data)) { 172 __be16 *ipcomp_hdr = (__be16 *)xprth; 173 174 fl->fl_ipsec_spi = htonl(ntohs(ipcomp_hdr[1])); 175 } 176 break; 177 default: 178 fl->fl_ipsec_spi = 0; 179 break; 180 } 181 } 182 fl->proto = iph->protocol; 183 fl->fl4_dst = reverse ? iph->saddr : iph->daddr; 184 fl->fl4_src = reverse ? iph->daddr : iph->saddr; 185 fl->fl4_tos = iph->tos; 186 } 187 188 static inline int xfrm4_garbage_collect(struct dst_ops *ops) 189 { 190 xfrm4_policy_afinfo.garbage_collect(); 191 return (atomic_read(&xfrm4_dst_ops.entries) > xfrm4_dst_ops.gc_thresh*2); 192 } 193 194 static void xfrm4_update_pmtu(struct dst_entry *dst, u32 mtu) 195 { 196 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 197 struct dst_entry *path = xdst->route; 198 199 path->ops->update_pmtu(path, mtu); 200 } 201 202 static void xfrm4_dst_destroy(struct dst_entry *dst) 203 { 204 struct xfrm_dst *xdst = (struct xfrm_dst *)dst; 205 206 if (likely(xdst->u.rt.idev)) 207 in_dev_put(xdst->u.rt.idev); 208 if (likely(xdst->u.rt.peer)) 209 inet_putpeer(xdst->u.rt.peer); 210 xfrm_dst_destroy(xdst); 211 } 212 213 static void xfrm4_dst_ifdown(struct dst_entry *dst, struct net_device *dev, 214 int unregister) 215 { 216 struct xfrm_dst *xdst; 217 218 if (!unregister) 219 return; 220 221 xdst = (struct xfrm_dst *)dst; 222 if (xdst->u.rt.idev->dev == dev) { 223 struct in_device *loopback_idev = 224 in_dev_get(dev_net(dev)->loopback_dev); 225 BUG_ON(!loopback_idev); 226 227 do { 228 in_dev_put(xdst->u.rt.idev); 229 xdst->u.rt.idev = loopback_idev; 230 in_dev_hold(loopback_idev); 231 xdst = (struct xfrm_dst *)xdst->u.dst.child; 232 } while (xdst->u.dst.xfrm); 233 234 __in_dev_put(loopback_idev); 235 } 236 237 xfrm_dst_ifdown(dst, dev); 238 } 239 240 static struct dst_ops xfrm4_dst_ops = { 241 .family = AF_INET, 242 .protocol = __constant_htons(ETH_P_IP), 243 .gc = xfrm4_garbage_collect, 244 .update_pmtu = xfrm4_update_pmtu, 245 .destroy = xfrm4_dst_destroy, 246 .ifdown = xfrm4_dst_ifdown, 247 .local_out = __ip_local_out, 248 .gc_thresh = 1024, 249 .entry_size = sizeof(struct xfrm_dst), 250 .entries = ATOMIC_INIT(0), 251 }; 252 253 static struct xfrm_policy_afinfo xfrm4_policy_afinfo = { 254 .family = AF_INET, 255 .dst_ops = &xfrm4_dst_ops, 256 .dst_lookup = xfrm4_dst_lookup, 257 .get_saddr = xfrm4_get_saddr, 258 .find_bundle = __xfrm4_find_bundle, 259 .decode_session = _decode_session4, 260 .get_tos = xfrm4_get_tos, 261 .init_path = xfrm4_init_path, 262 .fill_dst = xfrm4_fill_dst, 263 }; 264 265 static void __init xfrm4_policy_init(void) 266 { 267 xfrm_policy_register_afinfo(&xfrm4_policy_afinfo); 268 } 269 270 static void __exit xfrm4_policy_fini(void) 271 { 272 xfrm_policy_unregister_afinfo(&xfrm4_policy_afinfo); 273 } 274 275 void __init xfrm4_init(void) 276 { 277 xfrm4_state_init(); 278 xfrm4_policy_init(); 279 } 280 281