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 6320 2010-05-24 11:54:36Z svn_panicucci $
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;
51 int ip_defttl = 64; /* XXX set default value */
54 u_long in_ifaddrhmask; /* mask for hash table */
55 struct in_ifaddrhashhead *in_ifaddrhashtbl; /* inet addr hash table */
57 u_int rt_numfibs = RT_NUMFIBS;
61 * We make pfil_head_get return a non-null pointer, which is then ignored
62 * in our 'add-hook' routines.
65 typedef int (pfil_hook_t)
66 (void *, struct mbuf **, struct ifnet *, int, struct inpcb *);
69 pfil_head_get(int proto, u_long flags)
72 return (struct pfil_head *)&dummy;
76 pfil_add_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
82 pfil_remove_hook(pfil_hook_t *func, void *arg, int dir, struct pfil_head *h)
87 /* define empty body for kernel function */
89 priv_check(struct thread *td, int priv)
95 securelevel_ge(struct ucred *cr, int level)
101 sysctl_handle_int(SYSCTL_HANDLER_ARGS)
107 sysctl_handle_long(SYSCTL_HANDLER_ARGS)
113 ether_demux(struct ifnet *ifp, struct mbuf *m)
119 ether_output_frame(struct ifnet *ifp, struct mbuf *m)
125 in_rtalloc_ign(struct route *ro, u_long ignflags, u_int fibnum)
131 icmp_error(struct mbuf *n, int type, int code, uint32_t dest, int mtu)
137 in_cksum_skip(struct mbuf *m, int len, int skip)
143 in_cksum_hdr(struct ip *ip)
149 * we don't really reassemble, just return whatever we had.
152 ip_reass(struct mbuf *clone)
156 #ifdef INP_LOCK_ASSERT
157 #undef INP_LOCK_ASSERT
158 #define INP_LOCK_ASSERT(a)
161 /* credentials check */
162 #include <netinet/ip_fw.h>
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,
171 ipfw_insn_u32 *insn = (ipfw_insn_u32 *)_insn;
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
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);
182 if (*ugid_lookupp < 0)
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]);
193 #endif /* __linux__ */
196 jailed(struct ucred *cred)
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.
208 in_localaddr(struct in_addr in)
214 sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
216 size_t valsize = sopt->sopt_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);
226 * copy data from userland to kernel
229 sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
231 size_t valsize = sopt->sopt_valsize;
233 if (valsize < minlen)
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);
243 getmicrouptime(struct timeval *tv)
249 #include <arpa/inet.h>
252 inet_ntoa_r(struct in_addr ina, char *buf)
256 unsigned char *ucp = (unsigned char *)&ina;
258 sprintf(buf, "%d.%d.%d.%d",
268 inet_ntoa(struct in_addr ina)
271 return inet_ntoa_r(ina, buf);
278 static unsigned long seed;
281 KeQuerySystemTime(&tm);
284 return RtlRandomEx(&seed) & 0x7fffffff;
287 get_random_bytes(&r, sizeof(r));
288 return r & 0x7fffffff;
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.
299 div64(int64_t a, int64_t b)
306 int sign = ((a>0)?1:-1) * ((b>0)?1:-1);
317 strlcpy(char *dst, const char *src, size_t siz)
323 /* Copy as many bytes as will fit */
324 if (n != 0 && --n != 0) {
326 if ((*d++ = *s++) == 0)
331 /* Not enough room in dst, add NUL and traverse rest of src */
334 *d = '\0'; /* NUL-terminate dst */
339 return(s - src - 1); /* count does not include NUL */
344 * compact version of fnmatch.
347 fnmatch(const char *pattern, const char *string, int flags)
351 if (!string || !pattern)
352 return 1; /* no match */
353 while ( (s = *string++) ) {
355 if (p == '\0') /* pattern is over, no match */
357 if (p == '*') /* wildcard, match */
359 if (p == '.' || p == s) /* char match, continue */
361 return 1; /* no match */
363 /* end of string, make sure the pattern is over too */
364 if (*pattern == '\0' || *pattern == '*')
366 return 1; /* no match */
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.
375 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
376 inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
381 inline struct dst_entry *skb_dst(const struct sk_buff *skb)
383 return (struct dst_entry *)skb->dst;
388 /* support for sysctl emulation.
389 * XXX this is actually MI code that should be enabled also on openwrt
391 #ifdef EMULATE_SYSCTL
392 static struct sysctltable GST;
395 kesysctl_emu_get(struct sockopt* sopt)
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;
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);
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);
426 sopt->sopt_valsize = sizeneeded;
431 kesysctl_emu_set(void* p, int l)
433 struct sysctlhead* entry;
434 unsigned char* pdata;
435 unsigned char* pstring;
438 entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
439 pdata = (unsigned char*)(entry+1);
440 pstring = pdata + entry->datalen;
442 for (i=0; i<GST.count; i++) {
443 if (strcmp(GST.entry[i].name, pstring) != 0)
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);
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);
461 bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
464 printf("%s: match not found\n",__FUNCTION__);
468 /* convert all _ to . until the first . */
470 underscoretopoint(char* s)
472 for (; *s && *s != '.'; s++)
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)
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;
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);
517 void sysctl_addgroup_f1();
518 void sysctl_addgroup_f2();
519 void sysctl_addgroup_f3();
520 void sysctl_addgroup_f4();
527 sysctl_addgroup_f1();
528 sysctl_addgroup_f2();
529 sysctl_addgroup_f3();
530 sysctl_addgroup_f4();
533 printf("conversion of names failed for some reason\n");
535 printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
536 GST.count, GST.totalsize);
542 if (GST.namebuffer != NULL)
543 free(GST.namebuffer,0);
544 bzero(&GST, sizeof(GST));
548 sysctl_pushback(char* name, int flags, int datalen, void* data)
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");
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;
566 #endif /* EMULATE_SYSCTL */