This repo is obsolete, please see git://git.code.sf.net/p/dummynet/code@master
[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 6320 2010-05-24 11:54:36Z svn_panicucci $
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 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
376 inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
377 {
378         skb->dst = dst;
379 }
380
381 inline struct dst_entry *skb_dst(const struct sk_buff *skb)
382 {
383         return (struct dst_entry *)skb->dst;
384 }
385 #endif
386
387
388 /* support for sysctl emulation.
389  * XXX this is actually MI code that should be enabled also on openwrt
390  */
391 #ifdef EMULATE_SYSCTL
392 static struct sysctltable GST;
393
394 int
395 kesysctl_emu_get(struct sockopt* sopt)
396 {
397         struct dn_id* oid = sopt->sopt_val;
398         struct sysctlhead* entry;
399         int sizeneeded = sizeof(struct dn_id) + GST.totalsize +
400                 sizeof(struct sysctlhead);
401         unsigned char* pstring;
402         unsigned char* pdata;
403         int i;
404         
405         if (sopt->sopt_valsize < sizeneeded) {
406                 // this is a probe to retrieve the space needed for
407                 // a dump of the sysctl table
408                 oid->id = sizeneeded;
409                 sopt->sopt_valsize = sizeof(struct dn_id);
410                 return 0;
411         }
412         
413         entry = (struct sysctlhead*)(oid+1);
414         for( i=0; i<GST.count; i++) {
415                 entry->blocklen = GST.entry[i].head.blocklen;
416                 entry->namelen = GST.entry[i].head.namelen;
417                 entry->flags = GST.entry[i].head.flags;
418                 entry->datalen = GST.entry[i].head.datalen;
419                 pdata = (unsigned char*)(entry+1);
420                 pstring = pdata+GST.entry[i].head.datalen;
421                 bcopy(GST.entry[i].data, pdata, GST.entry[i].head.datalen);
422                 bcopy(GST.entry[i].name, pstring, GST.entry[i].head.namelen);
423                 entry = (struct sysctlhead*)
424                         ((unsigned char*)(entry) + GST.entry[i].head.blocklen);
425         }
426         sopt->sopt_valsize = sizeneeded;
427         return 0;
428 }
429
430 int
431 kesysctl_emu_set(void* p, int l)
432 {
433         struct sysctlhead* entry;
434         unsigned char* pdata;
435         unsigned char* pstring;
436         int i = 0;
437         
438         entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
439         pdata = (unsigned char*)(entry+1);
440         pstring = pdata + entry->datalen;
441         
442         for (i=0; i<GST.count; i++) {
443                 if (strcmp(GST.entry[i].name, pstring) != 0)
444                         continue;
445                 printf("%s: match found! %s\n",__FUNCTION__,pstring);
446                 //sanity check on len, not really useful now since
447                 //we only accept int32
448                 if (entry->datalen != GST.entry[i].head.datalen) {
449                         printf("%s: len mismatch, user %d vs kernel %d\n",
450                                 __FUNCTION__, entry->datalen,
451                                 GST.entry[i].head.datalen);
452                         return -1;
453                 }
454                 // check access (at the moment flags handles only the R/W rights
455                 //later on will be type + access
456                 if( (GST.entry[i].head.flags & 3) == CTLFLAG_RD) {
457                         printf("%s: the entry %s is read only\n",
458                                 __FUNCTION__,GST.entry[i].name);
459                         return -1;
460                 }
461                 bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
462                 return 0;
463         }
464         printf("%s: match not found\n",__FUNCTION__);
465         return 0;
466 }
467
468 /* convert all _ to . until the first . */
469 static void
470 underscoretopoint(char* s)
471 {
472         for (; *s && *s != '.'; s++)
473                 if (*s == '_')
474                         *s = '.';
475 }
476
477 static int
478 formatnames()
479 {
480         int i;
481         int size=0;
482         char* name;
483
484         for (i=0; i<GST.count; i++)
485                 size += GST.entry[i].head.namelen;
486         GST.namebuffer = malloc(size, 0, 0);
487         if (GST.namebuffer == NULL)
488                 return -1;
489         name = GST.namebuffer;
490         for (i=0; i<GST.count; i++) {
491                 bcopy(GST.entry[i].name, name, GST.entry[i].head.namelen);
492                 underscoretopoint(name);
493                 GST.entry[i].name = name;
494                 name += GST.entry[i].head.namelen;
495         }
496         return 0;
497 }
498
499 static void
500 dumpGST()
501 {
502         int i;
503
504         for (i=0; i<GST.count; i++) {
505                 printf("SYSCTL: entry %i\n", i);
506                 printf("name %s\n", GST.entry[i].name);
507                 printf("namelen %i\n", GST.entry[i].head.namelen);
508                 printf("type %i access %i\n",
509                         GST.entry[i].head.flags >> 2,
510                         GST.entry[i].head.flags & 0x00000003);
511                 printf("data %i\n", *(int*)(GST.entry[i].data));
512                 printf("datalen %i\n", GST.entry[i].head.datalen);
513                 printf("blocklen %i\n", GST.entry[i].head.blocklen);
514         }
515 }
516
517 void sysctl_addgroup_f1();
518 void sysctl_addgroup_f2();
519 void sysctl_addgroup_f3();
520 void sysctl_addgroup_f4();
521
522 void
523 keinit_GST()
524 {
525         int ret;
526
527         sysctl_addgroup_f1();
528         sysctl_addgroup_f2();
529         sysctl_addgroup_f3();
530         sysctl_addgroup_f4();
531         ret = formatnames();
532         if (ret != 0)
533                 printf("conversion of names failed for some reason\n");
534         //dumpGST();
535         printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
536                 GST.count, GST.totalsize);
537 }
538
539 void
540 keexit_GST()
541 {
542         if (GST.namebuffer != NULL)
543                 free(GST.namebuffer,0);
544         bzero(&GST, sizeof(GST));
545 }
546
547 void
548 sysctl_pushback(char* name, int flags, int datalen, void* data)
549 {
550         if (GST.count >= GST_HARD_LIMIT) {
551                 printf("WARNING: global sysctl table full, this entry will not be added,"
552                                 "please recompile the module increasing the table size\n");
553                 return;
554         }
555         GST.entry[GST.count].head.namelen = strlen(name)+1; //add space for '\0'
556         GST.entry[GST.count].name = name;
557         GST.entry[GST.count].head.flags = flags;
558         GST.entry[GST.count].data = data;
559         GST.entry[GST.count].head.datalen = datalen;
560         GST.entry[GST.count].head.blocklen =
561                 ((sizeof(struct sysctlhead) + GST.entry[GST.count].head.namelen +
562                         GST.entry[GST.count].head.datalen)+3) & ~3;
563         GST.totalsize += GST.entry[GST.count].head.blocklen;
564         GST.count++;
565 }
566 #endif /* EMULATE_SYSCTL */