This repo is obsolete, please see git://git.code.sf.net/p/dummynet/code@master
[ipfw.git] / dummynet2 / bsd_compat.c
index 70268bb..1397951 100644 (file)
@@ -24,7 +24,7 @@
  */
 
 /*
- * $Id: bsd_compat.c 4665 2010-01-04 12:35:39Z luigi $
+ * $Id: bsd_compat.c 6320 2010-05-24 11:54:36Z svn_panicucci $
  *
  * kernel variables and functions that are not available in linux.
  */
@@ -32,6 +32,9 @@
 #include <sys/cdefs.h>
 #include <asm/div64.h> /* do_div on 2.4 */
 #include <linux/random.h>      /* get_random_bytes on 2.4 */
+#include <netinet/ip_fw.h>
+#include <netinet/ip_dummynet.h>
+#include <sys/malloc.h>
 
 /*
  * gettimeofday would be in sys/time.h but it is not
@@ -43,10 +46,10 @@ int ticks;          /* kernel ticks counter */
 int hz = 1000;         /* default clock time */
 long tick = 1000;      /* XXX is this 100000/hz ? */
 int bootverbose = 0;
-time_t time_uptime = 0;
 struct timeval boottime;
 
-int     ip_defttl;
+int     ip_defttl = 64;        /* XXX set default value */
+int    max_linkhdr = 16;
 int fw_one_pass = 1;
 u_long  in_ifaddrhmask;                         /* mask for hash table */
 struct  in_ifaddrhashhead *in_ifaddrhashtbl;    /* inet addr hash table  */
@@ -157,6 +160,7 @@ ip_reass(struct mbuf *clone)
 
 /* credentials check */
 #include <netinet/ip_fw.h>
+#ifdef __linux__
 int
 cred_check(void *_insn,  int proto, struct ifnet *oif,
     struct in_addr dst_ip, u_int16_t dst_port, struct in_addr src_ip,
@@ -186,6 +190,7 @@ cred_check(void *_insn,  int proto, struct ifnet *oif,
                match = (u->gid == (uid_t)insn->d[0]);
        return match;
 }
+#endif /* __linux__ */
 
 int
 jailed(struct ucred *cred)
@@ -212,6 +217,7 @@ sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
 
        if (len < valsize)
                sopt->sopt_valsize = valsize = len;
+       //printf("copyout buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
        bcopy(buf, sopt->sopt_val, valsize);
        return 0;
 }
@@ -228,6 +234,7 @@ sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
                return EINVAL;
        if (valsize > len)
                sopt->sopt_valsize = valsize = len;
+       //printf("copyin buf = %p, sopt = %p, soptval = %p, len = %d \n", buf, sopt, sopt->sopt_val, len);
        bcopy(sopt->sopt_val, buf, valsize);
        return 0;
 }
@@ -235,10 +242,7 @@ sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
 void
 getmicrouptime(struct timeval *tv)
 {
-#ifdef _WIN32
-#else
        do_gettimeofday(tv);
-#endif
 }
 
 
@@ -271,7 +275,13 @@ int
 random(void)
 {
 #ifdef _WIN32
-       return 0x123456;
+       static unsigned long seed;
+       if (seed == 0) {
+               LARGE_INTEGER tm;
+               KeQuerySystemTime(&tm);
+               seed = tm.LowPart;
+       }
+       return RtlRandomEx(&seed) & 0x7fffffff;
 #else
        int r;
        get_random_bytes(&r, sizeof(r));
@@ -302,6 +312,34 @@ div64(int64_t a, int64_t b)
 #endif
 }
 
+#ifdef __MIPSEL__
+size_t
+strlcpy(char *dst, const char *src, size_t siz)
+{
+        char *d = dst;
+        const char *s = src;
+        size_t n = siz;
+        /* Copy as many bytes as will fit */
+        if (n != 0 && --n != 0) {
+                do {
+                        if ((*d++ = *s++) == 0)
+                                break;
+                } while (--n != 0);
+        }
+
+        /* Not enough room in dst, add NUL and traverse rest of src */
+        if (n == 0) {
+                if (siz != 0)
+                        *d = '\0';              /* NUL-terminate dst */
+                while (*s++)
+                        ;
+        }
+
+        return(s - src - 1);    /* count does not include NUL */
+}
+#endif // __MIPSEL__
+
 /*
  * compact version of fnmatch.
  */
@@ -328,43 +366,201 @@ fnmatch(const char *pattern, const char *string, int flags)
        return 1;       /* no match */
 }
 
-#ifdef _WIN32
+
 /*
- * as good as anywhere, place here the missing calls
+ * linux 2.6.33 defines these functions to access to
+ * skbuff internal structures. Define the missing
+ * function for the previous versions too.
  */
-
-void *
-my_alloc(int size)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,31)
+inline void skb_dst_set(struct sk_buff *skb, struct dst_entry *dst)
 {
-       void *_ret = ExAllocatePoolWithTag(0, size, 'wfpi');
-       if (_ret)
-               memset(_ret, 0, size);
-       return _ret;
+        skb->dst = dst;
 }
 
-void
-panic(const char *fmt, ...)
+inline struct dst_entry *skb_dst(const struct sk_buff *skb)
 {
-       printf("%s", fmt);
-       for (;;);
+        return (struct dst_entry *)skb->dst;
 }
+#endif
 
-#include <stdarg.h>
-
-extern int _vsnprintf(char *buf, int buf_size, char * fmt, va_list ap);
 
-/*
- * Windows' _snprintf doesn't terminate buffer with zero if size > buf_size
+/* support for sysctl emulation.
+ * XXX this is actually MI code that should be enabled also on openwrt
  */
+#ifdef EMULATE_SYSCTL
+static struct sysctltable GST;
+
 int
-snprintf(char *buf, int buf_size, char *fmt, ...)
+kesysctl_emu_get(struct sockopt* sopt)
 {
-    va_list ap;
-    va_start(ap, fmt);
-    if (_vsnprintf(buf, buf_size, fmt, ap) < 0)
-        buf[buf_size - 1] = '\0';
-    va_end(ap);
+       struct dn_id* oid = sopt->sopt_val;
+       struct sysctlhead* entry;
+       int sizeneeded = sizeof(struct dn_id) + GST.totalsize +
+               sizeof(struct sysctlhead);
+       unsigned char* pstring;
+       unsigned char* pdata;
+       int i;
+       
+       if (sopt->sopt_valsize < sizeneeded) {
+               // this is a probe to retrieve the space needed for
+               // a dump of the sysctl table
+               oid->id = sizeneeded;
+               sopt->sopt_valsize = sizeof(struct dn_id);
+               return 0;
+       }
+       
+       entry = (struct sysctlhead*)(oid+1);
+       for( i=0; i<GST.count; i++) {
+               entry->blocklen = GST.entry[i].head.blocklen;
+               entry->namelen = GST.entry[i].head.namelen;
+               entry->flags = GST.entry[i].head.flags;
+               entry->datalen = GST.entry[i].head.datalen;
+               pdata = (unsigned char*)(entry+1);
+               pstring = pdata+GST.entry[i].head.datalen;
+               bcopy(GST.entry[i].data, pdata, GST.entry[i].head.datalen);
+               bcopy(GST.entry[i].name, pstring, GST.entry[i].head.namelen);
+               entry = (struct sysctlhead*)
+                       ((unsigned char*)(entry) + GST.entry[i].head.blocklen);
+       }
+       sopt->sopt_valsize = sizeneeded;
+       return 0;
+}
 
-    return 0;
+int
+kesysctl_emu_set(void* p, int l)
+{
+       struct sysctlhead* entry;
+       unsigned char* pdata;
+       unsigned char* pstring;
+       int i = 0;
+       
+       entry = (struct sysctlhead*)(((struct dn_id*)p)+1);
+       pdata = (unsigned char*)(entry+1);
+       pstring = pdata + entry->datalen;
+       
+       for (i=0; i<GST.count; i++) {
+               if (strcmp(GST.entry[i].name, pstring) != 0)
+                       continue;
+               printf("%s: match found! %s\n",__FUNCTION__,pstring);
+               //sanity check on len, not really useful now since
+               //we only accept int32
+               if (entry->datalen != GST.entry[i].head.datalen) {
+                       printf("%s: len mismatch, user %d vs kernel %d\n",
+                               __FUNCTION__, entry->datalen,
+                               GST.entry[i].head.datalen);
+                       return -1;
+               }
+               // check access (at the moment flags handles only the R/W rights
+               //later on will be type + access
+               if( (GST.entry[i].head.flags & 3) == CTLFLAG_RD) {
+                       printf("%s: the entry %s is read only\n",
+                               __FUNCTION__,GST.entry[i].name);
+                       return -1;
+               }
+               bcopy(pdata, GST.entry[i].data, GST.entry[i].head.datalen);
+               return 0;
+       }
+       printf("%s: match not found\n",__FUNCTION__);
+       return 0;
 }
-#endif
+
+/* convert all _ to . until the first . */
+static void
+underscoretopoint(char* s)
+{
+       for (; *s && *s != '.'; s++)
+               if (*s == '_')
+                       *s = '.';
+}
+
+static int
+formatnames()
+{
+       int i;
+       int size=0;
+       char* name;
+
+       for (i=0; i<GST.count; i++)
+               size += GST.entry[i].head.namelen;
+       GST.namebuffer = malloc(size, 0, 0);
+       if (GST.namebuffer == NULL)
+               return -1;
+       name = GST.namebuffer;
+       for (i=0; i<GST.count; i++) {
+               bcopy(GST.entry[i].name, name, GST.entry[i].head.namelen);
+               underscoretopoint(name);
+               GST.entry[i].name = name;
+               name += GST.entry[i].head.namelen;
+       }
+       return 0;
+}
+
+static void
+dumpGST()
+{
+       int i;
+
+       for (i=0; i<GST.count; i++) {
+               printf("SYSCTL: entry %i\n", i);
+               printf("name %s\n", GST.entry[i].name);
+               printf("namelen %i\n", GST.entry[i].head.namelen);
+               printf("type %i access %i\n",
+                       GST.entry[i].head.flags >> 2,
+                       GST.entry[i].head.flags & 0x00000003);
+               printf("data %i\n", *(int*)(GST.entry[i].data));
+               printf("datalen %i\n", GST.entry[i].head.datalen);
+               printf("blocklen %i\n", GST.entry[i].head.blocklen);
+       }
+}
+
+void sysctl_addgroup_f1();
+void sysctl_addgroup_f2();
+void sysctl_addgroup_f3();
+void sysctl_addgroup_f4();
+
+void
+keinit_GST()
+{
+       int ret;
+
+       sysctl_addgroup_f1();
+       sysctl_addgroup_f2();
+       sysctl_addgroup_f3();
+       sysctl_addgroup_f4();
+       ret = formatnames();
+       if (ret != 0)
+               printf("conversion of names failed for some reason\n");
+       //dumpGST();
+       printf("*** Global Sysctl Table entries = %i, total size = %i ***\n",
+               GST.count, GST.totalsize);
+}
+
+void
+keexit_GST()
+{
+       if (GST.namebuffer != NULL)
+               free(GST.namebuffer,0);
+       bzero(&GST, sizeof(GST));
+}
+
+void
+sysctl_pushback(char* name, int flags, int datalen, void* data)
+{
+       if (GST.count >= GST_HARD_LIMIT) {
+               printf("WARNING: global sysctl table full, this entry will not be added,"
+                               "please recompile the module increasing the table size\n");
+               return;
+       }
+       GST.entry[GST.count].head.namelen = strlen(name)+1; //add space for '\0'
+       GST.entry[GST.count].name = name;
+       GST.entry[GST.count].head.flags = flags;
+       GST.entry[GST.count].data = data;
+       GST.entry[GST.count].head.datalen = datalen;
+       GST.entry[GST.count].head.blocklen =
+               ((sizeof(struct sysctlhead) + GST.entry[GST.count].head.namelen +
+                       GST.entry[GST.count].head.datalen)+3) & ~3;
+       GST.totalsize += GST.entry[GST.count].head.blocklen;
+       GST.count++;
+}
+#endif /* EMULATE_SYSCTL */