Main Page | Class List | File List | Class Members | File Members

ip_forward.c

Go to the documentation of this file.
00001 /* 00002 * INET An implementation of the TCP/IP protocol suite for the LINUX 00003 * operating system. INET is implemented using the BSD Socket 00004 * interface as the means of communication with the user level. 00005 * 00006 * The IP forwarding functionality. 00007 * 00008 * Version: $Id: ip_forward.c,v 1.48 2000/12/13 18:31:48 davem Exp $ 00009 * 00010 * Authors: see ip.c 00011 * 00012 * Fixes: 00013 * Many : Split from ip.c , see ip_input.c for 00014 * history. 00015 * Dave Gregorich : NULL ip_rt_put fix for multicast 00016 * routing. 00017 * Jos Vos : Add call_out_firewall before sending, 00018 * use output device for accounting. 00019 * Jos Vos : Call forward firewall after routing 00020 * (always use output device). 00021 * Mike McLagan : Routing by source 00022 */ 00023 00024 #include <linux/config.h> 00025 #include <linux/types.h> 00026 #include <linux/mm.h> 00027 #include <linux/sched.h> 00028 #include <linux/skbuff.h> 00029 #include <linux/ip.h> 00030 #include <linux/icmp.h> 00031 #include <linux/netdevice.h> 00032 #include <net/sock.h> 00033 #include <net/ip.h> 00034 #include <net/tcp.h> 00035 #include <net/udp.h> 00036 #include <net/icmp.h> 00037 #include <linux/tcp.h> 00038 #include <linux/udp.h> 00039 #include <linux/netfilter_ipv4.h> 00040 #include <net/checksum.h> 00041 #include <linux/route.h> 00042 #include <net/route.h> 00043 00044 static inline int ip_forward_finish(struct sk_buff *skb) 00045 { 00046 struct ip_options * opt = &(IPCB(skb)->opt); 00047 00048 IP_INC_STATS_BH(IpForwDatagrams); 00049 00050 if (opt->optlen == 0) { 00051 #ifdef CONFIG_NET_FASTROUTE 00052 struct rtable *rt = (struct rtable*)skb->dst; 00053 00054 if (rt->rt_flags&RTCF_FAST && !netdev_fastroute_obstacles) { 00055 struct dst_entry *old_dst; 00056 unsigned h = ((*(u8*)&rt->key.dst)^(*(u8*)&rt->key.src))&NETDEV_FASTROUTE_HMASK; 00057 00058 write_lock_irq(&skb->dev->fastpath_lock); 00059 old_dst = skb->dev->fastpath[h]; 00060 skb->dev->fastpath[h] = dst_clone(&rt->u.dst); 00061 write_unlock_irq(&skb->dev->fastpath_lock); 00062 00063 dst_release(old_dst); 00064 } 00065 #endif 00066 return (ip_send(skb)); 00067 } 00068 00069 ip_forward_options(skb); 00070 return (ip_send(skb)); 00071 } 00072 00073 int ip_forward(struct sk_buff *skb) 00074 { 00075 struct net_device *dev2; /* Output device */ 00076 struct iphdr *iph; /* Our header */ 00077 struct rtable *rt; /* Route we use */ 00078 struct ip_options * opt = &(IPCB(skb)->opt); 00079 unsigned short mtu; 00080 00081 if (IPCB(skb)->opt.router_alert && ip_call_ra_chain(skb)) 00082 return NET_RX_SUCCESS; 00083 00084 if (skb->pkt_type != PACKET_HOST) 00085 goto drop; 00086 00087 skb->ip_summed = CHECKSUM_NONE; 00088 00089 /* 00090 * According to the RFC, we must first decrease the TTL field. If 00091 * that reaches zero, we must reply an ICMP control message telling 00092 * that the packet's lifetime expired. 00093 */ 00094 00095 iph = skb->nh.iph; 00096 rt = (struct rtable*)skb->dst; 00097 00098 if (iph->ttl <= 1) 00099 goto too_many_hops; 00100 00101 if (opt->is_strictroute && rt->rt_dst != rt->rt_gateway) 00102 goto sr_failed; 00103 00104 /* 00105 * Having picked a route we can now send the frame out 00106 * after asking the firewall permission to do so. 00107 */ 00108 00109 skb->priority = rt_tos2priority(iph->tos); 00110 dev2 = rt->u.dst.dev; 00111 mtu = rt->u.dst.pmtu; 00112 00113 /* 00114 * We now generate an ICMP HOST REDIRECT giving the route 00115 * we calculated. 00116 */ 00117 if (rt->rt_flags&RTCF_DOREDIRECT && !opt->srr) 00118 ip_rt_send_redirect(skb); 00119 00120 /* We are about to mangle packet. Copy it! */ 00121 if (skb_cow(skb, dev2->hard_header_len)) 00122 goto drop; 00123 iph = skb->nh.iph; 00124 00125 /* Decrease ttl after skb cow done */ 00126 ip_decrease_ttl(iph); 00127 00128 /* 00129 * We now may allocate a new buffer, and copy the datagram into it. 00130 * If the indicated interface is up and running, kick it. 00131 */ 00132 00133 if (skb->len > mtu && (ntohs(iph->frag_off) & IP_DF)) 00134 goto frag_needed; 00135 00136 #ifdef CONFIG_IP_ROUTE_NAT 00137 if (rt->rt_flags & RTCF_NAT) { 00138 if (ip_do_nat(skb)) { 00139 kfree_skb(skb); 00140 return NET_RX_BAD; 00141 } 00142 } 00143 #endif 00144 00145 return NF_HOOK(PF_INET, NF_IP_FORWARD, skb, skb->dev, dev2, 00146 ip_forward_finish); 00147 00148 frag_needed: 00149 IP_INC_STATS_BH(IpFragFails); 00150 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, htonl(mtu)); 00151 goto drop; 00152 00153 sr_failed: 00154 /* 00155 * Strict routing permits no gatewaying 00156 */ 00157 icmp_send(skb, ICMP_DEST_UNREACH, ICMP_SR_FAILED, 0); 00158 goto drop; 00159 00160 too_many_hops: 00161 /* Tell the sender its packet died... */ 00162 icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, 0); 00163 drop: 00164 kfree_skb(skb); 00165 return NET_RX_DROP; 00166 }

Generated on Wed Dec 1 21:25:30 2004 for Linux 2.4.23 Networking by doxygen 1.3.8