www.usr.com/support/gpl/USR9113_release1.0.tar.gz
[bcm963xx.git] / kernel / linux / net / bridge / netfilter / ebt_time.c
1 /*
2   Description: EBTables time match extension kernelspace module.
3   Authors:  Song Wang <songw@broadcom.com>, ported from netfilter/iptables
4             The following is the original disclaimer.
5
6   This is a module which is used for time matching
7   It is using some modified code from dietlibc (localtime() function)
8   that you can find at http://www.fefe.de/dietlibc/
9   This file is distributed under the terms of the GNU General Public
10   License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
11   2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
12   2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
13      thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
14   2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
15   2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
16      added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
17 */
18
19 #include <linux/module.h>
20 #include <linux/skbuff.h>
21 #include <linux/netfilter_bridge/ebtables.h>
22 #include <linux/netfilter_bridge/ebt_time.h>
23 #include <linux/time.h>
24
25 static unsigned char debug;
26 MODULE_PARM(debug, "0-1b");
27 MODULE_PARM_DESC(debug, "debug=1 is turn on debug messages");
28 MODULE_AUTHOR("Song Wang <songw@broadcom.com>");
29 MODULE_DESCRIPTION("Match timestamp");
30 MODULE_LICENSE("GPL");
31
32 #define DEBUG_MSG(...) if (debug) printk (KERN_DEBUG "ebt_time: " __VA_ARGS__)
33
34 struct tm
35 {
36         int tm_sec;                   /* Seconds.     [0-60] (1 leap second) */
37         int tm_min;                   /* Minutes.     [0-59] */
38         int tm_hour;                  /* Hours.       [0-23] */
39         int tm_mday;                  /* Day.         [1-31] */
40         int tm_mon;                   /* Month.       [0-11] */
41         int tm_year;                  /* Year - 1900.  */
42         int tm_wday;                  /* Day of week. [0-6] */
43         int tm_yday;                  /* Days in year.[0-365] */
44         int tm_isdst;                 /* DST.         [-1/0/1]*/
45
46         long int tm_gmtoff;           /* we don't care, we count from GMT */
47         const char *tm_zone;          /* we don't care, we count from GMT */
48 };
49
50 void localtime(const time_t *timepr, struct tm *r);
51
52 static int ebt_filter_time(const struct sk_buff *skb,
53    const struct net_device *in, const struct net_device *out, const void *data,
54    unsigned int datalen)
55
56 {
57         const struct ebt_time_info *info = (struct ebt_time_info *)data;   /* match info for rule */
58         struct tm currenttime;                          /* time human readable */
59         u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
60         u_int16_t packet_time;
61         struct timeval kerneltimeval;
62         time_t packet_local_time;
63
64         /* if kerneltime=1, we don't read the skb->timestamp but kernel time instead */
65         if (info->kerneltime)
66         {
67                 do_gettimeofday(&kerneltimeval);
68                 packet_local_time = kerneltimeval.tv_sec;
69         }
70         else
71                 packet_local_time = skb->stamp.tv_sec;
72
73         /* Transform the timestamp of the packet, in a human readable form */
74         localtime(&packet_local_time, &currenttime);
75         DEBUG_MSG("currenttime: Y-%d M-%d D-%d H-%d M-%d S-%d, Day: W-%d\n",
76                 currenttime.tm_year, currenttime.tm_mon, currenttime.tm_mday,
77                 currenttime.tm_hour, currenttime.tm_min, currenttime.tm_sec,
78                 currenttime.tm_wday);
79
80         /* check if we match this timestamp, we start by the days... */
81         if (info->days_match != 0) {
82                 if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
83                         return EBT_NOMATCH; /* the day doesn't match */
84         }
85
86         /* ... check the time now */
87         packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
88         if ((packet_time < info->time_start) || (packet_time > info->time_stop))
89                 return EBT_NOMATCH;
90
91         /* here we match ! */
92         return EBT_MATCH;
93 }
94
95 static int ebt_time_check(const char *tablename, unsigned int hookmask,
96    const struct ebt_entry *e, void *data, unsigned int datalen)
97
98 {
99         struct ebt_time_info *info = (struct ebt_time_info *)data;   /* match info for rule */
100
101         /* First, check that we are in the correct hook */
102         /* PRE_ROUTING, LOCAL_IN or FROWARD */
103 #if 0
104         if (hookmask
105             & ~((1 << NF_BR_PRE_ROUTING) | (1 << NF_BR_LOCAL_IN) | (1 << NF_BR_FORWARD) | (1 << NF_BR_LOCAL_OUT)))
106         {
107                 printk("ebt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
108                 return -EINVAL;
109         }
110 #endif
111         /* we use the kerneltime if we are in forward or output */
112         info->kerneltime = 1;
113 #if 0
114         if (hookmask & ~((1 << NF_BR_FORWARD) | (1 << NF_BR_LOCAL_OUT))) 
115                 /* if not, we use the skb time */
116                 info->kerneltime = 0;
117 #endif
118
119         /* Check the size */
120         if (datalen != sizeof(struct ebt_time_info))
121                 return -EINVAL;
122         /* Now check the coherence of the data ... */
123         if ((info->time_start > 1439) ||        /* 23*60+59 = 1439*/
124             (info->time_stop  > 1439))
125         {
126                 printk(KERN_WARNING "ebt_time: invalid argument\n");
127                 return -EINVAL;
128         }
129
130         return 0;
131 }
132
133 static struct ebt_match time_match =
134 {
135         .name           = EBT_TIME_MATCH,
136         .match          = ebt_filter_time,
137         .check          = ebt_time_check,
138         .me             = THIS_MODULE,
139 };
140
141 static int __init init(void)
142 {
143         DEBUG_MSG("ebt_time loading\n");
144         return ebt_register_match(&time_match);
145 }
146
147 static void __exit fini(void)
148 {
149         ebt_unregister_match(&time_match);
150         DEBUG_MSG("ebt_time unloaded\n");
151 }
152
153 module_init(init);
154 module_exit(fini);
155
156
157 /* The part below is borowed and modified from dietlibc */
158
159 /* seconds per day */
160 #define SPD 24*60*60
161
162 void localtime(const time_t *timepr, struct tm *r) {
163         time_t i;
164         time_t timep;
165         extern struct timezone sys_tz;
166         const unsigned int __spm[12] =
167                 { 0,
168                   (31),
169                   (31+28),
170                   (31+28+31),
171                   (31+28+31+30),
172                   (31+28+31+30+31),
173                   (31+28+31+30+31+30),
174                   (31+28+31+30+31+30+31),
175                   (31+28+31+30+31+30+31+31),
176                   (31+28+31+30+31+30+31+31+30),
177                   (31+28+31+30+31+30+31+31+30+31),
178                   (31+28+31+30+31+30+31+31+30+31+30),
179                 };
180         register time_t work;
181
182         timep = (*timepr) - (sys_tz.tz_minuteswest * 60);
183         work=timep%(SPD);
184         r->tm_sec=work%60; work/=60;
185         r->tm_min=work%60; r->tm_hour=work/60;
186         work=timep/(SPD);
187         r->tm_wday=(4+work)%7;
188         for (i=1970; ; ++i) {
189                 register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
190                 if (work>k)
191                         work-=k;
192                 else
193                         break;
194         }
195         r->tm_year=i-1900;
196         for (i=11; i && __spm[i]>work; --i) ;
197         r->tm_mon=i;
198         r->tm_mday=work-__spm[i]+1;
199 }