2 * Copyright (C) 2009 Luigi Rizzo, Marta Carbone, Universita` di Pisa
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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
27 * $Id: bsd_compat.c 5813 2010-03-22 18:05:13Z svn_magno $
29 * kernel variables and functions that are not available in linux.
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>
40 * gettimeofday would be in sys/time.h but it is not
41 * visible if _KERNEL is defined
43 int gettimeofday(struct timeval *, struct timezone *);
45 int ticks; /* kernel ticks counter */
46 int hz = 1000; /* default clock time */
47 long tick = 1000; /* XXX is this 100000/hz ? */
49 struct timeval boottime;
53 u_long in_ifaddrhmask; /* mask for hash table */
54 struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */
56 u_int rt_numfibs = RT_NUMFIBS;
60 * We make pfil_head_get return a non-null pointer, which is then ignored
61 * in our 'add-hook' routines.
64 typedef int (pfil_hook_t)
65 (void *, struct mbuf **, struct ifnet *, int, struct inpcb *);
68 pfil_head_get(int proto, u_long flags)
71 return (struct pfil_head *)&dummy;
75 pfil_add_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
81 pfil_remove_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
86 /* define empty body for kernel function */
88 priv_check(struct thread *td, int priv)
94 securelevel_ge(struct ucred *cr, int level)
100 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
106 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
112 ether_demux(struct ifnet *ifp, struct mbuf *m)
118 ether_output_frame(struct ifnet *ifp, struct mbuf *m)
124 in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)
130 icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu)
136 in_cksum_skip(struct mbuf *m, int len, int skip)
142 in_cksum_hdr(struct ip *ip)
148 * we don't really reassemble, just return whatever we had.
151 ip_reass(struct mbuf *clone)
155 #ifdef INP_LOCK_ASSERT
156 #undef INP_LOCK_ASSERT
157 #define INP_LOCK_ASSERT(a)
160 /* credentials check */
161 #include <netinet/ip_fw.h>
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,
170 ipfw_insn_u32 *insn = (ipfw_insn_u32 *)_insn;
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
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);
181 if (*ugid_lookupp < 0)
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]);
192 #endif /* __linux__ */
195 jailed(struct ucred *cred)
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.
207 in_localaddr(struct in_addr in)
213 sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
215 size_t valsize = sopt->sopt_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);
225 * copy data from userland to kernel
228 sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
230 size_t valsize = sopt->sopt_valsize;
232 if (valsize < minlen)
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);
242 getmicrouptime(struct timeval *tv)
248 #include <arpa/inet.h>
251 inet_ntoa_r(struct in_addr ina, char *buf)
255 unsigned char *ucp = (unsigned char *)&ina;
257 sprintf(buf, "%d.%d.%d.%d",
267 inet_ntoa(struct in_addr ina)
270 return inet_ntoa_r(ina, buf);
277 static unsigned long seed;
280 KeQuerySystemTime(&tm);
283 return RtlRandomEx(&seed) & 0x7fffffff;
286 get_random_bytes(&r, sizeof(r));
287 return r & 0x7fffffff;
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.
298 div64(int64_t a, int64_t b)
305 int sign = ((a>0)?1:-1) * ((b>0)?1:-1);
316 strlcpy(char *dst, const char *src, size_t siz)
322 /* Copy as many bytes as will fit */
323 if (n != 0 && --n != 0) {
325 if ((*d++ = *s++) == 0)
330 /* Not enough room in dst, add NUL and traverse rest of src */
333 *d = '\0'; /* NUL-terminate dst */
338 return(s - src - 1); /* count does not include NUL */
343 * compact version of fnmatch.
346 fnmatch(const char *pattern, const char *string, int flags)
350 if (!string || !pattern)
351 return 1; /* no match */
352 while ( (s = *string++) ) {
354 if (p == '\0') /* pattern is over, no match */
356 if (p == '*') /* wildcard, match */
358 if (p == '.' || p == s) /* char match, continue */
360 return 1; /* no match */
362 /* end of string, make sure the pattern is over too */
363 if (*pattern == '\0' || *pattern == '*')
365 return 1; /* no match */
368 /* support for sysctl emulation.
369 * XXX this is actually MI code that should be enabled also on openwrt
371 #ifdef EMULATE_SYSCTL
372 static struct sysctltable GST;
375 kesysctl_emu_get(struct sockopt* sopt)
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;
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);
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);
406 sopt->sopt_valsize = sizeneeded;
411 kesysctl_emu_set(void* p, int l)
413 struct sysctlhead* entry;
414 unsigned char* pdata;
415 unsigned char* pstring;
418 entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
419 pdata = (unsigned char*)(entry+1);
420 pstring = pdata + entry->datalen;
422 for (i=0; i<GST.count; i++) {
423 if (strcmp(GST.entry[i].name, pstring) != 0)
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);
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);
441 bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
444 printf("%s: match not found\n",__FUNCTION__);
448 /* convert all _ to . until the first . */
450 underscoretopoint(char* s)
452 for (; *s && *s != '.'; s++)
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)
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;
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);
497 void sysctl_addgroup_f1();
498 void sysctl_addgroup_f2();
499 void sysctl_addgroup_f3();
500 void sysctl_addgroup_f4();
507 sysctl_addgroup_f1();
508 sysctl_addgroup_f2();
509 sysctl_addgroup_f3();
510 sysctl_addgroup_f4();
513 printf("conversion of names failed for some reason\n");
515 printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
516 GST.count, GST.totalsize);
522 if (GST.namebuffer != NULL)
523 free(GST.namebuffer,0);
524 bzero(&GST, sizeof(GST));
528 sysctl_pushback(char* name, int flags, int datalen, void* data)
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");
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;
546 #endif /* EMULATE_SYSCTL */