Linux-2.6.12-rc2
[linux-flexiantxendom0-natty.git] / net / ipv4 / ipvs / ip_vs_proto_icmp.c
1 /*
2  * ip_vs_proto_icmp.c:  ICMP load balancing support for IP Virtual Server
3  *
4  * Authors:     Julian Anastasov <ja@ssi.bg>, March 2002
5  *
6  *              This program is free software; you can redistribute it and/or
7  *              modify it under the terms of the GNU General Public License
8  *              version 2 as published by the Free Software Foundation;
9  *
10  */
11
12 #include <linux/module.h>
13 #include <linux/kernel.h>
14 #include <linux/icmp.h>
15 #include <linux/netfilter.h>
16 #include <linux/netfilter_ipv4.h>
17
18 #include <net/ip_vs.h>
19
20
21 static int icmp_timeouts[1] =           { 1*60*HZ };
22
23 static char * icmp_state_name_table[1] = { "ICMP" };
24
25 static struct ip_vs_conn *
26 icmp_conn_in_get(const struct sk_buff *skb,
27                  struct ip_vs_protocol *pp,
28                  const struct iphdr *iph,
29                  unsigned int proto_off,
30                  int inverse)
31 {
32 #if 0
33         struct ip_vs_conn *cp;
34
35         if (likely(!inverse)) {
36                 cp = ip_vs_conn_in_get(iph->protocol,
37                         iph->saddr, 0,
38                         iph->daddr, 0);
39         } else {
40                 cp = ip_vs_conn_in_get(iph->protocol,
41                         iph->daddr, 0,
42                         iph->saddr, 0);
43         }
44
45         return cp;
46
47 #else
48         return NULL;
49 #endif
50 }
51
52 static struct ip_vs_conn *
53 icmp_conn_out_get(const struct sk_buff *skb,
54                   struct ip_vs_protocol *pp,
55                   const struct iphdr *iph,
56                   unsigned int proto_off,
57                   int inverse)
58 {
59 #if 0
60         struct ip_vs_conn *cp;
61
62         if (likely(!inverse)) {
63                 cp = ip_vs_conn_out_get(iph->protocol,
64                         iph->saddr, 0,
65                         iph->daddr, 0);
66         } else {
67                 cp = ip_vs_conn_out_get(IPPROTO_UDP,
68                         iph->daddr, 0,
69                         iph->saddr, 0);
70         }
71
72         return cp;
73 #else
74         return NULL;
75 #endif
76 }
77
78 static int
79 icmp_conn_schedule(struct sk_buff *skb, struct ip_vs_protocol *pp,
80                    int *verdict, struct ip_vs_conn **cpp)
81 {
82         *verdict = NF_ACCEPT;
83         return 0;
84 }
85
86 static int
87 icmp_csum_check(struct sk_buff *skb, struct ip_vs_protocol *pp)
88 {
89         if (!(skb->nh.iph->frag_off & __constant_htons(IP_OFFSET))) {
90                 if (skb->ip_summed != CHECKSUM_UNNECESSARY) {
91                         if (ip_vs_checksum_complete(skb, skb->nh.iph->ihl * 4)) {
92                                 IP_VS_DBG_RL_PKT(0, pp, skb, 0, "Failed checksum for");
93                                 return 0;
94                         }
95                 }
96         }
97         return 1;
98 }
99
100 static void
101 icmp_debug_packet(struct ip_vs_protocol *pp,
102                   const struct sk_buff *skb,
103                   int offset,
104                   const char *msg)
105 {
106         char buf[256];
107         struct iphdr _iph, *ih;
108
109         ih = skb_header_pointer(skb, offset, sizeof(_iph), &_iph);
110         if (ih == NULL)
111                 sprintf(buf, "%s TRUNCATED", pp->name);
112         else if (ih->frag_off & __constant_htons(IP_OFFSET))
113                 sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u frag",
114                         pp->name, NIPQUAD(ih->saddr),
115                         NIPQUAD(ih->daddr));
116         else {
117                 struct icmphdr _icmph, *ic;
118
119                 ic = skb_header_pointer(skb, offset + ih->ihl*4,
120                                         sizeof(_icmph), &_icmph);
121                 if (ic == NULL)
122                         sprintf(buf, "%s TRUNCATED to %u bytes\n",
123                                 pp->name, skb->len - offset);
124                 else
125                         sprintf(buf, "%s %u.%u.%u.%u->%u.%u.%u.%u T:%d C:%d",
126                                 pp->name, NIPQUAD(ih->saddr),
127                                 NIPQUAD(ih->daddr),
128                                 ic->type, ic->code);
129         }
130         printk(KERN_DEBUG "IPVS: %s: %s\n", msg, buf);
131 }
132
133 static int
134 icmp_state_transition(struct ip_vs_conn *cp, int direction,
135                       const struct sk_buff *skb,
136                       struct ip_vs_protocol *pp)
137 {
138         cp->timeout = pp->timeout_table[IP_VS_ICMP_S_NORMAL];
139         return 1;
140 }
141
142 static int
143 icmp_set_state_timeout(struct ip_vs_protocol *pp, char *sname, int to)
144 {
145         int num;
146         char **names;
147
148         num = IP_VS_ICMP_S_LAST;
149         names = icmp_state_name_table;
150         return ip_vs_set_state_timeout(pp->timeout_table, num, names, sname, to);
151 }
152
153
154 static void icmp_init(struct ip_vs_protocol *pp)
155 {
156         pp->timeout_table = icmp_timeouts;
157 }
158
159 static void icmp_exit(struct ip_vs_protocol *pp)
160 {
161 }
162
163 struct ip_vs_protocol ip_vs_protocol_icmp = {
164         .name =                 "ICMP",
165         .protocol =             IPPROTO_ICMP,
166         .dont_defrag =          0,
167         .init =                 icmp_init,
168         .exit =                 icmp_exit,
169         .conn_schedule =        icmp_conn_schedule,
170         .conn_in_get =          icmp_conn_in_get,
171         .conn_out_get =         icmp_conn_out_get,
172         .snat_handler =         NULL,
173         .dnat_handler =         NULL,
174         .csum_check =           icmp_csum_check,
175         .state_transition =     icmp_state_transition,
176         .register_app =         NULL,
177         .unregister_app =       NULL,
178         .app_conn_bind =        NULL,
179         .debug_packet =         icmp_debug_packet,
180         .timeout_change =       NULL,
181         .set_state_timeout =    icmp_set_state_timeout,
182 };