# BRCM_VERSION=3
[bcm963xx.git] / kernel / linux / net / ipv4 / netfilter / ip_traffic_standalone.c~
1 /* This file contains all the functions required for the standalone
2    ip_traffic module.
3
4    These are not required by the compatibility layer.
5 */
6
7 /* (c) 2005 Echo Licenced under the GNU General
8    Public Licence. */
9
10 #include <linux/config.h>
11 #include <linux/types.h>
12 #include <linux/ip.h>
13 #include <linux/netfilter.h>
14 #include <linux/netfilter_ipv4.h>
15 #include <linux/module.h>
16 #include <linux/skbuff.h>
17 #include <linux/proc_fs.h>
18 #ifdef CONFIG_SYSCTL
19 #include <linux/sysctl.h>
20 #endif
21 #include <net/checksum.h>
22 #include <net/ip.h>
23
24
25 #include <linux/netfilter_ipv4/traffic_defs.h>
26 #include <linux/netfilter_ipv4/ip_conntrack.h>
27
28 #if 0
29 #define DEBUGP printk
30 #else
31 #define DEBUGP(format, args...)
32 #endif
33
34 #define ECHO_DEBUG 0
35
36 struct module *ip_traffic_module = THIS_MODULE;
37 MODULE_LICENSE ("GPL");
38
39 #define MEGA_BYTE       0x00080000      //Mega byte
40
41 unsigned int traffic_bytes = 0; // means 0MB
42 unsigned int traffic_tmp = 0;   //use to temporaly store the bytes less than 1 M
43
44 extern struct list_head traffic_config_list_head;
45
46 static int
47 list_traffics (char *buffer, char **start, off_t offset, int length)
48 {
49   int len = 0;
50   int i = 0;
51   const struct list_head *__t = &traffic_config_list_head;
52
53 #define BUFFSIZE 1024
54   char *tmp = kmalloc (BUFFSIZE, GFP_KERNEL);
55   if (tmp == NULL)
56     {
57       printk ("kernel malloc memory failed.\n");
58       return 0;
59     }
60   tmp[0] = 0;
61
62   //Note:
63   /*
64    * This simple implementation can only work in condition that data needed to show and
65    * configure is less than 4K.
66    * If the assumption is not true, then you should deal with the parameters start&offset
67    * You can find some helps in linux/fs/proc/generic.c about line 65. 
68    */
69
70   sprintf (tmp, "%sthrough_bytes(MB)=%d\n", tmp, traffic_bytes);
71   do
72     {
73       __t = __t->next;
74       if (__t == (&traffic_config_list_head))
75         {
76           __t = NULL;
77           break;
78         }
79       i++;
80       snprintf (tmp, BUFFSIZE, "%sip=%d\tlimit=%d\tblock=%d\n", tmp,
81                 ((const ptraffic_config_t) __t)->ip_address,
82                 ((const ptraffic_config_t) __t)->ip_traffic_MAX,
83                 ((const ptraffic_config_t) __t)->autoBlock);
84     }
85   while (1);
86   strncpy (buffer, tmp, BUFFSIZE);
87   kfree (tmp);
88   len = strlen (buffer);
89   return len;
90 }
91
92
93 /*
94 * The function is used to count the packet through the wan interface. 
95 * Packet is counted and indentified by IP address.
96 *
97 * When the sum of packet for certain IP address reaches the budget, than the 
98 * 1. No more packet can be sent to Internet through the router here.
99 * 2. No more new connection is allowed to established, but the current 
100 *    connection is not affected at all.
101 */
102
103 static unsigned int
104 ip_traffic_control (unsigned int hooknum, struct sk_buff **pskb,
105                     const struct net_device *in,
106                     const struct net_device *out,
107                     int (*okfn) (struct sk_buff *))
108 {
109   long int addr;
110   char *p = (char *) &addr;
111   struct list_head *__t = &traffic_config_list_head;
112 //for check the conntrack status of the packet.
113   struct ip_conntrack *ct;
114   enum ip_conntrack_info ctinfo;
115   unsigned int verdict = NF_ACCEPT;
116
117   int found = 0;                //the packet is in the list 
118   struct list_head other = NULL;        //refer to configuration for other pc.
119
120
121   *p = 192;
122   p[1] = 168;
123   p[2] = 10;
124   p[3] = 41;
125
126 #if ECHO_DEBUG
127   printk (KERN_INFO "a packet with daddr=%ld sapass throuth post_routing.\n",
128           (*pskb)->nh.iph->daddr);
129   printk (KERN_INFO "htonl(addr) = %ld", htonl (addr));
130 #endif
131
132
133 //      the packet coming from/to wan interface  
134
135   if ((out->name != NULL && strcmp (out->name, "br0") != 0)
136       || (*pskb)->sk == NULL)
137     {
138
139       if (out->name != NULL && strcmp (out->name, "br0") != 0)
140         {
141           traffic_tmp += (*pskb)->nh.iph->tot_len;
142           if (traffic_tmp >= MEGA_BYTE)
143             {
144               traffic_bytes += traffic_tmp / MEGA_BYTE;
145               traffic_tmp = traffic_tmp % MEGA_BYTE;
146             }
147         }
148
149       found = 0;
150       other = NULL;
151       if ((*pskb)->sk == NULL)
152         {
153           do
154             {
155               __t = __t->next;
156               if (__t == (&traffic_config_list_head))
157                 {
158                   __t = NULL;
159                   break;
160                 }
161 /*      if ((*pskb)->mac.raw >= (*pskb)->head
162           && ((*pskb)->mac.raw + ETH_HLEN) <= (*pskb)->data
163           && memcmp ((*pskb)->mac.ethernet->h_source,
164                      ((ptraffic_config_t) __t)->h_dest, ETH_ALEN) == 0)
165 */
166               if (((ptraffic_config_t) __t)->ip_address == 0)
167                 found = __t;
168               if ((*pskb)->nh.iph->daddr ==
169                   htonl (((ptraffic_config_t) __t)->ip_address)
170                   || (*pskb)->nh.iph->saddr ==
171                   htonl (((ptraffic_config_t) __t)->ip_address))
172                 {
173                   ((ptraffic_config_t) __t)->ip_traffic_local +=
174                     (*pskb)->nh.iph->tot_len;
175                   if (((ptraffic_config_t) __t)->ip_traffic_local >=
176                       MEGA_BYTE)
177                     {
178                       ((ptraffic_config_t) __t)->ip_traffic_MAX -=
179                         ((ptraffic_config_t) __t)->ip_traffic_local /
180                         MEGA_BYTE;
181                       ((ptraffic_config_t) __t)->ip_traffic_local =
182                         ((ptraffic_config_t) __t)->ip_traffic_local %
183                         MEGA_BYTE;
184                     }
185                   if (((ptraffic_config_t) __t)->ip_traffic_MAX <= 0)
186                     {
187                       //the verdict is according the autoBlock value  
188                       if (((ptraffic_config_t) __t)->autoBlock == 1)
189                         verdict = NF_DROP;
190                       else
191                         {
192                           ct = ip_conntrack_get (*pskb, &ctinfo);
193                           if (ct
194                               && (ctinfo == IP_CT_NEW
195                                   || ctinfo == IP_CT_RELATED))
196                             {
197                               verdict = NF_DROP;
198                             }
199                           else
200                             {
201                               verdict = NF_ACCEPT;
202                             }
203
204                         }
205
206                     }
207                   found = 1;
208                   break;
209                 }
210
211             }
212           while (1);
213         }
214     }
215
216 //do other accounting and block action
217   if (found == 0 && other != NULL)
218     {
219           ((ptraffic_config_t) other)->ip_traffic_local +=
220             (*pskb)->nh.iph->tot_len;
221           if (((ptraffic_config_t) other)->ip_traffic_local >= MEGA_BYTE)
222             {
223               ((ptraffic_config_t) other)->ip_traffic_MAX -=
224                 ((ptraffic_config_t) other)->ip_traffic_local / MEGA_BYTE;
225               ((ptraffic_config_t) other)->ip_traffic_local =
226                 ((ptraffic_config_t) other)->ip_traffic_local % MEGA_BYTE;
227             }
228
229           if (((ptraffic_config_t) other)->ip_traffic_MAX <= 0)
230             {
231               //the verdict is according the autoBlock value
232               if (((ptraffic_config_t) other)->autoBlock == 1)
233                 verdict = NF_DROP;
234               else
235                 {
236                   ct = ip_conntrack_get (*pskb, &ctinfo);
237                   if (ct && (ctinfo == IP_CT_NEW || ctinfo == IP_CT_RELATED))
238                     {
239                       verdict = NF_DROP;
240                     }
241                   else
242                     {
243                       verdict = NF_ACCEPT;
244                     }
245
246                 }
247
248             }
249
250         }
251
252
253       return verdict;
254
255     }
256
257 /*
258 * just count the packet received from wan
259 */
260
261   static unsigned int
262     ip_general_traffic_control (unsigned int hooknum, struct sk_buff **pskb,
263                                 const struct net_device *in,
264                                 const struct net_device *out,
265                                 int (*okfn) (struct sk_buff *))
266   {
267     if (in->name != NULL && strcmp (in->name, "br0") != 0)
268       {
269         traffic_tmp += (*pskb)->nh.iph->tot_len;
270         if (traffic_tmp >= MEGA_BYTE)
271           {
272             traffic_bytes += traffic_tmp / MEGA_BYTE;
273             traffic_tmp = traffic_tmp % MEGA_BYTE;
274           }
275       }
276     return NF_ACCEPT;
277   }
278
279
280 /*
281  * When the data is prepared to leave the ip stack, traffic control is done.
282  * So we made a hook call-back function at POST_ROUTING
283  */
284   static struct nf_hook_ops ip_traffic_control_ops = {
285     .hook = ip_traffic_control,
286     .owner = THIS_MODULE,
287     .pf = PF_INET,
288     .hooknum = NF_IP_POST_ROUTING,
289     .priority = NF_IP_PRI_CONNTRACK,
290   };
291
292   static struct nf_hook_ops ip_general_traffic_control_ops = {
293     .hook = ip_general_traffic_control,
294     .owner = THIS_MODULE,
295     .pf = PF_INET,
296     .hooknum = NF_IP_PRE_ROUTING,
297     .priority = NF_IP_PRI_CONNTRACK,
298   };
299
300   static int init_or_cleanup (int init)
301   {
302     struct proc_dir_entry *proc;
303     int ret = 0;
304
305     if (!init)
306       goto cleanup;
307
308 /*      ret = ip_traffic_init();
309         if (ret < 0)
310                 goto cleanup_nothing;
311 */
312     proc = proc_net_create ("ip_traffic", 0440, list_traffics);
313     if (!proc)
314       goto cleanup_init;
315     proc->owner = THIS_MODULE;
316
317     ret = nf_register_hook (&ip_traffic_control_ops);
318     if (ret < 0)
319       {
320         printk ("ip_traffic: can't register hook.\n");
321         goto cleanup_proc;
322       }
323     ret = nf_register_hook (&ip_general_traffic_control_ops);
324     if (ret < 0)
325       {
326         printk ("ip_traffic: can't register hook.\n");
327         goto cleanup_outops;
328       }
329     return ret;
330
331   cleanup:
332   cleanup_inops:
333     nf_unregister_hook (&ip_general_traffic_control_ops);
334   cleanup_outops:
335     nf_unregister_hook (&ip_traffic_control_ops);
336   cleanup_proc:
337     proc_net_remove ("ip_traffic");
338   cleanup_init:
339 /*
340         ip_traffic_cleanup();
341 */
342   cleanup_nothing:
343     return ret;
344   }
345
346   static int __init init (void)
347   {
348     return init_or_cleanup (1);
349   }
350
351   static void __exit fini (void)
352   {
353     init_or_cleanup (0);
354   }
355
356   module_init (init);
357   module_exit (fini);