The removal of the HAVE_NET_DEVICE_OPS in the kernel sources by David S. Miller makes it hard to implement compatibility code using compat.(c|h). Either the sources of the kernel and the external module have to diverge again or more complex workarounds have to be found.
Dropping support for kernels older than 2.6.29 will remove the dead ballast of stuff older than two years. People which need it can revert 7f1b7b837c205e413a7aa078a47ec96f0c11afa7 and this patch.
Signed-off-by: Sven Eckelmann sven@narfation.org --- compat.c | 991 +------------------------------------------------------------- compat.h | 236 +--------------- 2 files changed, 4 insertions(+), 1223 deletions(-)
diff --git a/compat.c b/compat.c index ebedae8..88ceb40 100644 --- a/compat.c +++ b/compat.c @@ -2,994 +2,7 @@ #include <linux/version.h> #include "main.h"
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) - -#include "bat_sysfs.h" /* struct bat_attribute */ - -ssize_t bat_wrapper_show(struct kobject *kobj, struct attribute *attr, - char *buf) -{ - struct bat_attribute *bat_attr = to_battr(attr); - - if (bat_attr->show) - return bat_attr->show(kobj, attr, buf); - - return -EIO; -} - -ssize_t bat_wrapper_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count) -{ - struct bat_attribute *bat_attr = to_battr(attr); - - if (bat_attr->store) - return bat_attr->store(kobj, attr, (char *)buf, count); - - return -EIO; -} - -#endif /* < KERNEL_VERSION(2, 6, 25) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - -/* - * linux/lib/vsprintf.c - * - * Copyright (C) 1991, 1992 Linus Torvalds - */ - -/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ -/* - * Wirzenius wrote this portably, Torvalds fucked it up :-) - */ - -/* - * Fri Jul 13 2001 Crutcher Dunnavant crutcher+kernel@datastacks.com - * - changed to provide snprintf and vsnprintf functions - * So Feb 1 16:51:32 CET 2004 Juergen Quade quade@hsnr.de - * - scnprintf and vscnprintf - */ - -#include <stdarg.h> -#include <linux/module.h> -#include <linux/types.h> -#include <linux/string.h> -#include <linux/ctype.h> -#include <linux/kernel.h> -#include <linux/kallsyms.h> -#include <linux/uaccess.h> -#include <linux/ioport.h> -#include <net/addrconf.h> - -#include <asm/page.h> /* for PAGE_SIZE */ -#include <asm/div64.h> -#include <asm/sections.h> /* for dereference_function_descriptor() */ - -#include "main.h" - -/* Works only for digits and letters, but small and fast */ -#define TOLOWER(x) ((x) | 0x20) - -/* We don't want to recursively call bat_printk here - because of the previous define in compat.h */ -#ifdef printk -#undef printk -#endif - -static int skip_atoi(const char **s) -{ - int i = 0; - - while (isdigit(**s)) - i = i*10 + *((*s)++) - '0'; - return i; -} - -/* Decimal conversion is by far the most typical, and is used - * for /proc and /sys data. This directly impacts e.g. top performance - * with many processes running. We optimize it for speed - * using code from - * http://www.cs.uiowa.edu/~jones/bcd/decimal.html - * (with permission from the author, Douglas W. Jones). */ - -/* Formats correctly any integer in [0,99999]. - * Outputs from one to five digits depending on input. - * On i386 gcc 4.1.2 -O2: ~250 bytes of code. */ -static char *put_dec_trunc(char *buf, unsigned q) -{ - unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); - - d0 = 6*(d3 + d2 + d1) + (q & 0xf); - q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; - *buf++ = d0 + '0'; /* least significant digit */ - d1 = q + 9*d3 + 5*d2 + d1; - if (d1 != 0) { - q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; /* next digit */ - - d2 = q + 2*d2; - if ((d2 != 0) || (d3 != 0)) { - q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; /* next digit */ - - d3 = q + 4*d3; - if (d3 != 0) { - q = (d3 * 0xcd) >> 11; - d3 = d3 - 10*q; - *buf++ = d3 + '0'; /* next digit */ - if (q != 0) - /* most sign. digit */ - *buf++ = q + '0'; - } - } - } - return buf; -} -/* Same with if's removed. Always emits five digits */ -static char *put_dec_full(char *buf, unsigned q) -{ - /* BTW, if q is in [0,9999], 8-bit ints will be enough, */ - /* but anyway, gcc produces better code with full-sized ints */ - unsigned d3, d2, d1, d0; - d1 = (q>>4) & 0xf; - d2 = (q>>8) & 0xf; - d3 = (q>>12); - - /* Possible ways to approx. divide by 10 */ - /* gcc -O2 replaces multiply with shifts and adds */ - /* (x * 0xcd) >> 11: 11001101 - shorter code than * 0x67 (on i386) */ - /* (x * 0x67) >> 10: 1100111 */ - /* (x * 0x34) >> 9: 110100 - same */ - /* (x * 0x1a) >> 8: 11010 - same */ - /* (x * 0x0d) >> 7: 1101 - same, shortest code (on i386) */ - - d0 = 6*(d3 + d2 + d1) + (q & 0xf); - q = (d0 * 0xcd) >> 11; - d0 = d0 - 10*q; - *buf++ = d0 + '0'; - d1 = q + 9*d3 + 5*d2 + d1; - q = (d1 * 0xcd) >> 11; - d1 = d1 - 10*q; - *buf++ = d1 + '0'; - - d2 = q + 2*d2; - q = (d2 * 0xd) >> 7; - d2 = d2 - 10*q; - *buf++ = d2 + '0'; - - d3 = q + 4*d3; - q = (d3 * 0xcd) >> 11; /* - shorter code */ - /* q = (d3 * 0x67) >> 10; - would also work */ - d3 = d3 - 10*q; - *buf++ = d3 + '0'; - *buf++ = q + '0'; - return buf; -} -/* No inlining helps gcc to use registers better */ -static noinline char *put_dec(char *buf, unsigned long long num) -{ - while (1) { - unsigned rem; - if (num < 100000) - return put_dec_trunc(buf, num); - rem = do_div(num, 100000); - buf = put_dec_full(buf, rem); - } -} - -#define ZEROPAD 1 /* pad with zero */ -#define SIGN 2 /* unsigned/signed long */ -#define PLUS 4 /* show plus */ -#define SPACE 8 /* space if plus */ -#define LEFT 16 /* left justified */ -#define SMALL 32 /* Must be 32 == 0x20 */ -#define SPECIAL 64 /* 0x */ - -enum format_type { - FORMAT_TYPE_NONE, /* Just a string part */ - FORMAT_TYPE_WIDTH, - FORMAT_TYPE_PRECISION, - FORMAT_TYPE_CHAR, - FORMAT_TYPE_STR, - FORMAT_TYPE_PTR, - FORMAT_TYPE_PERCENT_CHAR, - FORMAT_TYPE_INVALID, - FORMAT_TYPE_LONG_LONG, - FORMAT_TYPE_ULONG, - FORMAT_TYPE_LONG, - FORMAT_TYPE_UBYTE, - FORMAT_TYPE_BYTE, - FORMAT_TYPE_USHORT, - FORMAT_TYPE_SHORT, - FORMAT_TYPE_UINT, - FORMAT_TYPE_INT, - FORMAT_TYPE_NRCHARS, - FORMAT_TYPE_SIZE_T, - FORMAT_TYPE_PTRDIFF -}; - -struct printf_spec { - enum format_type type; - int flags; /* flags to number() */ - int field_width; /* width of output field */ - int base; - int precision; /* # of digits/chars */ - int qualifier; -}; - -static char *number(char *buf, char *end, unsigned long long num, - struct printf_spec spec) -{ - /* we are called with base 8, 10 or 16, only, thus don't need "G..." */ - static const char digits[16] = "0123456789ABCDEF"; - - char tmp[66]; - char sign; - char locase; - int need_pfx = ((spec.flags & SPECIAL) && spec.base != 10); - int i; - - /* locase = 0 or 0x20. ORing digits or letters with 'locase' - * produces same digits or (maybe lowercased) letters */ - locase = (spec.flags & SMALL); - if (spec.flags & LEFT) - spec.flags &= ~ZEROPAD; - sign = 0; - if (spec.flags & SIGN) { - if ((signed long long) num < 0) { - sign = '-'; - num = -(signed long long) num; - spec.field_width--; - } else if (spec.flags & PLUS) { - sign = '+'; - spec.field_width--; - } else if (spec.flags & SPACE) { - sign = ' '; - spec.field_width--; - } - } - if (need_pfx) { - spec.field_width--; - if (spec.base == 16) - spec.field_width--; - } - - /* generate full string in tmp[], in reverse order */ - i = 0; - if (num == 0) - tmp[i++] = '0'; - /* Generic code, for any base: - else do { - tmp[i++] = (digits[do_div(num,base)] | locase); - } while (num != 0); - */ - else if (spec.base != 10) { /* 8 or 16 */ - int mask = spec.base - 1; - int shift = 3; - if (spec.base == 16) - shift = 4; - do { - tmp[i++] = (digits[((unsigned char)num) & mask] - | locase); - num >>= shift; - } while (num); - } else { /* base 10 */ - i = put_dec(tmp, num) - tmp; - } - - /* printing 100 using %2d gives "100", not "00" */ - if (i > spec.precision) - spec.precision = i; - /* leading space padding */ - spec.field_width -= spec.precision; - if (!(spec.flags & (ZEROPAD+LEFT))) { - while (--spec.field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - } - /* sign */ - if (sign) { - if (buf < end) - *buf = sign; - ++buf; - } - /* "0x" / "0" prefix */ - if (need_pfx) { - if (buf < end) - *buf = '0'; - ++buf; - if (spec.base == 16) { - if (buf < end) - *buf = ('X' | locase); - ++buf; - } - } - /* zero or space padding */ - if (!(spec.flags & LEFT)) { - char c = (spec.flags & ZEROPAD) ? '0' : ' '; - while (--spec.field_width >= 0) { - if (buf < end) - *buf = c; - ++buf; - } - } - /* hmm even more zero padding? */ - while (i <= --spec.precision) { - if (buf < end) - *buf = '0'; - ++buf; - } - /* actual digits of result */ - while (--i >= 0) { - if (buf < end) - *buf = tmp[i]; - ++buf; - } - /* trailing space padding */ - while (--spec.field_width >= 0) { - if (buf < end) - *buf = ' '; - ++buf; - } - return buf; -} - -static char *string(char *buf, char *end, char *s, struct printf_spec spec) -{ - int len, i; - - if ((unsigned long)s < PAGE_SIZE) - s = "<NULL>"; - - len = strnlen(s, spec.precision); - - if (!(spec.flags & LEFT)) { - while (len < spec.field_width--) { - if (buf < end) - *buf = ' '; - ++buf; - } - } - for (i = 0; i < len; ++i) { - if (buf < end) - *buf = *s; - ++buf; ++s; - } - while (len < spec.field_width--) { - if (buf < end) - *buf = ' '; - ++buf; - } - return buf; -} - -static char *resource_string(char *buf, char *end, struct resource *res, - struct printf_spec spec) -{ -#ifndef IO_RSRC_PRINTK_SIZE -#define IO_RSRC_PRINTK_SIZE 4 -#endif - -#ifndef MEM_RSRC_PRINTK_SIZE -#define MEM_RSRC_PRINTK_SIZE 8 -#endif - struct printf_spec num_spec = { - .base = 16, - .precision = -1, - .flags = SPECIAL | SMALL | ZEROPAD, - }; - /* room for the actual numbers, the two "0x", -, [, ] and the final - zero */ - char sym[4*sizeof(resource_size_t) + 8]; - char *p = sym, *pend = sym + sizeof(sym); - int size = -1; - - if (res->flags & IORESOURCE_IO) - size = IO_RSRC_PRINTK_SIZE; - else if (res->flags & IORESOURCE_MEM) - size = MEM_RSRC_PRINTK_SIZE; - - *p++ = '['; - num_spec.field_width = size; - p = number(p, pend, res->start, num_spec); - *p++ = '-'; - p = number(p, pend, res->end, num_spec); - *p++ = ']'; - *p = 0; - - return string(buf, end, sym, spec); -} - -static char *mac_address_string(char *buf, char *end, u8 *addr, - struct printf_spec spec, const char *fmt) -{ - char mac_addr[sizeof("xx:xx:xx:xx:xx:xx")]; - char *p = mac_addr; - int i; - - for (i = 0; i < 6; i++) { - p = pack_hex_byte(p, addr[i]); - if (fmt[0] == 'M' && i != 5) - *p++ = ':'; - } - *p = '\0'; - - return string(buf, end, mac_addr, spec); -} - -/* - * Show a '%p' thing. A kernel extension is that the '%p' is followed - * by an extra set of alphanumeric characters that are extended format - * specifiers. - * - * Right now we handle: - * - * - 'F' For symbolic function descriptor pointers with offset - * - 'f' For simple symbolic function names without offset - * - 'R' For a struct resource pointer, it prints the range of - * addresses (not the name nor the flags) - * - 'M' For a 6-byte MAC address, it prints the address in the - * usual colon-separated hex notation - * - 'm' For a 6-byte MAC address, it prints the hex address without colons - * - 'I' [46] for IPv4/IPv6 addresses printed in the usual way - * IPv4 uses dot-separated decimal without leading 0's (1.2.3.4) - * IPv6 uses colon separated network-order 16 bit hex with leading 0's - * - 'i' [46] for 'raw' IPv4/IPv6 addresses - * IPv6 omits the colons (01020304...0f) - * IPv4 uses dot-separated decimal with leading 0's (010.123.045.006) - * - 'I6c' for IPv6 addresses printed as specified by - * http://www.ietf.org/id/draft-kawamura-ipv6-text-representation-03.txt - * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 - * function pointers are really function descriptors, which contain a - * pointer to the real address. - */ -static char *pointer(const char *fmt, char *buf, char *end, void *ptr, - struct printf_spec spec) -{ - if (!ptr) - return string(buf, end, "(null)", spec); - - switch (*fmt) { - case 'F': - case 'f': - ptr = dereference_function_descriptor(ptr); - case 'R': - return resource_string(buf, end, ptr, spec); - case 'M': /* Colon separated: 00:01:02:03:04:05 */ - case 'm': /* Contiguous: 000102030405 */ - return mac_address_string(buf, end, ptr, spec, fmt); - } - spec.flags |= SMALL; - if (spec.field_width == -1) { - spec.field_width = 2*sizeof(void *); - spec.flags |= ZEROPAD; - } - spec.base = 16; - - return number(buf, end, (unsigned long) ptr, spec); -} - -/* - * Helper function to decode printf style format. - * Each call decode a token from the format and return the - * number of characters read (or likely the delta where it wants - * to go on the next call). - * The decoded token is returned through the parameters - * - * 'h', 'l', or 'L' for integer fields - * 'z' support added 23/7/1999 S.H. - * 'z' changed to 'Z' --davidm 1/25/99 - * 't' added for ptrdiff_t - * - * @fmt: the format string - * @type of the token returned - * @flags: various flags such as +, -, # tokens.. - * @field_width: overwritten width - * @base: base of the number (octal, hex, ...) - * @precision: precision of a number - * @qualifier: qualifier of a number (long, size_t, ...) - */ -static int format_decode(const char *fmt, struct printf_spec *spec) -{ - const char *start = fmt; - - /* we finished early by reading the field width */ - if (spec->type == FORMAT_TYPE_WIDTH) { - if (spec->field_width < 0) { - spec->field_width = -spec->field_width; - spec->flags |= LEFT; - } - spec->type = FORMAT_TYPE_NONE; - goto precision; - } - - /* we finished early by reading the precision */ - if (spec->type == FORMAT_TYPE_PRECISION) { - if (spec->precision < 0) - spec->precision = 0; - - spec->type = FORMAT_TYPE_NONE; - goto qualifier; - } - - /* By default */ - spec->type = FORMAT_TYPE_NONE; - - for (; *fmt ; ++fmt) { - if (*fmt == '%') - break; - } - - /* Return the current non-format string */ - if (fmt != start || !*fmt) - return fmt - start; - - /* Process flags */ - spec->flags = 0; - - while (1) { /* this also skips first '%' */ - bool found = true; - - ++fmt; - - switch (*fmt) { - case '-': - spec->flags |= LEFT; - break; - case '+': - spec->flags |= PLUS; - break; - case ' ': - spec->flags |= SPACE; - break; - case '#': - spec->flags |= SPECIAL; - break; - case '0': - spec->flags |= ZEROPAD; - break; - default: - found = false; - } - - if (!found) - break; - } - - /* get field width */ - spec->field_width = -1; - - if (isdigit(*fmt)) - spec->field_width = skip_atoi(&fmt); - else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_WIDTH; - return ++fmt - start; - } - -precision: - /* get the precision */ - spec->precision = -1; - if (*fmt == '.') { - ++fmt; - if (isdigit(*fmt)) { - spec->precision = skip_atoi(&fmt); - if (spec->precision < 0) - spec->precision = 0; - } else if (*fmt == '*') { - /* it's the next argument */ - spec->type = FORMAT_TYPE_PRECISION; - return ++fmt - start; - } - } - -qualifier: - /* get the conversion qualifier */ - spec->qualifier = -1; - if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L' || - *fmt == 'Z' || *fmt == 'z' || *fmt == 't') { - spec->qualifier = *fmt++; - if (unlikely(spec->qualifier == *fmt)) { - if (spec->qualifier == 'l') { - spec->qualifier = 'L'; - ++fmt; - } else if (spec->qualifier == 'h') { - spec->qualifier = 'H'; - ++fmt; - } - } - } - - /* default base */ - spec->base = 10; - switch (*fmt) { - case 'c': - spec->type = FORMAT_TYPE_CHAR; - return ++fmt - start; - - case 's': - spec->type = FORMAT_TYPE_STR; - return ++fmt - start; - - case 'p': - spec->type = FORMAT_TYPE_PTR; - return fmt - start; - /* skip alnum */ - - case 'n': - spec->type = FORMAT_TYPE_NRCHARS; - return ++fmt - start; - - case '%': - spec->type = FORMAT_TYPE_PERCENT_CHAR; - return ++fmt - start; - - /* integer number formats - set up the flags and "break" */ - case 'o': - spec->base = 8; - break; - - case 'x': - spec->flags |= SMALL; - - case 'X': - spec->base = 16; - break; - - case 'd': - case 'i': - spec->flags |= SIGN; - case 'u': - break; - - default: - spec->type = FORMAT_TYPE_INVALID; - return fmt - start; - } - - if (spec->qualifier == 'L') - spec->type = FORMAT_TYPE_LONG_LONG; - else if (spec->qualifier == 'l') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_LONG; - else - spec->type = FORMAT_TYPE_ULONG; - } else if (spec->qualifier == 'Z' || spec->qualifier == 'z') { - spec->type = FORMAT_TYPE_SIZE_T; - } else if (spec->qualifier == 't') { - spec->type = FORMAT_TYPE_PTRDIFF; - } else if (spec->qualifier == 'H') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_BYTE; - else - spec->type = FORMAT_TYPE_UBYTE; - } else if (spec->qualifier == 'h') { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_SHORT; - else - spec->type = FORMAT_TYPE_USHORT; - } else { - if (spec->flags & SIGN) - spec->type = FORMAT_TYPE_INT; - else - spec->type = FORMAT_TYPE_UINT; - } - - return ++fmt - start; -} - -/** - * bat_vsnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * This function follows C99 bat_vsnprintf, but has some extensions: - * %pS output the name of a text symbol with offset - * %ps output the name of a text symbol without offset - * %pF output the name of a function pointer with its offset - * %pf output the name of a function pointer without its offset - * %pR output the address range in a struct resource - * %n is ignored - * - * The return value is the number of characters which would - * be generated for the given input, excluding the trailing - * '\0', as per ISO C99. If you want to have the exact - * number of characters written into @buf as return value - * (not including the trailing '\0'), use vscnprintf(). If the - * return is greater than or equal to @size, the resulting - * string is truncated. - * - * Call this function if you are already dealing with a va_list. - * You probably want snprintf() instead. - */ -static int bat_vsnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - unsigned long long num; - char *str, *end, c; - int read; - struct printf_spec spec = {0}; - - /* Reject out-of-range values early. Large positive sizes are - used for unknown buffer sizes. */ - if (WARN_ON_ONCE((int) size < 0)) - return 0; - - str = buf; - end = buf + size; - - /* Make sure end is always >= buf */ - if (end < buf) { - end = ((void *)-1); - size = end - buf; - } - - while (*fmt) { - const char *old_fmt = fmt; - - read = format_decode(fmt, &spec); - - fmt += read; - - switch (spec.type) { - case FORMAT_TYPE_NONE: { - int copy = read; - if (str < end) { - if (copy > end - str) - copy = end - str; - memcpy(str, old_fmt, copy); - } - str += read; - break; - } - - case FORMAT_TYPE_WIDTH: - spec.field_width = va_arg(args, int); - break; - - case FORMAT_TYPE_PRECISION: - spec.precision = va_arg(args, int); - break; - - case FORMAT_TYPE_CHAR: - if (!(spec.flags & LEFT)) { - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - - } - } - c = (unsigned char) va_arg(args, int); - if (str < end) - *str = c; - ++str; - while (--spec.field_width > 0) { - if (str < end) - *str = ' '; - ++str; - } - break; - - case FORMAT_TYPE_STR: - str = string(str, end, va_arg(args, char *), spec); - break; - - case FORMAT_TYPE_PTR: - str = pointer(fmt+1, str, end, va_arg(args, void *), - spec); - while (isalnum(*fmt)) - fmt++; - break; - - case FORMAT_TYPE_PERCENT_CHAR: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_INVALID: - if (str < end) - *str = '%'; - ++str; - break; - - case FORMAT_TYPE_NRCHARS: { - int qualifier = spec.qualifier; - - if (qualifier == 'l') { - long *ip = va_arg(args, long *); - *ip = (str - buf); - } else if (qualifier == 'Z' || - qualifier == 'z') { - size_t *ip = va_arg(args, size_t *); - *ip = (str - buf); - } else { - int *ip = va_arg(args, int *); - *ip = (str - buf); - } - break; - } - - default: - switch (spec.type) { - case FORMAT_TYPE_LONG_LONG: - num = va_arg(args, long long); - break; - case FORMAT_TYPE_ULONG: - num = va_arg(args, unsigned long); - break; - case FORMAT_TYPE_LONG: - num = va_arg(args, long); - break; - case FORMAT_TYPE_SIZE_T: - num = va_arg(args, size_t); - break; - case FORMAT_TYPE_PTRDIFF: - num = va_arg(args, ptrdiff_t); - break; - case FORMAT_TYPE_UBYTE: - num = (unsigned char) va_arg(args, int); - break; - case FORMAT_TYPE_BYTE: - num = (signed char) va_arg(args, int); - break; - case FORMAT_TYPE_USHORT: - num = (unsigned short) va_arg(args, int); - break; - case FORMAT_TYPE_SHORT: - num = (short) va_arg(args, int); - break; - case FORMAT_TYPE_INT: - num = (int) va_arg(args, int); - break; - default: - num = va_arg(args, unsigned int); - } - - str = number(str, end, num, spec); - } - } - - if (size > 0) { - if (str < end) - *str = '\0'; - else - end[-1] = '\0'; - } - - /* the trailing null byte doesn't count towards the total */ - return str-buf; - -} - -/** - * bat_vscnprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @args: Arguments for the format string - * - * The return value is the number of characters which have been written into - * the @buf not including the trailing '\0'. If @size is <= 0 the function - * returns 0. - * - * Call this function if you are already dealing with a va_list. - * You probably want scnprintf() instead. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int bat_vscnprintf(char *buf, size_t size, const char *fmt, va_list args) -{ - int i; - - i = bat_vsnprintf(buf, size, fmt, args); - - return (i >= size) ? (size - 1) : i; -} - -/** - * bat_printk - print a kernel message using extra %p formatting - * strings, forward compatible with kernel version 2.6.31 printk, minus - * *p[sS]. - * - * @fmt: format string - * - * This is printk(). It can be called from any context. We want it to work. - * - */ -asmlinkage int bat_printk(const char *fmt, ...) -{ - va_list args; - char buf[256]; - - va_start(args, fmt); - bat_vsnprintf(buf, sizeof(buf), fmt, args); - va_end(args); - - return printk("%s", buf); -} - -/** - * sprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The function returns the number of characters written - * into @buf. Use snprintf() or scnprintf() in order to avoid - * buffer overflows. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int bat_sprintf(char *buf, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = bat_vsnprintf(buf, INT_MAX, fmt, args); - va_end(args); - - return i; -} - -/** - * snprintf - Format a string and place it in a buffer - * @buf: The buffer to place the result into - * @size: The size of the buffer, including the trailing null space - * @fmt: The format string to use - * @...: Arguments for the format string - * - * The return value is the number of characters which would be - * generated for the given input, excluding the trailing null, - * as per ISO C99. If the return is greater than or equal to - * @size, the resulting string is truncated. - * - * See the vsnprintf() documentation for format string extensions over C99. - */ -int bat_snprintf(char *buf, size_t size, const char *fmt, ...) -{ - va_list args; - int i; - - va_start(args, fmt); - i = bat_vsnprintf(buf, size, fmt, args); - va_end(args); - - return i; -} - -int bat_seq_printf(struct seq_file *m, const char *f, ...) -{ - va_list args; - int len; - - if (m->count < m->size) { - va_start(args, f); - len = bat_vsnprintf(m->buf + m->count, m->size - m->count, f, args); - va_end(args); - if (m->count + len < m->size) { - m->count += len; - return 0; - } - } - m->count = m->size; - return -1; -} - -#endif /* < KERNEL_VERSION(2, 6, 29) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 40) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
void free_rcu_gw_node(struct rcu_head *rcu) { @@ -1031,4 +44,4 @@ void free_rcu_tt_global_entry(struct rcu_head *rcu) kfree(tt_global_entry); }
-#endif /* < KERNEL_VERSION(2, 6, 40) */ +#endif /* < KERNEL_VERSION(3, 0, 0) */ diff --git a/compat.h b/compat.h index 66a8adc..829b0fb 100644 --- a/compat.h +++ b/compat.h @@ -27,238 +27,6 @@
#include <linux/version.h> /* LINUX_VERSION_CODE */
-#ifndef IPPROTO_UDP -#define IPPROTO_UDP 17 -#endif - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 22) - -#define skb_set_network_header(_skb, _offset) \ - do { (_skb)->nh.raw = (_skb)->data + (_offset); } while (0) - -#define skb_reset_mac_header(_skb) \ - do { (_skb)->mac.raw = (_skb)->data; } while (0) - -#define list_first_entry(ptr, type, member) \ - list_entry((ptr)->next, type, member) - -#define skb_mac_header(_skb) \ - ((_skb)->mac.raw) - -#include <linux/etherdevice.h> -static inline __be16 bat_eth_type_trans(struct sk_buff *skb, - struct net_device *dev) -{ - skb->dev = dev; - return eth_type_trans(skb, dev); -} - -#define eth_type_trans(_skb, _dev) \ - bat_eth_type_trans(_skb, _dev); - -#endif /* < KERNEL_VERSION(2,6,22) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 23) - -static inline int skb_cow_head(struct sk_buff *skb, unsigned int headroom) -{ - return skb_cow(skb, headroom); -} - -#define cancel_delayed_work_sync(wq) cancel_delayed_work(wq) - -#endif /* < KERNEL_VERSION(2, 6, 23) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 24) - -#ifndef pr_fmt -#define pr_fmt(fmt) fmt -#endif - -#define pr_err(fmt, ...) \ - printk(KERN_ERR pr_fmt(fmt), ##__VA_ARGS__) -#define pr_warning(fmt, ...) \ - printk(KERN_WARNING pr_fmt(fmt), ##__VA_ARGS__) - -#if defined(DEBUG) -#define pr_debug(fmt, ...) \ - printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__) -#else -#define pr_debug(fmt, ...) \ - ({ if (0) printk(KERN_DEBUG pr_fmt(fmt), ##__VA_ARGS__); 0; }) -#endif - -#define dev_get_by_name(x, y) dev_get_by_name(y) - -#endif /* < KERNEL_VERSION(2, 6, 24) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25) - -#define strict_strtoul(cp, base, res) \ - ({ \ - int ret = 0; \ - char *endp; \ - *res = simple_strtoul(cp, &endp, base); \ - if (cp == endp) \ - ret = -EINVAL; \ - ret; \ -}) - -#define strict_strtol(cp, base, res) \ - ({ \ - int ret = 0; \ - char *endp; \ - *res = simple_strtol(cp, &endp, base); \ - if (cp == endp) \ - ret = -EINVAL; \ - ret; \ -}) - -#define to_battr(a) container_of(a, struct bat_attribute, attr) - -ssize_t bat_wrapper_show(struct kobject *kobj, struct attribute *attr, - char *buf); - -ssize_t bat_wrapper_store(struct kobject *kobj, struct attribute *attr, - const char *buf, size_t count); - -static struct sysfs_ops bat_wrapper_ops = { - .show = bat_wrapper_show, - .store = bat_wrapper_store, -}; - -static struct kobj_type ktype_bat_wrapper = { - .sysfs_ops = &bat_wrapper_ops, -}; - -static inline struct kobject *kobject_create_and_add(const char *name, - struct kobject *parent) -{ - struct kobject *kobj; - int err; - - kobj = kzalloc(sizeof(*kobj), GFP_KERNEL); - if (!kobj) - return NULL; - - kobject_set_name(kobj, "%s", name); - kobj->ktype = &ktype_bat_wrapper; - kobj->kset = NULL; - kobj->parent = parent; - - err = kobject_register(kobj); - if (err) { - kobject_put(kobj); - return NULL; - } - - return kobj; -} - -#define kobject_put(kobj) kobject_unregister(kobj) - -#endif /* < KERNEL_VERSION(2, 6, 25) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26) - -static const char hex_asc[] = "0123456789abcdef"; -#define hex_asc_lo(x) hex_asc[((x) & 0x0f)] -#define hex_asc_hi(x) hex_asc[((x) & 0xf0) >> 4] -static inline char *pack_hex_byte(char *buf, u8 byte) -{ - *buf++ = hex_asc_hi(byte); - *buf++ = hex_asc_lo(byte); - return buf; -} - -#endif /* < KERNEL_VERSION(2, 6, 26) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27) - -#define ethtool_cmd_speed_set(_ep, _speed) \ - do { (_ep)->speed = (_speed); } while (0) - -#ifndef dereference_function_descriptor -#define dereference_function_descriptor(p) (p) -#endif - -#include <linux/debugfs.h> - -static inline void debugfs_remove_recursive(struct dentry *dentry) -{ - struct dentry *child; - struct dentry *parent; - - if (!dentry) - return; - - parent = dentry->d_parent; - if (!parent || !parent->d_inode) - return; - - parent = dentry; - - while (1) { - /* - * When all dentries under "parent" has been removed, - * walk up the tree until we reach our starting point. - */ - if (list_empty(&parent->d_subdirs)) { - if (parent == dentry) - break; - parent = parent->d_parent; - } - child = list_entry(parent->d_subdirs.next, struct dentry, - d_u.d_child); -next_sibling: - - /* - * If "child" isn't empty, walk down the tree and - * remove all its descendants first. - */ - if (!list_empty(&child->d_subdirs)) { - parent = child; - continue; - } - debugfs_remove(child); - if (parent->d_subdirs.next == &child->d_u.d_child) { - /* - * Try the next sibling. - */ - if (child->d_u.d_child.next != &parent->d_subdirs) { - child = list_entry(child->d_u.d_child.next, - struct dentry, - d_u.d_child); - goto next_sibling; - } - break; - } - } - - debugfs_remove(dentry); -} - -#endif /* < KERNEL_VERSION(2, 6, 27) */ - -#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) - -int bat_vscnprintf(char *buf, size_t size, const char *fmt, va_list args); -#define vscnprintf bat_vscnprintf - -asmlinkage int bat_printk(const char *fmt, ...); -#define printk bat_printk - -int bat_sprintf(char *buf, const char *fmt, ...); -#define sprintf bat_sprintf - -int bat_snprintf(char *buf, size_t size, const char *fmt, ...); -#define snprintf bat_snprintf - -int bat_seq_printf(struct seq_file *m, const char *f, ...); -#define seq_printf bat_seq_printf - -#endif /* < KERNEL_VERSION(2, 6, 29) */ - #if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33)
#define __always_unused __attribute__((unused)) @@ -285,7 +53,7 @@ int bat_seq_printf(struct seq_file *m, const char *f, ...);
#endif /* < KERNEL_VERSION(2, 6, 36) */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 40) +#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 0, 0)
#define kfree_rcu(ptr, rcu_head) call_rcu(&ptr->rcu_head, free_rcu_##ptr)
@@ -295,6 +63,6 @@ void free_rcu_softif_neigh(struct rcu_head *rcu); void free_rcu_tt_local_entry(struct rcu_head *rcu); void free_rcu_tt_global_entry(struct rcu_head *rcu);
-#endif /* < KERNEL_VERSION(2, 6, 40) */ +#endif /* < KERNEL_VERSION(3, 0, 0) */
#endif /* _NET_BATMAN_ADV_COMPAT_H_ */
README | 2 +- compat.c | 8 ++++++++ compat.h | 17 +++++++++++++++++ soft-interface.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-)
diff --git a/README b/README index f590c99..34fda4f 100644 --- a/README +++ b/README @@ -18,7 +18,7 @@ Batman advanced was implemented as a Linux kernel driver to re- duce the overhead to a minimum. It does not depend on any (other) network driver, and can be used on wifi as well as ethernet lan, vpn, etc ... (anything with ethernet-style layer 2). It compiles -against and should work with Linux 2.6.29 - 3.1. Supporting +against and should work with Linux 2.6.21 - 3.1. Supporting older versions is not planned, but it's probably easy to backport it. If you work on a backport, feel free to contact us. :-)
diff --git a/compat.c b/compat.c index ebedae8..98da315 100644 --- a/compat.c +++ b/compat.c @@ -32,6 +32,14 @@ ssize_t bat_wrapper_store(struct kobject *kobj, struct attribute *attr,
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+int eth_validate_addr(struct net_device *dev) +{ + if (!is_valid_ether_addr(dev->dev_addr)) + return -EADDRNOTAVAIL; + + return 0; +} + /* * linux/lib/vsprintf.c * diff --git a/compat.h b/compat.h index 66a8adc..3f21e1a 100644 --- a/compat.h +++ b/compat.h @@ -242,6 +242,23 @@ next_sibling:
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29)
+#include <linux/netdevice.h> + +struct net_device_ops { + int (*ndo_open)(struct net_device *dev); + int (*ndo_stop)(struct net_device *dev); + int (*ndo_start_xmit) (struct sk_buff *skb, + struct net_device *dev); + int (*ndo_set_mac_address)(struct net_device *dev, + void *addr); + int (*ndo_validate_addr)(struct net_device *dev); + int (*ndo_change_mtu)(struct net_device *dev, + int new_mtu); + struct net_device_stats* (*ndo_get_stats)(struct net_device *dev); +}; + +int eth_validate_addr(struct net_device *dev); + int bat_vscnprintf(char *buf, size_t size, const char *fmt, va_list args); #define vscnprintf bat_vscnprintf
diff --git a/soft-interface.c b/soft-interface.c index 3e2f91f..26f7323 100644 --- a/soft-interface.c +++ b/soft-interface.c @@ -760,6 +760,25 @@ static const struct net_device_ops bat_netdev_ops = { .ndo_validate_addr = eth_validate_addr };
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +static void set_net_device_ops(struct net_device *dev, + const struct net_device_ops *netdev_ops) +{ + dev->open = netdev_ops->ndo_open; + dev->stop = netdev_ops->ndo_stop; + dev->get_stats = netdev_ops->ndo_get_stats; + dev->set_mac_address = netdev_ops->ndo_set_mac_address; + dev->change_mtu = netdev_ops->ndo_change_mtu; + dev->hard_start_xmit = netdev_ops->ndo_start_xmit; +} +#else +static void set_net_device_ops(struct net_device *dev, + const struct net_device_ops *netdev_ops) +{ + dev->netdev_ops = netdev_ops; +} +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) */ + static void interface_setup(struct net_device *dev) { struct bat_priv *priv = netdev_priv(dev); @@ -767,7 +786,7 @@ static void interface_setup(struct net_device *dev)
ether_setup(dev);
- dev->netdev_ops = &bat_netdev_ops; + set_net_device_ops(dev, &bat_netdev_ops); dev->destructor = free_netdev; dev->tx_queue_len = 0;
@@ -872,6 +891,15 @@ void softif_destroy(struct net_device *soft_iface) unregister_netdevice(soft_iface); }
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) +int softif_is_valid(const struct net_device *net_dev) +{ + if (net_dev->hard_start_xmit == interface_tx) + return 1; + + return 0; +} +#else /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) */ int softif_is_valid(const struct net_device *net_dev) { if (net_dev->netdev_ops->ndo_start_xmit == interface_tx) @@ -879,6 +907,7 @@ int softif_is_valid(const struct net_device *net_dev)
return 0; } +#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 29) */
/* ethtool */ static int bat_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
On Sunday 17 July 2011 13:11:19 Sven Eckelmann wrote:
README | 2 +- compat.c | 8 ++++++++ compat.h | 17 +++++++++++++++++ soft-interface.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-)
The sendmail killed my comment. So here it is again:
This is just a small note... but it is completely unacceptable for the kernel folks. d0tslash wanted to have "another ugly compat.h macro" - so he can continue here.
Kind regards, Sven
Hey Sven,
actually I wanted an ugly macro which keeps the kernel version check in the compat.h only - I tried my luck based on your patch, but i failed miserably... I just can't tame the preprocessor. Sorry. :D
I'm fine with dropping the support for < 2.6.29, it does not hurt me both personally and professionally. I don't know if there is anyone who uses old kernels and can't patch back themselves.
As a compromise, we might upload compat patches on open-mesh.org for release versions of batman-adv. No maintaining, just "best effort service". We keep some more unmaintained patches there too [1]. What do you think?
Is there anyone using old kernels?
best regards, Simon
[1] http://downloads.open-mesh.org/batman/patches/
On Sun, Jul 17, 2011 at 01:15:03PM +0200, Sven Eckelmann wrote:
On Sunday 17 July 2011 13:11:19 Sven Eckelmann wrote:
README | 2 +- compat.c | 8 ++++++++ compat.h | 17 +++++++++++++++++ soft-interface.c | 31 ++++++++++++++++++++++++++++++- 4 files changed, 56 insertions(+), 2 deletions(-)
The sendmail killed my comment. So here it is again:
This is just a small note... but it is completely unacceptable for the kernel folks. d0tslash wanted to have "another ugly compat.h macro" - so he can continue here.
Kind regards, Sven
On Sunday 17 July 2011 21:14:07 Simon Wunderlich wrote:
Hey Sven,
actually I wanted an ugly macro which keeps the kernel version check in the compat.h only - I tried my luck based on your patch, but i failed miserably... I just can't tame the preprocessor. Sorry. :D
I never expected that you are able to fix it without doing more ugly things inside the source code.
[...]
As a compromise, we might upload compat patches on open-mesh.org for release versions of batman-adv. No maintaining, just "best effort service". We keep some more unmaintained patches there too [1]. What do you think?
That is exactly what we started to discuss. Personally I don't have anything against it, but Marek said that nobody will test it and it will be harder and harder to backport. My answer was that it is already even harder to backport it to 2.6.21 without modifying the actual sources. But at least it is a way to share some work for people which have to work together with.... against a marketing department that doesn't understands that "supports latest linux" doesn't mean some old and rotting linux 2.6.x.
The current steps for the compat patch is to revert David's patch (but modify it to use >= 2.6.29 instead of HAVE_....) and revert my "remove that old compat stuff" patch.
Kind regards, Sven
On Sunday, July 17, 2011 12:43:12 Sven Eckelmann wrote:
The removal of the HAVE_NET_DEVICE_OPS in the kernel sources by David S. Miller makes it hard to implement compatibility code using compat.(c|h). Either the sources of the kernel and the external module have to diverge again or more complex workarounds have to be found.
Dropping support for kernels older than 2.6.29 will remove the dead ballast of stuff older than two years. People which need it can revert 7f1b7b837c205e413a7aa078a47ec96f0c11afa7 and this patch.
Although it might not please everyone I believe this is the way to go. In case somebody does not agree he can propose an alternative in the following days.
Cheers, Marek
On Sunday, July 17, 2011 12:43:12 Sven Eckelmann wrote:
The removal of the HAVE_NET_DEVICE_OPS in the kernel sources by David S. Miller makes it hard to implement compatibility code using compat.(c|h). Either the sources of the kernel and the external module have to diverge again or more complex workarounds have to be found.
Dropping support for kernels older than 2.6.29 will remove the dead ballast of stuff older than two years. People which need it can revert 7f1b7b837c205e413a7aa078a47ec96f0c11afa7 and this patch.
Since we seem to have been in agreement regarding the support of older kernels I applied your patch in revision a6786eb.
Thanks, Marek
b.a.t.m.a.n@lists.open-mesh.org