Sync with the new ipfw3 version.
[ipfw.git] / dummynet2 / 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 5813 2010-03-22 18:05:13Z svn_magno $
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;
52 int fw_one_pass = 1;
53 u_long  in_ifaddrhmask;                         /* mask for hash table */
54 struct  in_ifaddrhashhead *in_ifaddrhashtbl;    /* inet addr hash table  */
55
56 u_int rt_numfibs = RT_NUMFIBS;
57
58 /*
59  * pfil hook support.
60  * We make pfil_head_get return a non-null pointer, which is then ignored
61  * in our 'add-hook' routines.
62  */
63 struct pfil_head;
64 typedef int (pfil_hook_t)
65         (void *, struct mbuf **, struct ifnet *, int, struct inpcb *);
66
67 struct pfil_head *
68 pfil_head_get(int proto, u_long flags)
69 {
70         static int dummy;
71         return (struct pfil_head *)&dummy;
72 }
73  
74 int
75 pfil_add_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
76 {
77         return 0;
78 }
79
80 int
81 pfil_remove_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
82 {
83         return 0;
84 }
85
86 /* define empty body for kernel function */
87 int
88 priv_check(struct thread *td, int priv)
89 {
90         return 0;
91 }
92
93 int
94 securelevel_ge(struct ucred *cr, int level)
95 {
96         return 0;
97 }
98
99 int
100 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
101 {
102         return 0;
103 }
104
105 int
106 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
107 {
108         return 0;
109 }
110
111 void
112 ether_demux(struct ifnet *ifp, struct mbuf *m)
113 {
114         return;
115 }
116
117 int
118 ether_output_frame(struct ifnet *ifp, struct mbuf *m)
119 {
120         return 0;
121 }
122
123 void
124 in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)
125 {
126         return;
127 }
128
129 void
130 icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu)
131 {
132         return;
133 }
134
135 u_short
136 in_cksum_skip(struct mbuf *m, int len, int skip)
137 {
138         return 0;
139 }
140
141 u_short
142 in_cksum_hdr(struct ip *ip)
143 {
144         return 0;
145 }
146
147 /*
148  * we don't really reassemble, just return whatever we had.
149  */
150 struct mbuf *
151 ip_reass(struct mbuf *clone)
152 {
153         return clone;
154 }
155 #ifdef INP_LOCK_ASSERT
156 #undef INP_LOCK_ASSERT
157 #define INP_LOCK_ASSERT(a)
158 #endif
159
160 /* credentials check */
161 #include <netinet/ip_fw.h>
162 #ifdef __linux__
163 int
164 cred_check(void *_insn,  int proto, struct ifnet *oif,
165     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
166     u_int16_t src_port, struct bsd_ucred *u, int *ugid_lookupp,
167     struct sk_buff *skb)
168 {
169         int match = 0;
170         ipfw_insn_u32 *insn = (ipfw_insn_u32 *)_insn;
171
172         if (*ugid_lookupp == 0) {        /* actively lookup and copy in cache */
173                 /* returns null if any element of the chain up to file is null.
174                  * if sk != NULL then we also have a reference
175                  */
176                 *ugid_lookupp = linux_lookup(proto,
177                         src_ip.s_addr, htons(src_port),
178                         dst_ip.s_addr, htons(dst_port),
179                         skb, oif ? 1 : 0, u);
180         }
181         if (*ugid_lookupp < 0)
182                 return 0;
183
184         if (insn->o.opcode == O_UID)
185                 match = (u->uid == (uid_t)insn->d[0]);
186         else if (insn->o.opcode == O_JAIL)
187                 match = (u->xid == (uid_t)insn->d[0]);
188         else if (insn->o.opcode == O_GID)
189                 match = (u->gid == (uid_t)insn->d[0]);
190         return match;
191 }
192 #endif  /* __linux__ */
193
194 int
195 jailed(struct ucred *cred)
196 {
197         return 0;
198 }
199
200 /*
201 * Return 1 if an internet address is for a ``local'' host
202 * (one to which we have a connection).  If subnetsarelocal
203 * is true, this includes other subnets of the local net.
204 * Otherwise, it includes only the directly-connected (sub)nets.
205 */
206 int
207 in_localaddr(struct in_addr in)
208 {
209         return 1;
210 }
211
212 int
213 sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
214 {
215         size_t valsize = sopt->sopt_valsize;
216
217         if (len < valsize)
218                 sopt->sopt_valsize = valsize = len;
219         //printf("copyout buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
220         bcopy(buf, sopt->sopt_val, valsize);
221         return 0;
222 }
223
224 /*
225  * copy data from userland to kernel
226  */
227 int
228 sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
229 {
230         size_t valsize = sopt->sopt_valsize;
231
232         if (valsize < minlen)
233                 return EINVAL;
234         if (valsize > len)
235                 sopt->sopt_valsize = valsize = len;
236         //printf("copyin buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
237         bcopy(sopt->sopt_val, buf, valsize);
238         return 0;
239 }
240
241 void
242 getmicrouptime(struct timeval *tv)
243 {
244         do_gettimeofday(tv);
245 }
246
247
248 #include <arpa/inet.h>
249
250 char *
251 inet_ntoa_r(struct in_addr ina, char *buf)
252 {
253 #ifdef _WIN32
254 #else
255         unsigned char *ucp = (unsigned char *)&ina;
256
257         sprintf(buf, "%d.%d.%d.%d",
258         ucp[0] & 0xff,
259         ucp[1] & 0xff,
260         ucp[2] & 0xff,
261         ucp[3] & 0xff);
262 #endif
263         return buf;
264 }
265
266 char *
267 inet_ntoa(struct in_addr ina)
268 {
269         static char buf[16];
270         return inet_ntoa_r(ina, buf);
271 }
272
273 int
274 random(void)
275 {
276 #ifdef _WIN32
277         static unsigned long seed;
278         if (seed == 0) {
279                 LARGE_INTEGER tm;
280                 KeQuerySystemTime(&tm);
281                 seed = tm.LowPart;
282         }
283         return RtlRandomEx(&seed) & 0x7fffffff;
284 #else
285         int r;
286         get_random_bytes(&r, sizeof(r));
287         return r & 0x7fffffff; 
288 #endif
289 }
290
291
292 /*
293  * do_div really does a u64 / u32 bit division.
294  * we save the sign and convert to uint befor calling.
295  * We are safe just because we always call it with small operands.
296  */
297 int64_t
298 div64(int64_t a, int64_t b)
299 {
300 #ifdef _WIN32
301         int a1 = a, b1 = b;
302         return a1/b1;
303 #else
304         uint64_t ua, ub;
305         int sign = ((a>0)?1:-1) * ((b>0)?1:-1);
306
307         ua = ((a>0)?a:-a);
308         ub = ((b>0)?b:-b);
309         do_div(ua, ub);
310         return sign*ua;
311 #endif
312 }
313
314 #ifdef __MIPSEL__
315 size_t
316 strlcpy(char *dst, const char *src, size_t siz)
317 {
318         char *d = dst;
319         const char *s = src;
320         size_t n = siz;
321  
322         /* Copy as many bytes as will fit */
323         if (n != 0 && --n != 0) {
324                 do {
325                         if ((*d++ = *s++) == 0)
326                                 break;
327                 } while (--n != 0);
328         }
329
330         /* Not enough room in dst, add NUL and traverse rest of src */
331         if (n == 0) {
332                 if (siz != 0)
333                         *d = '\0';              /* NUL-terminate dst */
334                 while (*s++)
335                         ;
336         }
337
338         return(s - src - 1);    /* count does not include NUL */
339 }
340 #endif // __MIPSEL__
341
342 /*
343  * compact version of fnmatch.
344  */
345 int
346 fnmatch(const char *pattern, const char *string, int flags)
347 {
348         char s;
349
350         if (!string || !pattern)
351                 return 1;       /* no match */
352         while ( (s = *string++) ) {
353                 char p = *pattern++;
354                 if (p == '\0')          /* pattern is over, no match */
355                         return 1;
356                 if (p == '*')           /* wildcard, match */
357                         return 0;
358                 if (p == '.' || p == s) /* char match, continue */
359                         continue;
360                 return 1;               /* no match */
361         }
362         /* end of string, make sure the pattern is over too */
363         if (*pattern == '\0' || *pattern == '*')
364                 return 0;
365         return 1;       /* no match */
366 }
367
368 /* support for sysctl emulation.
369  * XXX this is actually MI code that should be enabled also on openwrt
370  */
371 #ifdef EMULATE_SYSCTL
372 static struct sysctltable GST;
373
374 int
375 kesysctl_emu_get(struct sockopt* sopt)
376 {
377         struct dn_id* oid = sopt->sopt_val;
378         struct sysctlhead* entry;
379         int sizeneeded = sizeof(struct dn_id) + GST.totalsize +
380                 sizeof(struct sysctlhead);
381         unsigned char* pstring;
382         unsigned char* pdata;
383         int i;
384         
385         if (sopt->sopt_valsize < sizeneeded) {
386                 // this is a probe to retrieve the space needed for
387                 // a dump of the sysctl table
388                 oid->id = sizeneeded;
389                 sopt->sopt_valsize = sizeof(struct dn_id);
390                 return 0;
391         }
392         
393         entry = (struct sysctlhead*)(oid+1);
394         for( i=0; i<GST.count; i++) {
395                 entry->blocklen = GST.entry[i].head.blocklen;
396                 entry->namelen = GST.entry[i].head.namelen;
397                 entry->flags = GST.entry[i].head.flags;
398                 entry->datalen = GST.entry[i].head.datalen;
399                 pdata = (unsigned char*)(entry+1);
400                 pstring = pdata+GST.entry[i].head.datalen;
401                 bcopy(GST.entry[i].data, pdata, GST.entry[i].head.datalen);
402                 bcopy(GST.entry[i].name, pstring, GST.entry[i].head.namelen);
403                 entry = (struct sysctlhead*)
404                         ((unsigned char*)(entry) + GST.entry[i].head.blocklen);
405         }
406         sopt->sopt_valsize = sizeneeded;
407         return 0;
408 }
409
410 int
411 kesysctl_emu_set(void* p, int l)
412 {
413         struct sysctlhead* entry;
414         unsigned char* pdata;
415         unsigned char* pstring;
416         int i = 0;
417         
418         entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
419         pdata = (unsigned char*)(entry+1);
420         pstring = pdata + entry->datalen;
421         
422         for (i=0; i<GST.count; i++) {
423                 if (strcmp(GST.entry[i].name, pstring) != 0)
424                         continue;
425                 printf("%s: match found! %s\n",__FUNCTION__,pstring);
426                 //sanity check on len, not really useful now since
427                 //we only accept int32
428                 if (entry->datalen != GST.entry[i].head.datalen) {
429                         printf("%s: len mismatch, user %d vs kernel %d\n",
430                                 __FUNCTION__, entry->datalen,
431                                 GST.entry[i].head.datalen);
432                         return -1;
433                 }
434                 // check access (at the moment flags handles only the R/W rights
435                 //later on will be type + access
436                 if( (GST.entry[i].head.flags & 3) == CTLFLAG_RD) {
437                         printf("%s: the entry %s is read only\n",
438                                 __FUNCTION__,GST.entry[i].name);
439                         return -1;
440                 }
441                 bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
442                 return 0;
443         }
444         printf("%s: match not found\n",__FUNCTION__);
445         return 0;
446 }
447
448 /* convert all _ to . until the first . */
449 static void
450 underscoretopoint(char* s)
451 {
452         for (; *s && *s != '.'; s++)
453                 if (*s == '_')
454                         *s = '.';
455 }
456
457 static int
458 formatnames()
459 {
460         int i;
461         int size=0;
462         char* name;
463
464         for (i=0; i<GST.count; i++)
465                 size += GST.entry[i].head.namelen;
466         GST.namebuffer = malloc(size, 0, 0);
467         if (GST.namebuffer == NULL)
468                 return -1;
469         name = GST.namebuffer;
470         for (i=0; i<GST.count; i++) {
471                 bcopy(GST.entry[i].name, name, GST.entry[i].head.namelen);
472                 underscoretopoint(name);
473                 GST.entry[i].name = name;
474                 name += GST.entry[i].head.namelen;
475         }
476         return 0;
477 }
478
479 static void
480 dumpGST()
481 {
482         int i;
483
484         for (i=0; i<GST.count; i++) {
485                 printf("SYSCTL: entry %i\n", i);
486                 printf("name %s\n", GST.entry[i].name);
487                 printf("namelen %i\n", GST.entry[i].head.namelen);
488                 printf("type %i access %i\n",
489                         GST.entry[i].head.flags >> 2,
490                         GST.entry[i].head.flags & 0x00000003);
491                 printf("data %i\n", *(int*)(GST.entry[i].data));
492                 printf("datalen %i\n", GST.entry[i].head.datalen);
493                 printf("blocklen %i\n", GST.entry[i].head.blocklen);
494         }
495 }
496
497 void sysctl_addgroup_f1();
498 void sysctl_addgroup_f2();
499 void sysctl_addgroup_f3();
500 void sysctl_addgroup_f4();
501
502 void
503 keinit_GST()
504 {
505         int ret;
506
507         sysctl_addgroup_f1();
508         sysctl_addgroup_f2();
509         sysctl_addgroup_f3();
510         sysctl_addgroup_f4();
511         ret = formatnames();
512         if (ret != 0)
513                 printf("conversion of names failed for some reason\n");
514         //dumpGST();
515         printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
516                 GST.count, GST.totalsize);
517 }
518
519 void
520 keexit_GST()
521 {
522         if (GST.namebuffer != NULL)
523                 free(GST.namebuffer,0);
524         bzero(&GST, sizeof(GST));
525 }
526
527 void
528 sysctl_pushback(char* name, int flags, int datalen, void* data)
529 {
530         if (GST.count >= GST_HARD_LIMIT) {
531                 printf("WARNING: global sysctl table full, this entry will not be added,"
532                                 "please recompile the module increasing the table size\n");
533                 return;
534         }
535         GST.entry[GST.count].head.namelen = strlen(name)+1; //add space for '\0'
536         GST.entry[GST.count].name = name;
537         GST.entry[GST.count].head.flags = flags;
538         GST.entry[GST.count].data = data;
539         GST.entry[GST.count].head.datalen = datalen;
540         GST.entry[GST.count].head.blocklen =
541                 ((sizeof(struct sysctlhead) + GST.entry[GST.count].head.namelen +
542                         GST.entry[GST.count].head.datalen)+3) & ~3;
543         GST.totalsize += GST.entry[GST.count].head.blocklen;
544         GST.count++;
545 }
546 #endif /* EMULATE_SYSCTL */