initial version, corresponding to ipfw3-2012
[ipfw-google.git] / kipfw / bsd_compat.c
1 /*
2  * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
23  * SUCH DAMAGE.
24  */
25
26 /*
27  * $Id: bsd_compat.c 11530 2012-08-01 10:29:32Z luigi $
28  *
29  * kernel variables and functions that are not available in linux.
30  */
31
32 #include <sys/cdefs.h>
33 #include <asm/div64.h>  /* do_div on 2.4 */
34 #include <linux/random.h>       /* get_random_bytes on 2.4 */
35 #include <netinet/ip_fw.h>
36 #include <netinet/ip_dummynet.h>
37 #include <sys/malloc.h>
38
39 /*
40  * gettimeofday would be in sys/time.h but it is not
41  * visible if _KERNEL is defined
42  */
43 int gettimeofday(struct timeval *, struct timezone *);
44
45 int ticks;              /* kernel ticks counter */
46 int hz = 1000;          /* default clock time */
47 long tick = 1000;       /* XXX is this 100000/hz ? */
48 int bootverbose = 0;
49 struct timeval boottime;
50
51 int     ip_defttl = 64; /* XXX set default value */
52 int     max_linkhdr = 16;
53 int fw_one_pass = 1;
54 u_long  in_ifaddrhmask;                         /* mask for hash table */
55 struct  in_ifaddrhashhead *in_ifaddrhashtbl;    /* inet addr hash table  */
56
57 u_int rt_numfibs = RT_NUMFIBS;
58
59 /*
60  * pfil hook support.
61  * We make pfil_head_get return a non-null pointer, which is then ignored
62  * in our 'add-hook' routines.
63  */
64 struct pfil_head;
65 typedef int (pfil_hook_t)
66         (void *, struct mbuf **, struct ifnet *, int, struct inpcb *);
67
68 struct pfil_head *
69 pfil_head_get(int proto, u_long flags)
70 {
71         static int dummy;
72         return (struct pfil_head *)&dummy;
73 }
74  
75 int
76 pfil_add_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
77 {
78         return 0;
79 }
80
81 int
82 pfil_remove_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
83 {
84         return 0;
85 }
86
87 /* define empty body for kernel function */
88 int
89 priv_check(struct thread *td, int priv)
90 {
91         return 0;
92 }
93
94 int
95 securelevel_ge(struct ucred *cr, int level)
96 {
97         return 0;
98 }
99
100 int
101 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
102 {
103         return 0;
104 }
105
106 int
107 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
108 {
109         return 0;
110 }
111
112 void
113 ether_demux(struct ifnet *ifp, struct mbuf *m)
114 {
115         return;
116 }
117
118 int
119 ether_output_frame(struct ifnet *ifp, struct mbuf *m)
120 {
121         return 0;
122 }
123
124 void
125 in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)
126 {
127         return;
128 }
129
130 void
131 icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu)
132 {
133         return;
134 }
135
136 u_short
137 in_cksum_skip(struct mbuf *m, int len, int skip)
138 {
139         return 0;
140 }
141
142 u_short
143 in_cksum_hdr(struct ip *ip)
144 {
145         return 0;
146 }
147
148 /*
149  * we don't really reassemble, just return whatever we had.
150  */
151 struct mbuf *
152 ip_reass(struct mbuf *clone)
153 {
154         return clone;
155 }
156 #ifdef INP_LOCK_ASSERT
157 #undef INP_LOCK_ASSERT
158 #define INP_LOCK_ASSERT(a)
159 #endif
160
161 /* credentials check */
162 #include <netinet/ip_fw.h>
163 #ifdef __linux__
164 int
165 cred_check(void *_insn,  int proto, struct ifnet *oif,
166     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
167     u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,
168     struct sk_buff *skb)
169 {
170         int match = 0;
171         ipfw_insn_u32 *insn = (ipfw_insn_u32 *)_insn;
172
173         if (*ugid_lookupp == 0) {        /* actively lookup and copy in cache */
174                 /* returns null if any element of the chain up to file is null.
175                  * if sk != NULL then we also have a reference
176                  */
177                 *ugid_lookupp = linux_lookup(proto,
178                         src_ip.s_addr, htons(src_port),
179                         dst_ip.s_addr, htons(dst_port),
180                         skb, oif ? 1 : 0, u);
181         }
182         if (*ugid_lookupp < 0)
183                 return 0;
184
185         if (insn->o.opcode == O_UID)
186                 match = (u->uid == (uid_t)insn->d[0]);
187         else if (insn->o.opcode == O_JAIL)
188                 match = (u->xid == (uid_t)insn->d[0]);
189         else if (insn->o.opcode == O_GID)
190                 match = (u->gid == (uid_t)insn->d[0]);
191         return match;
192 }
193 #endif  /* __linux__ */
194
195 int
196 jailed(struct ucred *cred)
197 {
198         return 0;
199 }
200
201 /*
202 * Return 1 if an internet address is for a ``local'' host
203 * (one to which we have a connection).  If subnetsarelocal
204 * is true, this includes other subnets of the local net.
205 * Otherwise, it includes only the directly-connected (sub)nets.
206 */
207 int
208 in_localaddr(struct in_addr in)
209 {
210         return 1;
211 }
212
213 int
214 sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
215 {
216         size_t valsize = sopt->sopt_valsize;
217
218         if (len < valsize)
219                 sopt->sopt_valsize = valsize = len;
220         //printf("copyout buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
221         bcopy(buf, sopt->sopt_val, valsize);
222         return 0;
223 }
224
225 /*
226  * copy data from userland to kernel
227  */
228 int
229 sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
230 {
231         size_t valsize = sopt->sopt_valsize;
232
233         if (valsize < minlen)
234                 return EINVAL;
235         if (valsize > len)
236                 sopt->sopt_valsize = valsize = len;
237         //printf("copyin buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
238         bcopy(sopt->sopt_val, buf, valsize);
239         return 0;
240 }
241
242 void
243 getmicrouptime(struct timeval *tv)
244 {
245         do_gettimeofday(tv);
246 }
247
248
249 #include <arpa/inet.h>
250
251 char *
252 inet_ntoa_r(struct in_addr ina, char *buf)
253 {
254 #ifdef _WIN32
255 #else
256         unsigned char *ucp = (unsigned char *)&ina;
257
258         sprintf(buf, "%d.%d.%d.%d",
259         ucp[0] & 0xff,
260         ucp[1] & 0xff,
261         ucp[2] & 0xff,
262         ucp[3] & 0xff);
263 #endif
264         return buf;
265 }
266
267 char *
268 inet_ntoa(struct in_addr ina)
269 {
270         static char buf[16];
271         return inet_ntoa_r(ina, buf);
272 }
273
274 int
275 random(void)
276 {
277 #ifdef _WIN32
278         static unsigned long seed;
279         if (seed == 0) {
280                 LARGE_INTEGER tm;
281                 KeQuerySystemTime(&tm);
282                 seed = tm.LowPart;
283         }
284         return RtlRandomEx(&seed) & 0x7fffffff;
285 #else
286         int r;
287         get_random_bytes(&r, sizeof(r));
288         return r & 0x7fffffff; 
289 #endif
290 }
291
292
293 /*
294  * do_div really does a u64 / u32 bit division.
295  * we save the sign and convert to uint befor calling.
296  * We are safe just because we always call it with small operands.
297  */
298 int64_t
299 div64(int64_t a, int64_t b)
300 {
301 #ifdef _WIN32
302         int a1 = a, b1 = b;
303         return a1/b1;
304 #else
305         uint64_t ua, ub;
306         int sign = ((a>0)?1:-1) * ((b>0)?1:-1);
307
308         ua = ((a>0)?a:-a);
309         ub = ((b>0)?b:-b);
310         do_div(ua, ub);
311         return sign*ua;
312 #endif
313 }
314
315 #ifdef __MIPSEL__
316 size_t
317 strlcpy(char *dst, const char *src, size_t siz)
318 {
319         char *d = dst;
320         const char *s = src;
321         size_t n = siz;
322  
323         /* Copy as many bytes as will fit */
324         if (n != 0 && --n != 0) {
325                 do {
326                         if ((*d++ = *s++) == 0)
327                                 break;
328                 } while (--n != 0);
329         }
330
331         /* Not enough room in dst, add NUL and traverse rest of src */
332         if (n == 0) {
333                 if (siz != 0)
334                         *d = '\0';              /* NUL-terminate dst */
335                 while (*s++)
336                         ;
337         }
338
339         return(s - src - 1);    /* count does not include NUL */
340 }
341 #endif // __MIPSEL__
342
343 /*
344  * compact version of fnmatch.
345  */
346 int
347 fnmatch(const char *pattern, const char *string, int flags)
348 {
349         char s;
350
351         if (!string || !pattern)
352                 return 1;       /* no match */
353         while ( (s = *string++) ) {
354                 char p = *pattern++;
355                 if (p == '\0')          /* pattern is over, no match */
356                         return 1;
357                 if (p == '*')           /* wildcard, match */
358                         return 0;
359                 if (p == '.' || p == s) /* char match, continue */
360                         continue;
361                 return 1;               /* no match */
362         }
363         /* end of string, make sure the pattern is over too */
364         if (*pattern == '\0' || *pattern == '*')
365                 return 0;
366         return 1;       /* no match */
367 }
368
369
370 /*
371  * linux 2.6.33 defines these functions to access to
372  * skbuff internal structures. Define the missing
373  * function for the previous versions too.
374  */
375 #ifdef linux
376 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
377 inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
378 {
379         skb->dst = dst;
380 }
381
382 inline struct dst_entry *skb_dst(const struct sk_buff *skb)
383 {
384         return (struct dst_entry *)skb->dst;
385 }
386 #endif /* < 2.6.31 */
387 #endif /* linux */
388
389
390 /* support for sysctl emulation.
391  * XXX this is actually MI code that should be enabled also on openwrt
392  */
393 #ifdef EMULATE_SYSCTL
394 static struct sysctltable GST;
395
396 int
397 kesysctl_emu_get(struct sockopt* sopt)
398 {
399         struct dn_id* oid = sopt->sopt_val;
400         struct sysctlhead* entry;
401         int sizeneeded = sizeof(struct dn_id) + GST.totalsize +
402                 sizeof(struct sysctlhead);
403         unsigned char* pstring;
404         unsigned char* pdata;
405         int i;
406         
407         if (sopt->sopt_valsize < sizeneeded) {
408                 // this is a probe to retrieve the space needed for
409                 // a dump of the sysctl table
410                 oid->id = sizeneeded;
411                 sopt->sopt_valsize = sizeof(struct dn_id);
412                 return 0;
413         }
414         
415         entry = (struct sysctlhead*)(oid+1);
416         for( i=0; i<GST.count; i++) {
417                 entry->blocklen = GST.entry[i].head.blocklen;
418                 entry->namelen = GST.entry[i].head.namelen;
419                 entry->flags = GST.entry[i].head.flags;
420                 entry->datalen = GST.entry[i].head.datalen;
421                 pdata = (unsigned char*)(entry+1);
422                 pstring = pdata+GST.entry[i].head.datalen;
423                 bcopy(GST.entry[i].data, pdata, GST.entry[i].head.datalen);
424                 bcopy(GST.entry[i].name, pstring, GST.entry[i].head.namelen);
425                 entry = (struct sysctlhead*)
426                         ((unsigned char*)(entry) + GST.entry[i].head.blocklen);
427         }
428         sopt->sopt_valsize = sizeneeded;
429         return 0;
430 }
431
432 int
433 kesysctl_emu_set(void* p, int l)
434 {
435         struct sysctlhead* entry;
436         unsigned char* pdata;
437         unsigned char* pstring;
438         int i = 0;
439         
440         entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
441         pdata = (unsigned char*)(entry+1);
442         pstring = pdata + entry->datalen;
443         
444         for (i=0; i<GST.count; i++) {
445                 if (strcmp(GST.entry[i].name, pstring) != 0)
446                         continue;
447                 printf("%s: match found! %s\n",__FUNCTION__,pstring);
448                 //sanity check on len, not really useful now since
449                 //we only accept int32
450                 if (entry->datalen != GST.entry[i].head.datalen) {
451                         printf("%s: len mismatch, user %d vs kernel %d\n",
452                                 __FUNCTION__, entry->datalen,
453                                 GST.entry[i].head.datalen);
454                         return -1;
455                 }
456                 // check access (at the moment flags handles only the R/W rights
457                 //later on will be type + access
458                 if( (GST.entry[i].head.flags & 3) == CTLFLAG_RD) {
459                         printf("%s: the entry %s is read only\n",
460                                 __FUNCTION__,GST.entry[i].name);
461                         return -1;
462                 }
463                 bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
464                 return 0;
465         }
466         printf("%s: match not found\n",__FUNCTION__);
467         return 0;
468 }
469
470 /* convert all _ to . until the first . */
471 static void
472 underscoretopoint(char* s)
473 {
474         for (; *s && *s != '.'; s++)
475                 if (*s == '_')
476                         *s = '.';
477 }
478
479 static int
480 formatnames()
481 {
482         int i;
483         int size=0;
484         char* name;
485
486         for (i=0; i<GST.count; i++)
487                 size += GST.entry[i].head.namelen;
488         GST.namebuffer = malloc(size, 0, 0);
489         if (GST.namebuffer == NULL)
490                 return -1;
491         name = GST.namebuffer;
492         for (i=0; i<GST.count; i++) {
493                 bcopy(GST.entry[i].name, name, GST.entry[i].head.namelen);
494                 underscoretopoint(name);
495                 GST.entry[i].name = name;
496                 name += GST.entry[i].head.namelen;
497         }
498         return 0;
499 }
500
501 static void
502 dumpGST()
503 {
504         int i;
505
506         for (i=0; i<GST.count; i++) {
507                 printf("SYSCTL: entry %i\n", i);
508                 printf("name %s\n", GST.entry[i].name);
509                 printf("namelen %i\n", GST.entry[i].head.namelen);
510                 printf("type %i access %i\n",
511                         GST.entry[i].head.flags >> 2,
512                         GST.entry[i].head.flags & 0x00000003);
513                 printf("data %i\n", *(int*)(GST.entry[i].data));
514                 printf("datalen %i\n", GST.entry[i].head.datalen);
515                 printf("blocklen %i\n", GST.entry[i].head.blocklen);
516         }
517 }
518
519 void sysctl_addgroup_f1();
520 void sysctl_addgroup_f2();
521 void sysctl_addgroup_f3();
522 void sysctl_addgroup_f4();
523
524 void
525 keinit_GST()
526 {
527         int ret;
528
529         sysctl_addgroup_f1();
530         sysctl_addgroup_f2();
531         sysctl_addgroup_f3();
532         sysctl_addgroup_f4();
533         ret = formatnames();
534         if (ret != 0)
535                 printf("conversion of names failed for some reason\n");
536         //dumpGST();
537         printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
538                 GST.count, GST.totalsize);
539 }
540
541 void
542 keexit_GST()
543 {
544         if (GST.namebuffer != NULL)
545                 free(GST.namebuffer,0);
546         bzero(&GST, sizeof(GST));
547 }
548
549 void
550 sysctl_pushback(char* name, int flags, int datalen, void* data)
551 {
552         if (GST.count >= GST_HARD_LIMIT) {
553                 printf("WARNING: global sysctl table full, this entry will not be added,"
554                                 "please recompile the module increasing the table size\n");
555                 return;
556         }
557         GST.entry[GST.count].head.namelen = strlen(name)+1; //add space for '\0'
558         GST.entry[GST.count].name = name;
559         GST.entry[GST.count].head.flags = flags;
560         GST.entry[GST.count].data = data;
561         GST.entry[GST.count].head.datalen = datalen;
562         GST.entry[GST.count].head.blocklen =
563                 ((sizeof(struct sysctlhead) + GST.entry[GST.count].head.namelen +
564                         GST.entry[GST.count].head.datalen)+3) & ~3;
565         GST.totalsize += GST.entry[GST.count].head.blocklen;
566         GST.count++;
567 }
568 #endif /* EMULATE_SYSCTL */