add generic 2.6.28 patches

SVN-Revision: 13546
This commit is contained in:
Imre Kaloz 2008-12-08 13:23:09 +00:00
parent 206ccdf4ae
commit f21f51d858
80 changed files with 36878 additions and 0 deletions

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,201 @@
/*
* character device wrapper for generic gpio layer
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA02111-1307USA
*
* Feedback, Bugs... blogic@openwrt.org
*
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/gpio.h>
#include <asm/atomic.h>
#include <linux/init.h>
#include <linux/genhd.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/gpio_dev.h>
#define DRVNAME "gpiodev"
#define DEVNAME "gpio"
static int dev_major;
static unsigned int gpio_access_mask;
static struct class *gpiodev_class;
/* Counter is 1, if the device is not opened and zero (or less) if opened. */
static atomic_t gpio_open_cnt = ATOMIC_INIT(1);
static int
gpio_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
int retval = 0;
if (((1 << arg) & gpio_access_mask) != (1 << arg))
{
retval = -EINVAL;
goto out;
}
switch (cmd)
{
case GPIO_GET:
retval = gpio_get_value(arg);
break;
case GPIO_SET:
gpio_set_value(arg, 1);
break;
case GPIO_CLEAR:
gpio_set_value(arg, 0);
break;
case GPIO_DIR_IN:
gpio_direction_input(arg);
break;
case GPIO_DIR_OUT:
gpio_direction_output(arg, 0);
break;
default:
retval = -EINVAL;
break;
}
out:
return retval;
}
static int
gpio_open(struct inode *inode, struct file *file)
{
int result = 0;
unsigned int dev_minor = MINOR(inode->i_rdev);
if (dev_minor != 0)
{
printk(KERN_ERR DRVNAME ": trying to access unknown minor device -> %d\n", dev_minor);
result = -ENODEV;
goto out;
}
/* FIXME: We should really allow multiple applications to open the device
* at the same time, as long as the apps access different IO pins.
* The generic gpio-registration functions can be used for that.
* Two new IOCTLs have to be introduced for that. Need to check userspace
* compatibility first. --mb */
if (!atomic_dec_and_test(&gpio_open_cnt)) {
atomic_inc(&gpio_open_cnt);
printk(KERN_ERR DRVNAME ": Device with minor ID %d already in use\n", dev_minor);
result = -EBUSY;
goto out;
}
out:
return result;
}
static int
gpio_close(struct inode * inode, struct file * file)
{
smp_mb__before_atomic_inc();
atomic_inc(&gpio_open_cnt);
return 0;
}
struct file_operations gpio_fops = {
ioctl: gpio_ioctl,
open: gpio_open,
release: gpio_close
};
static int
gpio_probe(struct platform_device *dev)
{
int result = 0;
dev_major = register_chrdev(0, DEVNAME, &gpio_fops);
if (!dev_major)
{
printk(KERN_ERR DRVNAME ": Error whilst opening %s \n", DEVNAME);
result = -ENODEV;
goto out;
}
gpiodev_class = class_create(THIS_MODULE, DRVNAME);
device_create(gpiodev_class, NULL, MKDEV(dev_major, 0), dev, DEVNAME);
printk(KERN_INFO DRVNAME ": gpio device registered with major %d\n", dev_major);
if (dev->num_resources != 1)
{
printk(KERN_ERR DRVNAME ": device may only have 1 resource\n");
result = -ENODEV;
goto out;
}
gpio_access_mask = dev->resource[0].start;
printk(KERN_INFO DRVNAME ": gpio platform device registered with access mask %08X\n", gpio_access_mask);
out:
return result;
}
static int
gpio_remove(struct platform_device *dev)
{
unregister_chrdev(dev_major, DEVNAME);
return 0;
}
static struct
platform_driver gpio_driver = {
.probe = gpio_probe,
.remove = gpio_remove,
.driver = {
.name = "GPIODEV",
.owner = THIS_MODULE,
},
};
static int __init
gpio_mod_init(void)
{
int ret = platform_driver_register(&gpio_driver);
if (ret)
printk(KERN_INFO DRVNAME ": Error registering platfom driver!");
return ret;
}
static void __exit
gpio_mod_exit(void)
{
platform_driver_unregister(&gpio_driver);
}
module_init (gpio_mod_init);
module_exit (gpio_mod_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("John Crispin / OpenWrt");
MODULE_DESCRIPTION("Character device for for generic gpio api");

View file

@ -0,0 +1,209 @@
/*
* Driver for buttons on GPIO lines not capable of generating interrupts
*
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: /drivers/input/misc/cobalt_btns.c
* Copyright (C) 2007 Yoichi Yuasa <yoichi_yuasa@tripeaks.co.jp>
*
* also was based on: /drivers/input/keyboard/gpio_keys.c
* Copyright 2005 Phil Blundell
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/input-polldev.h>
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio_buttons.h>
#include <asm/gpio.h>
#define DRV_NAME "gpio-buttons"
#define DRV_VERSION "0.1.1"
#define PFX DRV_NAME ": "
struct gpio_buttons_dev {
struct input_polled_dev *poll_dev;
struct gpio_buttons_platform_data *pdata;
};
static void gpio_buttons_poll(struct input_polled_dev *dev)
{
struct gpio_buttons_dev *bdev = dev->private;
struct gpio_buttons_platform_data *pdata = bdev->pdata;
struct input_dev *input = dev->input;
int i;
for (i = 0; i < bdev->pdata->nbuttons; i++) {
struct gpio_button *button = &pdata->buttons[i];
unsigned int type = button->type ?: EV_KEY;
int state;
state = gpio_get_value(button->gpio) ? 1 : 0;
state ^= button->active_low;
if (state) {
button->count++;
} else {
if (button->count >= button->threshold) {
input_event(input, type, button->code, 1);
input_sync(input);
}
button->count = 0;
}
if (button->count == button->threshold) {
input_event(input, type, button->code, 0);
input_sync(input);
}
}
}
static int __devinit gpio_buttons_probe(struct platform_device *pdev)
{
struct gpio_buttons_platform_data *pdata = pdev->dev.platform_data;
struct gpio_buttons_dev *bdev;
struct input_polled_dev *poll_dev;
struct input_dev *input;
int error, i;
if (!pdata)
return -ENXIO;
bdev = kzalloc(sizeof(*bdev), GFP_KERNEL);
if (!bdev) {
printk(KERN_ERR DRV_NAME "no memory for device\n");
return -ENOMEM;
}
poll_dev = input_allocate_polled_device();
if (!poll_dev) {
printk(KERN_ERR DRV_NAME "no memory for polled device\n");
error = -ENOMEM;
goto err_free_bdev;
}
poll_dev->private = bdev;
poll_dev->poll = gpio_buttons_poll;
poll_dev->poll_interval = pdata->poll_interval;
input = poll_dev->input;
input->evbit[0] = BIT(EV_KEY);
input->name = pdev->name;
input->phys = "gpio-buttons/input0";
input->dev.parent = &pdev->dev;
input->id.bustype = BUS_HOST;
input->id.vendor = 0x0001;
input->id.product = 0x0001;
input->id.version = 0x0100;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_button *button = &pdata->buttons[i];
unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
error = gpio_request(gpio, button->desc ?
button->desc : DRV_NAME);
if (error) {
printk(KERN_ERR PFX "unable to claim gpio %u, "
"error %d\n", gpio, error);
goto err_free_gpio;
}
error = gpio_direction_input(gpio);
if (error) {
printk(KERN_ERR PFX "unable to set direction on "
"gpio %u, error %d\n", gpio, error);
goto err_free_gpio;
}
input_set_capability(input, type, button->code);
button->count = 0;
}
bdev->poll_dev = poll_dev;
bdev->pdata = pdata;
platform_set_drvdata(pdev, bdev);
error = input_register_polled_device(poll_dev);
if (error) {
printk(KERN_ERR PFX "unable to register polled device, "
"error %d\n", error);
goto err_free_gpio;
}
return 0;
err_free_gpio:
for (i = i - 1; i >= 0; i--)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(poll_dev);
err_free_bdev:
kfree(bdev);
platform_set_drvdata(pdev, NULL);
return error;
}
static int __devexit gpio_buttons_remove(struct platform_device *pdev)
{
struct gpio_buttons_dev *bdev = platform_get_drvdata(pdev);
struct gpio_buttons_platform_data *pdata = bdev->pdata;
int i;
input_unregister_polled_device(bdev->poll_dev);
for (i = 0; i < pdata->nbuttons; i++)
gpio_free(pdata->buttons[i].gpio);
input_free_polled_device(bdev->poll_dev);
kfree(bdev);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver gpio_buttons_driver = {
.probe = gpio_buttons_probe,
.remove = __devexit_p(gpio_buttons_remove),
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
},
};
static int __init gpio_buttons_init(void)
{
printk(KERN_INFO DRV_NAME " driver version " DRV_VERSION "\n");
return platform_driver_register(&gpio_buttons_driver);
}
static void __exit gpio_buttons_exit(void)
{
platform_driver_unregister(&gpio_buttons_driver);
}
module_init(gpio_buttons_init);
module_exit(gpio_buttons_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_VERSION(DRV_VERSION);
MODULE_DESCRIPTION("Polled buttons driver for CPU GPIOs");

View file

@ -0,0 +1,172 @@
/*
* LEDs driver for PCEngines ALIX 2/3 series
*
* Copyright (C) 2007 Petr Liebman
*
* Based on leds-wrap.c
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/leds.h>
#include <linux/err.h>
#include <asm/io.h>
#define DRVNAME "alix-led"
#define ALIX_LED1_PORT (0x6100)
#define ALIX_LED1_ON (1<<22)
#define ALIX_LED1_OFF (1<<6)
#define ALIX_LED2_PORT (0x6180)
#define ALIX_LED2_ON (1<<25)
#define ALIX_LED2_OFF (1<<9)
#define ALIX_LED3_PORT (0x6180)
#define ALIX_LED3_ON (1<<27)
#define ALIX_LED3_OFF (1<<11)
static struct platform_device *pdev;
static void alix_led_set_1(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED1_ON, ALIX_LED1_PORT);
else
outl(ALIX_LED1_OFF, ALIX_LED1_PORT);
}
static void alix_led_set_2(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED2_ON, ALIX_LED2_PORT);
else
outl(ALIX_LED2_OFF, ALIX_LED2_PORT);
}
static void alix_led_set_3(struct led_classdev *led_cdev,
enum led_brightness value)
{
if (value)
outl(ALIX_LED3_ON, ALIX_LED3_PORT);
else
outl(ALIX_LED3_OFF, ALIX_LED3_PORT);
}
static struct led_classdev alix_led_1 = {
.name = "alix:1",
.brightness_set = alix_led_set_1,
};
static struct led_classdev alix_led_2 = {
.name = "alix:2",
.brightness_set = alix_led_set_2,
};
static struct led_classdev alix_led_3 = {
.name = "alix:3",
.brightness_set = alix_led_set_3,
};
#ifdef CONFIG_PM
static int alix_led_suspend(struct platform_device *dev,
pm_message_t state)
{
led_classdev_suspend(&alix_led_1);
led_classdev_suspend(&alix_led_2);
led_classdev_suspend(&alix_led_3);
return 0;
}
static int alix_led_resume(struct platform_device *dev)
{
led_classdev_resume(&alix_led_1);
led_classdev_resume(&alix_led_2);
led_classdev_resume(&alix_led_3);
return 0;
}
#else
#define alix_led_suspend NULL
#define alix_led_resume NULL
#endif
static int alix_led_probe(struct platform_device *pdev)
{
int ret;
ret = led_classdev_register(&pdev->dev, &alix_led_1);
if (ret >= 0)
{
ret = led_classdev_register(&pdev->dev, &alix_led_2);
if (ret >= 0)
{
ret = led_classdev_register(&pdev->dev, &alix_led_3);
if (ret < 0)
led_classdev_unregister(&alix_led_2);
}
if (ret < 0)
led_classdev_unregister(&alix_led_1);
}
return ret;
}
static int alix_led_remove(struct platform_device *pdev)
{
led_classdev_unregister(&alix_led_1);
led_classdev_unregister(&alix_led_2);
led_classdev_unregister(&alix_led_3);
return 0;
}
static struct platform_driver alix_led_driver = {
.probe = alix_led_probe,
.remove = alix_led_remove,
.suspend = alix_led_suspend,
.resume = alix_led_resume,
.driver = {
.name = DRVNAME,
.owner = THIS_MODULE,
},
};
static int __init alix_led_init(void)
{
int ret;
ret = platform_driver_register(&alix_led_driver);
if (ret < 0)
goto out;
pdev = platform_device_register_simple(DRVNAME, -1, NULL, 0);
if (IS_ERR(pdev)) {
ret = PTR_ERR(pdev);
platform_driver_unregister(&alix_led_driver);
goto out;
}
out:
return ret;
}
static void __exit alix_led_exit(void)
{
platform_device_unregister(pdev);
platform_driver_unregister(&alix_led_driver);
}
module_init(alix_led_init);
module_exit(alix_led_exit);
MODULE_AUTHOR("Petr Liebman");
MODULE_DESCRIPTION("PCEngines ALIX LED driver");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,365 @@
/*
* LED Morse Trigger
*
* Copyright (C) 2007 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: drivers/led/ledtrig-timer.c
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* also based on the patch '[PATCH] 2.5.59 morse code panics' posted
* in the LKML by Tomas Szepe at Thu, 30 Jan 2003
* Copyright (C) 2002 Andrew Rodland <arodland@noln.com>
* Copyright (C) 2003 Tomas Szepe <szepe@pinerecords.com>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation.
*
*/
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/leds.h>
#include "leds.h"
#define MORSE_DELAY_BASE (HZ/2)
#define MORSE_STATE_BLINK_START 0
#define MORSE_STATE_BLINK_STOP 1
#define MORSE_DIT_LEN 1
#define MORSE_DAH_LEN 3
#define MORSE_SPACE_LEN 7
struct morse_trig_data {
unsigned long delay;
char *msg;
unsigned char morse;
unsigned char state;
char *msgpos;
struct timer_list timer;
};
const unsigned char morsetable[] = {
0122, 0, 0310, 0, 0, 0163, /* "#$%&' */
055, 0155, 0, 0, 0163, 0141, 0152, 0051, /* ()*+,-./ */
077, 076, 074, 070, 060, 040, 041, 043, 047, 057, /* 0-9 */
0107, 0125, 0, 0061, 0, 0114, 0, /* :;<=>?@ */
006, 021, 025, 011, 002, 024, 013, 020, 004, /* A-I */
036, 015, 022, 007, 005, 017, 026, 033, 012, /* J-R */
010, 003, 014, 030, 016, 031, 035, 023, /* S-Z */
0, 0, 0, 0, 0154 /* [\]^_ */
};
static inline unsigned char tomorse(char c) {
if (c >= 'a' && c <= 'z')
c = c - 'a' + 'A';
if (c >= '"' && c <= '_') {
return morsetable[c - '"'];
} else
return 0;
}
static inline unsigned long dit_len(struct morse_trig_data *morse_data)
{
return MORSE_DIT_LEN*morse_data->delay;
}
static inline unsigned long dah_len(struct morse_trig_data *morse_data)
{
return MORSE_DAH_LEN*morse_data->delay;
}
static inline unsigned long space_len(struct morse_trig_data *morse_data)
{
return MORSE_SPACE_LEN*morse_data->delay;
}
static void morse_timer_function(unsigned long data)
{
struct led_classdev *led_cdev = (struct led_classdev *)data;
struct morse_trig_data *morse_data = led_cdev->trigger_data;
unsigned long brightness = LED_OFF;
unsigned long delay = 0;
if (!morse_data->msg)
goto set_led;
switch (morse_data->state) {
case MORSE_STATE_BLINK_START:
/* Starting a new blink. We have a valid code in morse. */
delay = (morse_data->morse & 001) ? dah_len(morse_data):
dit_len(morse_data);
brightness = LED_FULL;
morse_data->state = MORSE_STATE_BLINK_STOP;
morse_data->morse >>= 1;
break;
case MORSE_STATE_BLINK_STOP:
/* Coming off of a blink. */
morse_data->state = MORSE_STATE_BLINK_START;
if (morse_data->morse > 1) {
/* Not done yet, just a one-dit pause. */
delay = dit_len(morse_data);
break;
}
/* Get a new char, figure out how much space. */
/* First time through */
if (!morse_data->msgpos)
morse_data->msgpos = (char *)morse_data->msg;
if (!*morse_data->msgpos) {
/* Repeating */
morse_data->msgpos = (char *)morse_data->msg;
delay = space_len(morse_data);
} else {
/* Inter-letter space */
delay = dah_len(morse_data);
}
if (!(morse_data->morse = tomorse(*morse_data->msgpos))) {
delay = space_len(morse_data);
/* And get us back here */
morse_data->state = MORSE_STATE_BLINK_STOP;
}
morse_data->msgpos++;
break;
}
mod_timer(&morse_data->timer, jiffies + msecs_to_jiffies(delay));
set_led:
led_set_brightness(led_cdev, brightness);
}
static ssize_t _morse_delay_show(struct led_classdev *led_cdev, char *buf)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
sprintf(buf, "%lu\n", morse_data->delay);
return strlen(buf) + 1;
}
static ssize_t _morse_delay_store(struct led_classdev *led_cdev,
const char *buf, size_t size)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
char *after;
unsigned long state = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
int ret = -EINVAL;
if (*after && isspace(*after))
count++;
if (count == size) {
morse_data->delay = state;
mod_timer(&morse_data->timer, jiffies + 1);
ret = count;
}
return ret;
}
static ssize_t _morse_msg_show(struct led_classdev *led_cdev, char *buf)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
if (!morse_data->msg)
sprintf(buf, "<none>\n");
else
sprintf(buf, "%s\n", morse_data->msg);
return strlen(buf) + 1;
}
static ssize_t _morse_msg_store(struct led_classdev *led_cdev,
const char *buf, size_t size)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
char *m;
m = kmalloc(size, GFP_KERNEL);
if (!m)
return -ENOMEM;
memcpy(m,buf,size);
m[size]='\0';
if (morse_data->msg)
kfree(morse_data->msg);
morse_data->msg = m;
morse_data->msgpos = NULL;
morse_data->state = MORSE_STATE_BLINK_STOP;
mod_timer(&morse_data->timer, jiffies + 1);
return size;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
static ssize_t morse_delay_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_delay_show(led_cdev, buf);
}
static ssize_t morse_delay_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_delay_store(led_cdev, buf, size);
}
static ssize_t morse_msg_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_msg_show(led_cdev, buf);
}
static ssize_t morse_msg_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
return _morse_msg_store(led_cdev, buf, size);
}
static DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
static DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
#define led_device_create_file(leddev, attr) \
device_create_file(leddev->dev, &dev_attr_ ## attr)
#define led_device_remove_file(leddev, attr) \
device_remove_file(leddev->dev, &dev_attr_ ## attr)
#else
static ssize_t morse_delay_show(struct class_device *dev, char *buf)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_delay_show(led_cdev, buf);
}
static ssize_t morse_delay_store(struct class_device *dev, const char *buf,
size_t size)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_delay_store(led_cdev, buf, size);
}
static ssize_t morse_msg_show(struct class_device *dev, char *buf)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_msg_show(led_cdev, buf);
}
static ssize_t morse_msg_store(struct class_device *dev, const char *buf,
size_t size)
{
struct led_classdev *led_cdev = class_get_devdata(dev);
return _morse_msg_store(led_cdev, buf, size);
}
static CLASS_DEVICE_ATTR(delay, 0644, morse_delay_show, morse_delay_store);
static CLASS_DEVICE_ATTR(message, 0644, morse_msg_show, morse_msg_store);
#define led_device_create_file(leddev, attr) \
class_device_create_file(leddev->class_dev, &class_device_attr_ ## attr)
#define led_device_remove_file(leddev, attr) \
class_device_remove_file(leddev->class_dev, &class_device_attr_ ## attr)
#endif
static void morse_trig_activate(struct led_classdev *led_cdev)
{
struct morse_trig_data *morse_data;
int rc;
morse_data = kzalloc(sizeof(*morse_data), GFP_KERNEL);
if (!morse_data)
return;
morse_data->delay = MORSE_DELAY_BASE;
init_timer(&morse_data->timer);
morse_data->timer.function = morse_timer_function;
morse_data->timer.data = (unsigned long)led_cdev;
rc = led_device_create_file(led_cdev, delay);
if (rc) goto err;
rc = led_device_create_file(led_cdev, message);
if (rc) goto err_delay;
led_cdev->trigger_data = morse_data;
return;
err_delay:
led_device_remove_file(led_cdev, delay);
err:
kfree(morse_data);
}
static void morse_trig_deactivate(struct led_classdev *led_cdev)
{
struct morse_trig_data *morse_data = led_cdev->trigger_data;
if (!morse_data)
return;
led_device_remove_file(led_cdev, message);
led_device_remove_file(led_cdev, delay);
del_timer_sync(&morse_data->timer);
if (morse_data->msg)
kfree(morse_data->msg);
kfree(morse_data);
}
static struct led_trigger morse_led_trigger = {
.name = "morse",
.activate = morse_trig_activate,
.deactivate = morse_trig_deactivate,
};
static int __init morse_trig_init(void)
{
return led_trigger_register(&morse_led_trigger);
}
static void __exit morse_trig_exit(void)
{
led_trigger_unregister(&morse_led_trigger);
}
module_init(morse_trig_init);
module_exit(morse_trig_exit);
MODULE_AUTHOR("Gabor Juhos <juhosg at openwrt.org>");
MODULE_DESCRIPTION("Morse LED trigger");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,451 @@
/*
* LED Kernel Netdev Trigger
*
* Toggles the LED to reflect the link and traffic state of a named net device
*
* Copyright 2007 Oliver Jowett <oliver@opencloud.com>
*
* Derived from ledtrig-timer.c which is:
* Copyright 2005-2006 Openedhand Ltd.
* Author: Richard Purdie <rpurdie@openedhand.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#include <linux/module.h>
#include <linux/jiffies.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/spinlock.h>
#include <linux/device.h>
#include <linux/sysdev.h>
#include <linux/netdevice.h>
#include <linux/timer.h>
#include <linux/ctype.h>
#include <linux/leds.h>
#include <linux/version.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
#include <net/net_namespace.h>
#endif
#include "leds.h"
/*
* Configurable sysfs attributes:
*
* device_name - network device name to monitor
*
* interval - duration of LED blink, in milliseconds
*
* mode - either "none" (LED is off) or a space separated list of one or more of:
* link: LED's normal state reflects whether the link is up (has carrier) or not
* tx: LED blinks on transmitted data
* rx: LED blinks on receive data
*
* Some suggestions:
*
* Simple link status LED:
* $ echo netdev >someled/trigger
* $ echo eth0 >someled/device_name
* $ echo link >someled/mode
*
* Ethernet-style link/activity LED:
* $ echo netdev >someled/trigger
* $ echo eth0 >someled/device_name
* $ echo "link tx rx" >someled/mode
*
* Modem-style tx/rx LEDs:
* $ echo netdev >led1/trigger
* $ echo ppp0 >led1/device_name
* $ echo tx >led1/mode
* $ echo netdev >led2/trigger
* $ echo ppp0 >led2/device_name
* $ echo rx >led2/mode
*
*/
#define MODE_LINK 1
#define MODE_TX 2
#define MODE_RX 4
struct led_netdev_data {
rwlock_t lock;
struct timer_list timer;
struct notifier_block notifier;
struct led_classdev *led_cdev;
struct net_device *net_dev;
char device_name[IFNAMSIZ];
unsigned interval;
unsigned mode;
unsigned link_up;
unsigned last_activity;
};
static void set_baseline_state(struct led_netdev_data *trigger_data)
{
if ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up)
led_set_brightness(trigger_data->led_cdev, LED_FULL);
else
led_set_brightness(trigger_data->led_cdev, LED_OFF);
if ((trigger_data->mode & (MODE_TX | MODE_RX)) != 0 && trigger_data->link_up)
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
else
del_timer(&trigger_data->timer);
}
static ssize_t led_device_name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
sprintf(buf, "%s\n", trigger_data->device_name);
read_unlock(&trigger_data->lock);
return strlen(buf) + 1;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,21)
extern struct net init_net;
#endif
static ssize_t led_device_name_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
if (size < 0 || size >= IFNAMSIZ)
return -EINVAL;
write_lock(&trigger_data->lock);
strcpy(trigger_data->device_name, buf);
if (size > 0 && trigger_data->device_name[size-1] == '\n')
trigger_data->device_name[size-1] = 0;
if (trigger_data->device_name[0] != 0) {
/* check for existing device to update from */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,26)
trigger_data->net_dev = dev_get_by_name(&init_net, trigger_data->device_name);
#else
trigger_data->net_dev = dev_get_by_name(trigger_data->device_name);
#endif
if (trigger_data->net_dev != NULL)
trigger_data->link_up = (dev_get_flags(trigger_data->net_dev) & IFF_LOWER_UP) != 0;
set_baseline_state(trigger_data); /* updates LEDs, may start timers */
}
write_unlock(&trigger_data->lock);
return size;
}
static DEVICE_ATTR(device_name, 0644, led_device_name_show, led_device_name_store);
static ssize_t led_mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
if (trigger_data->mode == 0) {
strcpy(buf, "none\n");
} else {
if (trigger_data->mode & MODE_LINK)
strcat(buf, "link ");
if (trigger_data->mode & MODE_TX)
strcat(buf, "tx ");
if (trigger_data->mode & MODE_RX)
strcat(buf, "rx ");
strcat(buf, "\n");
}
read_unlock(&trigger_data->lock);
return strlen(buf)+1;
}
static ssize_t led_mode_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
char copybuf[1024];
int new_mode = -1;
char *p, *token;
/* take a copy since we don't want to trash the inbound buffer when using strsep */
strncpy(copybuf, buf, sizeof(copybuf));
copybuf[1023] = 0;
p = copybuf;
while ((token = strsep(&p, " \t\n")) != NULL) {
if (!*token)
continue;
if (new_mode == -1)
new_mode = 0;
if (!strcmp(token, "none"))
new_mode = 0;
else if (!strcmp(token, "tx"))
new_mode |= MODE_TX;
else if (!strcmp(token, "rx"))
new_mode |= MODE_RX;
else if (!strcmp(token, "link"))
new_mode |= MODE_LINK;
else
return -EINVAL;
}
if (new_mode == -1)
return -EINVAL;
write_lock(&trigger_data->lock);
trigger_data->mode = new_mode;
set_baseline_state(trigger_data);
write_unlock(&trigger_data->lock);
return size;
}
static DEVICE_ATTR(mode, 0644, led_mode_show, led_mode_store);
static ssize_t led_interval_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
read_lock(&trigger_data->lock);
sprintf(buf, "%u\n", jiffies_to_msecs(trigger_data->interval));
read_unlock(&trigger_data->lock);
return strlen(buf) + 1;
}
static ssize_t led_interval_store(struct device *dev,
struct device_attribute *attr, const char *buf, size_t size)
{
struct led_classdev *led_cdev = dev_get_drvdata(dev);
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
int ret = -EINVAL;
char *after;
unsigned long value = simple_strtoul(buf, &after, 10);
size_t count = after - buf;
if (*after && isspace(*after))
count++;
/* impose some basic bounds on the timer interval */
if (count == size && value >= 5 && value <= 10000) {
write_lock(&trigger_data->lock);
trigger_data->interval = msecs_to_jiffies(value);
set_baseline_state(trigger_data); // resets timer
write_unlock(&trigger_data->lock);
ret = count;
}
return ret;
}
static DEVICE_ATTR(interval, 0644, led_interval_show, led_interval_store);
static int netdev_trig_notify(struct notifier_block *nb,
unsigned long evt,
void *dv)
{
struct net_device *dev = dv;
struct led_netdev_data *trigger_data = container_of(nb, struct led_netdev_data, notifier);
if (evt != NETDEV_UP && evt != NETDEV_DOWN && evt != NETDEV_CHANGE && evt != NETDEV_REGISTER && evt != NETDEV_UNREGISTER)
return NOTIFY_DONE;
write_lock(&trigger_data->lock);
if (strcmp(dev->name, trigger_data->device_name))
goto done;
if (evt == NETDEV_REGISTER) {
if (trigger_data->net_dev != NULL)
dev_put(trigger_data->net_dev);
dev_hold(dev);
trigger_data->net_dev = dev;
trigger_data->link_up = 0;
goto done;
}
if (evt == NETDEV_UNREGISTER && trigger_data->net_dev != NULL) {
dev_put(trigger_data->net_dev);
trigger_data->net_dev = NULL;
goto done;
}
/* UP / DOWN / CHANGE */
trigger_data->link_up = (evt != NETDEV_DOWN && netif_carrier_ok(dev));
set_baseline_state(trigger_data);
done:
write_unlock(&trigger_data->lock);
return NOTIFY_DONE;
}
/* here's the real work! */
static void netdev_trig_timer(unsigned long arg)
{
struct led_netdev_data *trigger_data = (struct led_netdev_data *)arg;
struct net_device_stats *dev_stats;
unsigned new_activity;
write_lock(&trigger_data->lock);
if (!trigger_data->link_up || !trigger_data->net_dev || (trigger_data->mode & (MODE_TX | MODE_RX)) == 0) {
/* we don't need to do timer work, just reflect link state. */
led_set_brightness(trigger_data->led_cdev, ((trigger_data->mode & MODE_LINK) != 0 && trigger_data->link_up) ? LED_FULL : LED_OFF);
goto no_restart;
}
dev_stats = trigger_data->net_dev->get_stats(trigger_data->net_dev);
new_activity =
((trigger_data->mode & MODE_TX) ? dev_stats->tx_packets : 0) +
((trigger_data->mode & MODE_RX) ? dev_stats->rx_packets : 0);
if (trigger_data->mode & MODE_LINK) {
/* base state is ON (link present) */
/* if there's no link, we don't get this far and the LED is off */
/* OFF -> ON always */
/* ON -> OFF on activity */
if (trigger_data->led_cdev->brightness == LED_OFF) {
led_set_brightness(trigger_data->led_cdev, LED_FULL);
} else if (trigger_data->last_activity != new_activity) {
led_set_brightness(trigger_data->led_cdev, LED_OFF);
}
} else {
/* base state is OFF */
/* ON -> OFF always */
/* OFF -> ON on activity */
if (trigger_data->led_cdev->brightness == LED_FULL) {
led_set_brightness(trigger_data->led_cdev, LED_OFF);
} else if (trigger_data->last_activity != new_activity) {
led_set_brightness(trigger_data->led_cdev, LED_FULL);
}
}
trigger_data->last_activity = new_activity;
mod_timer(&trigger_data->timer, jiffies + trigger_data->interval);
no_restart:
write_unlock(&trigger_data->lock);
}
static void netdev_trig_activate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data;
int rc;
trigger_data = kzalloc(sizeof(struct led_netdev_data), GFP_KERNEL);
if (!trigger_data)
return;
rwlock_init(&trigger_data->lock);
trigger_data->notifier.notifier_call = netdev_trig_notify;
trigger_data->notifier.priority = 10;
setup_timer(&trigger_data->timer, netdev_trig_timer, (unsigned long) trigger_data);
trigger_data->led_cdev = led_cdev;
trigger_data->net_dev = NULL;
trigger_data->device_name[0] = 0;
trigger_data->mode = 0;
trigger_data->interval = msecs_to_jiffies(50);
trigger_data->link_up = 0;
trigger_data->last_activity = 0;
led_cdev->trigger_data = trigger_data;
rc = device_create_file(led_cdev->dev, &dev_attr_device_name);
if (rc)
goto err_out;
rc = device_create_file(led_cdev->dev, &dev_attr_mode);
if (rc)
goto err_out_device_name;
rc = device_create_file(led_cdev->dev, &dev_attr_interval);
if (rc)
goto err_out_mode;
register_netdevice_notifier(&trigger_data->notifier);
return;
err_out_mode:
device_remove_file(led_cdev->dev, &dev_attr_mode);
err_out_device_name:
device_remove_file(led_cdev->dev, &dev_attr_device_name);
err_out:
led_cdev->trigger_data = NULL;
kfree(trigger_data);
}
static void netdev_trig_deactivate(struct led_classdev *led_cdev)
{
struct led_netdev_data *trigger_data = led_cdev->trigger_data;
if (trigger_data) {
unregister_netdevice_notifier(&trigger_data->notifier);
device_remove_file(led_cdev->dev, &dev_attr_device_name);
device_remove_file(led_cdev->dev, &dev_attr_mode);
device_remove_file(led_cdev->dev, &dev_attr_interval);
write_lock(&trigger_data->lock);
if (trigger_data->net_dev) {
dev_put(trigger_data->net_dev);
trigger_data->net_dev = NULL;
}
write_unlock(&trigger_data->lock);
del_timer_sync(&trigger_data->timer);
kfree(trigger_data);
}
}
static struct led_trigger netdev_led_trigger = {
.name = "netdev",
.activate = netdev_trig_activate,
.deactivate = netdev_trig_deactivate,
};
static int __init netdev_trig_init(void)
{
return led_trigger_register(&netdev_led_trigger);
}
static void __exit netdev_trig_exit(void)
{
led_trigger_unregister(&netdev_led_trigger);
}
module_init(netdev_trig_init);
module_exit(netdev_trig_exit);
MODULE_AUTHOR("Oliver Jowett <oliver@opencloud.com>");
MODULE_DESCRIPTION("Netdev LED trigger");
MODULE_LICENSE("GPL");

View file

@ -0,0 +1,35 @@
/*
* Definitions for the GPIO buttons interface driver
*
* Copyright (C) 2007,2008 Gabor Juhos <juhosg at openwrt.org>
*
* This file was based on: /include/linux/gpio_keys.h
* The original gpio_keys.h seems not to have a license.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*
*/
#ifndef _GPIO_BUTTONS_H_
#define _GPIO_BUTTONS_H_
struct gpio_button {
int gpio; /* GPIO line number */
int active_low;
char *desc; /* button description */
int type; /* input event type (EV_KEY, EV_SW) */
int code; /* input event code (KEY_*, SW_*) */
int count;
int threshold; /* count threshold */
};
struct gpio_buttons_platform_data {
struct gpio_button *buttons;
int nbuttons; /* number of buttons */
int poll_interval; /* polling interval */
};
#endif /* _GPIO_BUTTONS_H_ */

View file

@ -0,0 +1,11 @@
#ifndef _GPIODEV_H__
#define _GPIODEV_H__
#define IOC_GPIODEV_MAGIC 'B'
#define GPIO_GET _IO(IOC_GPIODEV_MAGIC, 10)
#define GPIO_SET _IO(IOC_GPIODEV_MAGIC, 11)
#define GPIO_CLEAR _IO(IOC_GPIODEV_MAGIC, 12)
#define GPIO_DIR_IN _IO(IOC_GPIODEV_MAGIC, 13)
#define GPIO_DIR_OUT _IO(IOC_GPIODEV_MAGIC, 14)
#endif

View file

@ -0,0 +1,168 @@
/*
* switch.h: Switch configuration API
*
* Copyright (C) 2008 Felix Fietkau <nbd@openwrt.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef __LINUX_SWITCH_H
#define __LINUX_SWITCH_H
#include <linux/types.h>
#include <linux/netdevice.h>
#include <linux/netlink.h>
#include <linux/genetlink.h>
#ifndef __KERNEL__
#include <netlink/netlink.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#else
#include <net/genetlink.h>
#endif
/* main attributes */
enum {
SWITCH_ATTR_UNSPEC,
/* global */
SWITCH_ATTR_TYPE,
/* device */
SWITCH_ATTR_ID,
SWITCH_ATTR_NAME,
SWITCH_ATTR_DEV_NAME,
SWITCH_ATTR_VLANS,
SWITCH_ATTR_PORTS,
/* attributes */
SWITCH_ATTR_OP_ID,
SWITCH_ATTR_OP_TYPE,
SWITCH_ATTR_OP_NAME,
SWITCH_ATTR_OP_PORT,
SWITCH_ATTR_OP_VLAN,
SWITCH_ATTR_OP_VALUE_INT,
SWITCH_ATTR_OP_VALUE_STR,
SWITCH_ATTR_OP_VALUE_PORTS,
SWITCH_ATTR_OP_DESCRIPTION,
/* port lists */
SWITCH_ATTR_PORT,
SWITCH_ATTR_MAX
};
/* commands */
enum {
SWITCH_CMD_UNSPEC,
SWITCH_CMD_GET_SWITCH,
SWITCH_CMD_NEW_ATTR,
SWITCH_CMD_LIST_GLOBAL,
SWITCH_CMD_GET_GLOBAL,
SWITCH_CMD_SET_GLOBAL,
SWITCH_CMD_LIST_PORT,
SWITCH_CMD_GET_PORT,
SWITCH_CMD_SET_PORT,
SWITCH_CMD_LIST_VLAN,
SWITCH_CMD_GET_VLAN,
SWITCH_CMD_SET_VLAN
};
/* data types */
enum switch_val_type {
SWITCH_TYPE_UNSPEC,
SWITCH_TYPE_INT,
SWITCH_TYPE_STRING,
SWITCH_TYPE_PORTS,
SWITCH_TYPE_NOVAL,
};
/* port nested attributes */
enum {
SWITCH_PORT_UNSPEC,
SWITCH_PORT_ID,
SWITCH_PORT_FLAG_TAGGED,
SWITCH_PORT_ATTR_MAX
};
#define SWITCH_ATTR_DEFAULTS_OFFSET 0x1000
#ifdef __KERNEL__
struct switch_dev;
struct switch_op;
struct switch_val;
struct switch_attr;
struct switch_attrlist;
int register_switch(struct switch_dev *dev, struct net_device *netdev);
void unregister_switch(struct switch_dev *dev);
struct switch_attrlist {
/* filled in by the driver */
int n_attr;
struct switch_attr *attr;
};
struct switch_dev {
int id;
void *priv;
const char *name;
/* NB: either devname or netdev must be set */
const char *devname;
struct net_device *netdev;
int ports;
int vlans;
int cpu_port;
struct switch_attrlist attr_global, attr_port, attr_vlan;
spinlock_t lock;
struct switch_port *portbuf;
struct list_head dev_list;
unsigned long def_global, def_port, def_vlan;
int (*get_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
int (*set_vlan_ports)(struct switch_dev *dev, struct switch_val *val);
int (*apply_config)(struct switch_dev *dev);
};
struct switch_port {
u32 id;
u32 flags;
};
struct switch_val {
struct switch_attr *attr;
int port_vlan;
int len;
union {
const char *s;
u32 i;
struct switch_port *ports;
} value;
};
struct switch_attr {
int disabled;
int type;
const char *name;
const char *description;
int (*set)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val);
int (*get)(struct switch_dev *dev, struct switch_attr *attr, struct switch_val *val);
/* for driver internal use */
int id;
int ofs;
int max;
};
#endif
#endif

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,780 @@
--- /dev/null
+++ b/include/linux/LzmaDecode.h
@@ -0,0 +1,100 @@
+/*
+ LzmaDecode.h
+ LZMA Decoder interface
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#ifndef __LZMADECODE_H
+#define __LZMADECODE_H
+
+/* #define _LZMA_IN_CB */
+/* Use callback for input data */
+
+/* #define _LZMA_OUT_READ */
+/* Use read function for output data */
+
+/* #define _LZMA_PROB32 */
+/* It can increase speed on some 32-bit CPUs,
+ but memory usage will be doubled in that case */
+
+/* #define _LZMA_LOC_OPT */
+/* Enable local speed optimizations inside code */
+
+#ifndef UInt32
+#ifdef _LZMA_UINT32_IS_ULONG
+#define UInt32 unsigned long
+#else
+#define UInt32 unsigned int
+#endif
+#endif
+
+#ifdef _LZMA_PROB32
+#define CProb UInt32
+#else
+#define CProb unsigned short
+#endif
+
+#define LZMA_RESULT_OK 0
+#define LZMA_RESULT_DATA_ERROR 1
+#define LZMA_RESULT_NOT_ENOUGH_MEM 2
+
+#ifdef _LZMA_IN_CB
+typedef struct _ILzmaInCallback
+{
+ int (*Read)(void *object, unsigned char **buffer, UInt32 *bufferSize);
+} ILzmaInCallback;
+#endif
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+/*
+bufferSize = (LZMA_BASE_SIZE + (LZMA_LIT_SIZE << (lc + lp)))* sizeof(CProb)
+bufferSize += 100 in case of _LZMA_OUT_READ
+by default CProb is unsigned short,
+but if specify _LZMA_PROB_32, CProb will be UInt32(unsigned int)
+*/
+
+#ifdef _LZMA_OUT_READ
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+);
+#endif
+
+int LzmaDecode(
+ unsigned char *buffer,
+ #ifndef _LZMA_OUT_READ
+ UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed);
+
+#endif
--- /dev/null
+++ b/lib/LzmaDecode.c
@@ -0,0 +1,663 @@
+/*
+ LzmaDecode.c
+ LZMA Decoder
+
+ LZMA SDK 4.05 Copyright (c) 1999-2004 Igor Pavlov (2004-08-25)
+ http://www.7-zip.org/
+
+ LZMA SDK is licensed under two licenses:
+ 1) GNU Lesser General Public License (GNU LGPL)
+ 2) Common Public License (CPL)
+ It means that you can select one of these two licenses and
+ follow rules of that license.
+
+ SPECIAL EXCEPTION:
+ Igor Pavlov, as the author of this code, expressly permits you to
+ statically or dynamically link your code (or bind by name) to the
+ interfaces of this file without subjecting your linked code to the
+ terms of the CPL or GNU LGPL. Any modifications or additions
+ to this file, however, are subject to the LGPL or CPL terms.
+*/
+
+#include <linux/LzmaDecode.h>
+
+#ifndef Byte
+#define Byte unsigned char
+#endif
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+typedef struct _CRangeDecoder
+{
+ Byte *Buffer;
+ Byte *BufferLim;
+ UInt32 Range;
+ UInt32 Code;
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *InCallback;
+ int Result;
+ #endif
+ int ExtraBytes;
+} CRangeDecoder;
+
+Byte RangeDecoderReadByte(CRangeDecoder *rd)
+{
+ if (rd->Buffer == rd->BufferLim)
+ {
+ #ifdef _LZMA_IN_CB
+ UInt32 size;
+ rd->Result = rd->InCallback->Read(rd->InCallback, &rd->Buffer, &size);
+ rd->BufferLim = rd->Buffer + size;
+ if (size == 0)
+ #endif
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+ }
+ return (*rd->Buffer++);
+}
+
+/* #define ReadByte (*rd->Buffer++) */
+#define ReadByte (RangeDecoderReadByte(rd))
+
+void RangeDecoderInit(CRangeDecoder *rd,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ Byte *stream, UInt32 bufferSize
+ #endif
+ )
+{
+ int i;
+ #ifdef _LZMA_IN_CB
+ rd->InCallback = inCallback;
+ rd->Buffer = rd->BufferLim = 0;
+ #else
+ rd->Buffer = stream;
+ rd->BufferLim = stream + bufferSize;
+ #endif
+ rd->ExtraBytes = 0;
+ rd->Code = 0;
+ rd->Range = (0xFFFFFFFF);
+ for(i = 0; i < 5; i++)
+ rd->Code = (rd->Code << 8) | ReadByte;
+}
+
+#define RC_INIT_VAR UInt32 range = rd->Range; UInt32 code = rd->Code;
+#define RC_FLUSH_VAR rd->Range = range; rd->Code = code;
+#define RC_NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | ReadByte; }
+
+UInt32 RangeDecoderDecodeDirectBits(CRangeDecoder *rd, int numTotalBits)
+{
+ RC_INIT_VAR
+ UInt32 result = 0;
+ int i;
+ for (i = numTotalBits; i > 0; i--)
+ {
+ /* UInt32 t; */
+ range >>= 1;
+
+ result <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ result |= 1;
+ }
+ /*
+ t = (code - range) >> 31;
+ t &= 1;
+ code -= range & (t - 1);
+ result = (result + result) | (1 - t);
+ */
+ RC_NORMALIZE
+ }
+ RC_FLUSH_VAR
+ return result;
+}
+
+int RangeDecoderBitDecode(CProb *prob, CRangeDecoder *rd)
+{
+ UInt32 bound = (rd->Range >> kNumBitModelTotalBits) * *prob;
+ if (rd->Code < bound)
+ {
+ rd->Range = bound;
+ *prob += (kBitModelTotal - *prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 0;
+ }
+ else
+ {
+ rd->Range -= bound;
+ rd->Code -= bound;
+ *prob -= (*prob) >> kNumMoveBits;
+ if (rd->Range < kTopValue)
+ {
+ rd->Code = (rd->Code << 8) | ReadByte;
+ rd->Range <<= 8;
+ }
+ return 1;
+ }
+}
+
+#define RC_GET_BIT2(prob, mi, A0, A1) \
+ UInt32 bound = (range >> kNumBitModelTotalBits) * *prob; \
+ if (code < bound) \
+ { A0; range = bound; *prob += (kBitModelTotal - *prob) >> kNumMoveBits; mi <<= 1; } \
+ else \
+ { A1; range -= bound; code -= bound; *prob -= (*prob) >> kNumMoveBits; mi = (mi + mi) + 1; } \
+ RC_NORMALIZE
+
+#define RC_GET_BIT(prob, mi) RC_GET_BIT2(prob, mi, ; , ;)
+
+int RangeDecoderBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = numLevels; i > 0; i--)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT(prob, mi)
+ #else
+ mi = (mi + mi) + RangeDecoderBitDecode(probs + mi, rd);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return mi - (1 << numLevels);
+}
+
+int RangeDecoderReverseBitTreeDecode(CProb *probs, int numLevels, CRangeDecoder *rd)
+{
+ int mi = 1;
+ int i;
+ int symbol = 0;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ for(i = 0; i < numLevels; i++)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + mi;
+ RC_GET_BIT2(prob, mi, ; , symbol |= (1 << i))
+ #else
+ int bit = RangeDecoderBitDecode(probs + mi, rd);
+ mi = mi + mi + bit;
+ symbol |= (bit << i);
+ #endif
+ }
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecode(CProb *probs, CRangeDecoder *rd)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+Byte LzmaLiteralDecodeMatch(CProb *probs, CRangeDecoder *rd, Byte matchByte)
+{
+ int symbol = 1;
+ #ifdef _LZMA_LOC_OPT
+ RC_INIT_VAR
+ #endif
+ do
+ {
+ int bit;
+ int matchBit = (matchByte >> 7) & 1;
+ matchByte <<= 1;
+ #ifdef _LZMA_LOC_OPT
+ {
+ CProb *prob = probs + ((1 + matchBit) << 8) + symbol;
+ RC_GET_BIT2(prob, symbol, bit = 0, bit = 1)
+ }
+ #else
+ bit = RangeDecoderBitDecode(probs + ((1 + matchBit) << 8) + symbol, rd);
+ symbol = (symbol << 1) | bit;
+ #endif
+ if (matchBit != bit)
+ {
+ while (symbol < 0x100)
+ {
+ #ifdef _LZMA_LOC_OPT
+ CProb *prob = probs + symbol;
+ RC_GET_BIT(prob, symbol)
+ #else
+ symbol = (symbol + symbol) | RangeDecoderBitDecode(probs + symbol, rd);
+ #endif
+ }
+ break;
+ }
+ }
+ while (symbol < 0x100);
+ #ifdef _LZMA_LOC_OPT
+ RC_FLUSH_VAR
+ #endif
+ return symbol;
+}
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+int LzmaLenDecode(CProb *p, CRangeDecoder *rd, int posState)
+{
+ if(RangeDecoderBitDecode(p + LenChoice, rd) == 0)
+ return RangeDecoderBitTreeDecode(p + LenLow +
+ (posState << kLenNumLowBits), kLenNumLowBits, rd);
+ if(RangeDecoderBitDecode(p + LenChoice2, rd) == 0)
+ return kLenNumLowSymbols + RangeDecoderBitTreeDecode(p + LenMid +
+ (posState << kLenNumMidBits), kLenNumMidBits, rd);
+ return kLenNumLowSymbols + kLenNumMidSymbols +
+ RangeDecoderBitTreeDecode(p + LenHigh, kLenNumHighBits, rd);
+}
+
+#define kNumStates 12
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+#ifdef _LZMA_OUT_READ
+
+typedef struct _LzmaVarState
+{
+ CRangeDecoder RangeDecoder;
+ Byte *Dictionary;
+ UInt32 DictionarySize;
+ UInt32 DictionaryPos;
+ UInt32 GlobalPos;
+ UInt32 Reps[4];
+ int lc;
+ int lp;
+ int pb;
+ int State;
+ int PreviousIsMatch;
+ int RemainLen;
+} LzmaVarState;
+
+int LzmaDecoderInit(
+ unsigned char *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ unsigned char *dictionary, UInt32 dictionarySize,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback
+ #else
+ unsigned char *inStream, UInt32 inSize
+ #endif
+ )
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ UInt32 i;
+ if (bufferSize < numProbs * sizeof(CProb) + sizeof(LzmaVarState))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ vs->Dictionary = dictionary;
+ vs->DictionarySize = dictionarySize;
+ vs->DictionaryPos = 0;
+ vs->GlobalPos = 0;
+ vs->Reps[0] = vs->Reps[1] = vs->Reps[2] = vs->Reps[3] = 1;
+ vs->lc = lc;
+ vs->lp = lp;
+ vs->pb = pb;
+ vs->State = 0;
+ vs->PreviousIsMatch = 0;
+ vs->RemainLen = 0;
+ dictionary[dictionarySize - 1] = 0;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&vs->RangeDecoder,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+ return LZMA_RESULT_OK;
+}
+
+int LzmaDecode(unsigned char *buffer,
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ LzmaVarState *vs = (LzmaVarState *)buffer;
+ CProb *p = (CProb *)(buffer + sizeof(LzmaVarState));
+ CRangeDecoder rd = vs->RangeDecoder;
+ int state = vs->State;
+ int previousIsMatch = vs->PreviousIsMatch;
+ Byte previousByte;
+ UInt32 rep0 = vs->Reps[0], rep1 = vs->Reps[1], rep2 = vs->Reps[2], rep3 = vs->Reps[3];
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << (vs->pb)) - 1;
+ UInt32 literalPosMask = (1 << (vs->lp)) - 1;
+ int lc = vs->lc;
+ int len = vs->RemainLen;
+ UInt32 globalPos = vs->GlobalPos;
+
+ Byte *dictionary = vs->Dictionary;
+ UInt32 dictionarySize = vs->DictionarySize;
+ UInt32 dictionaryPos = vs->DictionaryPos;
+
+ if (len == -1)
+ {
+ *outSizeProcessed = 0;
+ return LZMA_RESULT_OK;
+ }
+
+ while(len > 0 && nowPos < outSize)
+ {
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ outStream[nowPos++] = dictionary[dictionaryPos] = dictionary[pos];
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ len--;
+ }
+ if (dictionaryPos == 0)
+ previousByte = dictionary[dictionarySize - 1];
+ else
+ previousByte = dictionary[dictionaryPos - 1];
+#else
+
+int LzmaDecode(
+ Byte *buffer, UInt32 bufferSize,
+ int lc, int lp, int pb,
+ #ifdef _LZMA_IN_CB
+ ILzmaInCallback *inCallback,
+ #else
+ unsigned char *inStream, UInt32 inSize,
+ #endif
+ unsigned char *outStream, UInt32 outSize,
+ UInt32 *outSizeProcessed)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (lc + lp));
+ CProb *p = (CProb *)buffer;
+ CRangeDecoder rd;
+ UInt32 i;
+ int state = 0;
+ int previousIsMatch = 0;
+ Byte previousByte = 0;
+ UInt32 rep0 = 1, rep1 = 1, rep2 = 1, rep3 = 1;
+ UInt32 nowPos = 0;
+ UInt32 posStateMask = (1 << pb) - 1;
+ UInt32 literalPosMask = (1 << lp) - 1;
+ int len = 0;
+ if (bufferSize < numProbs * sizeof(CProb))
+ return LZMA_RESULT_NOT_ENOUGH_MEM;
+ for (i = 0; i < numProbs; i++)
+ p[i] = kBitModelTotal >> 1;
+ RangeDecoderInit(&rd,
+ #ifdef _LZMA_IN_CB
+ inCallback
+ #else
+ inStream, inSize
+ #endif
+ );
+#endif
+
+ *outSizeProcessed = 0;
+ while(nowPos < outSize)
+ {
+ int posState = (int)(
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & posStateMask);
+ #ifdef _LZMA_IN_CB
+ if (rd.Result != LZMA_RESULT_OK)
+ return rd.Result;
+ #endif
+ if (rd.ExtraBytes != 0)
+ return LZMA_RESULT_DATA_ERROR;
+ if (RangeDecoderBitDecode(p + IsMatch + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ CProb *probs = p + Literal + (LZMA_LIT_SIZE *
+ (((
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ & literalPosMask) << lc) + (previousByte >> (8 - lc))));
+
+ if (state < 4) state = 0;
+ else if (state < 10) state -= 3;
+ else state -= 6;
+ if (previousIsMatch)
+ {
+ Byte matchByte;
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ matchByte = dictionary[pos];
+ #else
+ matchByte = outStream[nowPos - rep0];
+ #endif
+ previousByte = LzmaLiteralDecodeMatch(probs, &rd, matchByte);
+ previousIsMatch = 0;
+ }
+ else
+ previousByte = LzmaLiteralDecode(probs, &rd);
+ outStream[nowPos++] = previousByte;
+ #ifdef _LZMA_OUT_READ
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #endif
+ }
+ else
+ {
+ previousIsMatch = 1;
+ if (RangeDecoderBitDecode(p + IsRep + state, &rd) == 1)
+ {
+ if (RangeDecoderBitDecode(p + IsRepG0 + state, &rd) == 0)
+ {
+ if (RangeDecoderBitDecode(p + IsRep0Long + (state << kNumPosBitsMax) + posState, &rd) == 0)
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos;
+ #endif
+ if (
+ (nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ == 0)
+ return LZMA_RESULT_DATA_ERROR;
+ state = state < 7 ? 9 : 11;
+ #ifdef _LZMA_OUT_READ
+ pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ continue;
+ }
+ }
+ else
+ {
+ UInt32 distance;
+ if(RangeDecoderBitDecode(p + IsRepG1 + state, &rd) == 0)
+ distance = rep1;
+ else
+ {
+ if(RangeDecoderBitDecode(p + IsRepG2 + state, &rd) == 0)
+ distance = rep2;
+ else
+ {
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ len = LzmaLenDecode(p + RepLenCoder, &rd, posState);
+ state = state < 7 ? 8 : 11;
+ }
+ else
+ {
+ int posSlot;
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ state = state < 7 ? 7 : 10;
+ len = LzmaLenDecode(p + LenCoder, &rd, posState);
+ posSlot = RangeDecoderBitTreeDecode(p + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits), kNumPosSlotBits, &rd);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+ rep0 = ((2 | ((UInt32)posSlot & 1)) << numDirectBits);
+ if (posSlot < kEndPosModelIndex)
+ {
+ rep0 += RangeDecoderReverseBitTreeDecode(
+ p + SpecPos + rep0 - posSlot - 1, numDirectBits, &rd);
+ }
+ else
+ {
+ rep0 += RangeDecoderDecodeDirectBits(&rd,
+ numDirectBits - kNumAlignBits) << kNumAlignBits;
+ rep0 += RangeDecoderReverseBitTreeDecode(p + Align, kNumAlignBits, &rd);
+ }
+ }
+ else
+ rep0 = posSlot;
+ rep0++;
+ }
+ if (rep0 == (UInt32)(0))
+ {
+ /* it's for stream version */
+ len = -1;
+ break;
+ }
+ if (rep0 > nowPos
+ #ifdef _LZMA_OUT_READ
+ + globalPos
+ #endif
+ )
+ {
+ return LZMA_RESULT_DATA_ERROR;
+ }
+ len += kMatchMinLen;
+ do
+ {
+ #ifdef _LZMA_OUT_READ
+ UInt32 pos = dictionaryPos - rep0;
+ if (pos >= dictionarySize)
+ pos += dictionarySize;
+ previousByte = dictionary[pos];
+ dictionary[dictionaryPos] = previousByte;
+ if (++dictionaryPos == dictionarySize)
+ dictionaryPos = 0;
+ #else
+ previousByte = outStream[nowPos - rep0];
+ #endif
+ outStream[nowPos++] = previousByte;
+ len--;
+ }
+ while(len > 0 && nowPos < outSize);
+ }
+ }
+
+ #ifdef _LZMA_OUT_READ
+ vs->RangeDecoder = rd;
+ vs->DictionaryPos = dictionaryPos;
+ vs->GlobalPos = globalPos + nowPos;
+ vs->Reps[0] = rep0;
+ vs->Reps[1] = rep1;
+ vs->Reps[2] = rep2;
+ vs->Reps[3] = rep3;
+ vs->State = state;
+ vs->PreviousIsMatch = previousIsMatch;
+ vs->RemainLen = len;
+ #endif
+
+ *outSizeProcessed = nowPos;
+ return LZMA_RESULT_OK;
+}
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -20,7 +20,7 @@ lib-y += kobject.o kref.o klist.o
obj-y += bcd.o div64.o sort.o parser.o halfmd4.o debug_locks.o random32.o \
bust_spinlocks.o hexdump.o kasprintf.o bitmap.o scatterlist.o \
- string_helpers.o
+ string_helpers.o LzmaDecode.o
ifeq ($(CONFIG_DEBUG_KOBJECT),y)
CFLAGS_kobject.o += -DDEBUG

View file

@ -0,0 +1,107 @@
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -4,6 +4,9 @@
* Copyright (c) 2002, 2003, 2004, 2005, 2006
* Phillip Lougher <phillip@lougher.org.uk>
*
+ * LZMA decompressor support added by Oleg I. Vdovikin
+ * Copyright (c) 2005 Oleg I.Vdovikin <oleg@cs.msu.su>
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2,
@@ -21,6 +24,7 @@
* inode.c
*/
+#define SQUASHFS_LZMA
#include <linux/types.h>
#include <linux/squashfs_fs.h>
#include <linux/module.h>
@@ -44,6 +48,19 @@
#include "squashfs.h"
+#ifdef SQUASHFS_LZMA
+#include <linux/LzmaDecode.h>
+
+/* default LZMA settings, should be in sync with mksquashfs */
+#define LZMA_LC 3
+#define LZMA_LP 0
+#define LZMA_PB 2
+
+#define LZMA_WORKSPACE_SIZE ((LZMA_BASE_SIZE + \
+ (LZMA_LIT_SIZE << (LZMA_LC + LZMA_LP))) * sizeof(CProb))
+
+#endif
+
static void squashfs_put_super(struct super_block *);
static int squashfs_statfs(struct dentry *, struct kstatfs *);
static int squashfs_symlink_readpage(struct file *file, struct page *page);
@@ -64,7 +81,11 @@ static int squashfs_get_sb(struct file_s
const char *, void *, struct vfsmount *);
+#ifdef SQUASHFS_LZMA
+static unsigned char lzma_workspace[LZMA_WORKSPACE_SIZE];
+#else
static z_stream stream;
+#endif
static struct file_system_type squashfs_fs_type = {
.owner = THIS_MODULE,
@@ -249,6 +270,15 @@ SQSH_EXTERN unsigned int squashfs_read_d
if (compressed) {
int zlib_err;
+#ifdef SQUASHFS_LZMA
+ if ((zlib_err = LzmaDecode(lzma_workspace,
+ LZMA_WORKSPACE_SIZE, LZMA_LC, LZMA_LP, LZMA_PB,
+ c_buffer, c_byte, buffer, msblk->read_size, &bytes)) != LZMA_RESULT_OK)
+ {
+ ERROR("lzma returned unexpected result 0x%x\n", zlib_err);
+ bytes = 0;
+ }
+#else
stream.next_in = c_buffer;
stream.avail_in = c_byte;
stream.next_out = buffer;
@@ -263,7 +293,7 @@ SQSH_EXTERN unsigned int squashfs_read_d
bytes = 0;
} else
bytes = stream.total_out;
-
+#endif
up(&msblk->read_data_mutex);
}
@@ -2045,15 +2075,19 @@ static int __init init_squashfs_fs(void)
printk(KERN_INFO "squashfs: version 3.0 (2006/03/15) "
"Phillip Lougher\n");
+#ifndef SQUASHFS_LZMA
if (!(stream.workspace = vmalloc(zlib_inflate_workspacesize()))) {
ERROR("Failed to allocate zlib workspace\n");
destroy_inodecache();
err = -ENOMEM;
goto out;
}
+#endif
if ((err = register_filesystem(&squashfs_fs_type))) {
+#ifndef SQUASHFS_LZMA
vfree(stream.workspace);
+#endif
destroy_inodecache();
}
@@ -2064,7 +2098,9 @@ out:
static void __exit exit_squashfs_fs(void)
{
+#ifndef SQUASHFS_LZMA
vfree(stream.workspace);
+#endif
unregister_filesystem(&squashfs_fs_type);
destroy_inodecache();
}

View file

@ -0,0 +1,12 @@
--- a/Makefile
+++ b/Makefile
@@ -549,6 +549,9 @@ endif
NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include)
CHECKFLAGS += $(NOSTDINC_FLAGS)
+# improve gcc optimization
+CFLAGS += $(call cc-option,-funit-at-a-time,)
+
# warn about C99 declaration after statement
KBUILD_CFLAGS += $(call cc-option,-Wdeclaration-after-statement,)

View file

@ -0,0 +1,29 @@
--- a/fs/squashfs/inode.c
+++ b/fs/squashfs/inode.c
@@ -33,6 +33,7 @@
#include <linux/fs.h>
#include <linux/smp_lock.h>
#include <linux/slab.h>
+#include <linux/exportfs.h>
#include <linux/squashfs_fs_sb.h>
#include <linux/squashfs_fs_i.h>
#include <linux/buffer_head.h>
@@ -43,8 +44,8 @@
#include <linux/zlib.h>
#include <linux/blkdev.h>
#include <linux/vmalloc.h>
+#include <linux/semaphore.h>
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include "squashfs.h"
@@ -2125,7 +2126,7 @@ static void squashfs_destroy_inode(struc
}
-static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags)
+static void init_once(void *foo)
{
struct squashfs_inode_info *ei = foo;

View file

@ -0,0 +1,11 @@
--- a/arch/mips/include/asm/system.h
+++ b/arch/mips/include/asm/system.h
@@ -187,7 +187,7 @@ extern __u64 __xchg_u64_unsupported_on_3
if something tries to do an invalid xchg(). */
extern void __xchg_called_with_bad_pointer(void);
-static inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
+static __always_inline unsigned long __xchg(unsigned long x, volatile void * ptr, int size)
{
switch (size) {
case 4:

View file

@ -0,0 +1,36 @@
--- a/drivers/mtd/chips/cfi_cmdset_0002.c
+++ b/drivers/mtd/chips/cfi_cmdset_0002.c
@@ -51,6 +51,7 @@
#define SST49LF040B 0x0050
#define SST49LF008A 0x005a
#define AT49BV6416 0x00d6
+#define MANUFACTURER_SAMSUNG 0x00ec
static int cfi_amdstd_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
static int cfi_amdstd_write_words(struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
@@ -365,12 +366,19 @@ struct mtd_info *cfi_cmdset_0002(struct
if (extp->MajorVersion != '1' ||
(extp->MinorVersion < '0' || extp->MinorVersion > '4')) {
- printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
- "version %c.%c.\n", extp->MajorVersion,
- extp->MinorVersion);
- kfree(extp);
- kfree(mtd);
- return NULL;
+ if (cfi->mfr == MANUFACTURER_SAMSUNG &&
+ (extp->MajorVersion == '3' && extp->MinorVersion == '3')) {
+ printk(KERN_NOTICE " Newer Samsung flash detected, "
+ "should be compatibile with Amd/Fujitsu.\n");
+ }
+ else {
+ printk(KERN_ERR " Unknown Amd/Fujitsu Extended Query "
+ "version %c.%c.\n", extp->MajorVersion,
+ extp->MinorVersion);
+ kfree(extp);
+ kfree(mtd);
+ return NULL;
+ }
}
/* Install our own private info structure */

View file

@ -0,0 +1,19 @@
--- a/fs/squashfs/Makefile
+++ b/fs/squashfs/Makefile
@@ -4,4 +4,3 @@
obj-$(CONFIG_SQUASHFS) += squashfs.o
squashfs-y += inode.o
-squashfs-y += squashfs2_0.o
--- a/fs/squashfs/squashfs.h
+++ b/fs/squashfs/squashfs.h
@@ -24,6 +24,9 @@
#ifdef CONFIG_SQUASHFS_1_0_COMPATIBILITY
#undef CONFIG_SQUASHFS_1_0_COMPATIBILITY
#endif
+#ifdef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#undef CONFIG_SQUASHFS_2_0_COMPATIBILITY
+#endif
#ifdef SQUASHFS_TRACE
#define TRACE(s, args...) printk(KERN_NOTICE "SQUASHFS: "s, ## args)

View file

@ -0,0 +1,11 @@
--- a/arch/mips/kernel/head.S
+++ b/arch/mips/kernel/head.S
@@ -121,6 +121,8 @@
#endif
.endm
+ j kernel_entry
+ nop
#ifndef CONFIG_NO_EXCEPT_FILL
/*
* Reserved space for exception handlers.

View file

@ -0,0 +1,133 @@
--- /dev/null
+++ b/include/asm-mips/mips_machine.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#ifndef __ASM_MIPS_MACHINE_H
+#define __ASM_MIPS_MACHINE_H
+
+#include <linux/init.h>
+#include <linux/list.h>
+
+#define MIPS_MACHINE_NAME_LEN 64
+
+struct mips_machine {
+ unsigned long mach_type;
+ void (*mach_setup)(void);
+ unsigned char mach_name[MIPS_MACHINE_NAME_LEN];
+ struct list_head list;
+};
+
+void mips_machine_register(struct mips_machine *) __init;
+void mips_machine_setup(unsigned long machtype) __init;
+
+extern unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN];
+
+#define MIPS_MACHINE(_type, _name, _setup) \
+static struct mips_machine machine_##_type __initdata = \
+{ \
+ .mach_type = _type, \
+ .mach_name = _name, \
+ .mach_setup = _setup, \
+}; \
+ \
+static int __init register_machine_##_type(void) \
+{ \
+ mips_machine_register(&machine_##_type); \
+ return 0; \
+} \
+ \
+pure_initcall(register_machine_##_type)
+
+#endif /* __ASM_MIPS_MACHINE_H */
+
--- /dev/null
+++ b/arch/mips/kernel/mips_machine.c
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2008 Gabor Juhos <juhosg@openwrt.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published
+ * by the Free Software Foundation.
+ *
+ */
+
+#include <asm/mips_machine.h>
+#include <asm/bootinfo.h>
+
+static struct list_head mips_machines __initdata =
+ LIST_HEAD_INIT(mips_machines);
+
+unsigned char mips_machine_name[MIPS_MACHINE_NAME_LEN] = "Unknown";
+
+static struct mips_machine * __init mips_machine_find(unsigned long machtype)
+{
+ struct list_head *this;
+
+ list_for_each(this, &mips_machines) {
+ struct mips_machine *mach;
+
+ mach = list_entry(this, struct mips_machine, list);
+ if (mach->mach_type == machtype)
+ return mach;
+ }
+
+ return NULL;
+}
+
+void __init mips_machine_register(struct mips_machine *mach)
+{
+ list_add_tail(&mach->list, &mips_machines);
+}
+
+void __init mips_machine_setup(unsigned long machtype)
+{
+ struct mips_machine *mach;
+
+ mach = mips_machine_find(machtype);
+ if (!mach) {
+ printk(KERN_ALERT "MIPS: no machine registered for "
+ "machtype %lu\n", machtype);
+ return;
+ }
+
+ if (mach->mach_name[0])
+ strncpy(mips_machine_name, mach->mach_name,
+ MIPS_MACHINE_NAME_LEN);
+
+ printk(KERN_INFO "MIPS: machine is %s\n", mips_machine_name);
+
+ if (mach->mach_setup)
+ mach->mach_setup();
+}
+
--- a/arch/mips/kernel/Makefile
+++ b/arch/mips/kernel/Makefile
@@ -84,6 +84,7 @@ obj-$(CONFIG_GPIO_TXX9) += gpio_txx9.o
obj-$(CONFIG_KEXEC) += machine_kexec.o relocate_kernel.o
obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
+obj-$(CONFIG_MIPS_MACHINE) += mips_machine.o
CFLAGS_cpu-bugs64.o = $(shell if $(CC) $(KBUILD_CFLAGS) -Wa,-mdaddi -c -o /dev/null -xc /dev/null >/dev/null 2>&1; then echo "-DHAVE_AS_SET_DADDI"; fi)
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -763,6 +763,9 @@ config MIPS_DISABLE_OBSOLETE_IDE
config SYNC_R4K
bool
+config MIPS_MACHINE
+ def_bool n
+
config NO_IOPORT
def_bool n

View file

@ -0,0 +1,110 @@
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -14,6 +14,7 @@
#include <linux/list.h>
#include <linux/init.h>
#include <linux/mtd/mtd.h>
+#include <linux/mtd/partitions.h>
#include <linux/buffer_head.h>
#include <linux/mutex.h>
#include <linux/mount.h>
@@ -232,10 +233,11 @@ static void block2mtd_free_device(struct
/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size)
+static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
{
struct block_device *bdev;
struct block2mtd_dev *dev;
+ struct mtd_partition *part;
char *name;
if (!devname)
@@ -273,17 +275,17 @@ static struct block2mtd_dev *add_device(
mutex_init(&dev->write_mutex);
- /* Setup the MTD structure */
- /* make the name contain the block device in */
- name = kmalloc(sizeof("block2mtd: ") + strlen(devname) + 1,
- GFP_KERNEL);
+ if (!mtdname)
+ mtdname = devname;
+
+ name = kmalloc(strlen(mtdname) + 1, GFP_KERNEL);
if (!name)
goto devinit_err;
- sprintf(name, "block2mtd: %s", devname);
+ strcpy(name, mtdname);
dev->mtd.name = name;
- dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK;
+ dev->mtd.size = dev->blkdev->bd_inode->i_size & PAGE_MASK & ~(erase_size - 1);
dev->mtd.erasesize = erase_size;
dev->mtd.writesize = 1;
dev->mtd.type = MTD_RAM;
@@ -296,14 +298,17 @@ static struct block2mtd_dev *add_device(
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
- if (add_mtd_device(&dev->mtd)) {
+ part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
+ part->name = dev->mtd.name;
+ part->offset = 0;
+ part->size = dev->mtd.size;
+ if (add_mtd_partitions(&dev->mtd, part, 1)) {
/* Device didnt get added, so free the entry */
goto devinit_err;
}
list_add(&dev->list, &blkmtd_device_list);
INFO("mtd%d: [%s] erase_size = %dKiB [%d]", dev->mtd.index,
- dev->mtd.name + strlen("block2mtd: "),
- dev->mtd.erasesize >> 10, dev->mtd.erasesize);
+ mtdname, dev->mtd.erasesize >> 10, dev->mtd.erasesize);
return dev;
devinit_err:
@@ -376,9 +381,9 @@ static char block2mtd_paramline[80 + 12]
static int block2mtd_setup2(const char *val)
{
- char buf[80 + 12]; /* 80 for device, 12 for erase size */
+ char buf[80 + 12 + 80]; /* 80 for device, 12 for erase size, 80 for name */
char *str = buf;
- char *token[2];
+ char *token[3];
char *name;
size_t erase_size = PAGE_SIZE;
int i, ret;
@@ -389,7 +394,7 @@ static int block2mtd_setup2(const char *
strcpy(str, val);
kill_final_newline(str);
- for (i = 0; i < 2; i++)
+ for (i = 0; i < 3; i++)
token[i] = strsep(&str, ",");
if (str)
@@ -408,8 +413,10 @@ static int block2mtd_setup2(const char *
parse_err("illegal erase size");
}
}
+ if (token[2] && (strlen(token[2]) + 1 > 80))
+ parse_err("mtd device name too long");
- add_device(name, erase_size);
+ add_device(name, erase_size, token[2]);
return 0;
}
@@ -443,7 +450,7 @@ static int block2mtd_setup(const char *v
module_param_call(block2mtd, block2mtd_setup, NULL, NULL, 0200);
-MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>]\"");
+MODULE_PARM_DESC(block2mtd, "Device to use. \"block2mtd=<dev>[,<erasesize>[,<name>]]\"");
static int __init block2mtd_init(void)
{

View file

@ -0,0 +1,625 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -45,6 +45,16 @@ config MTD_PARTITIONS
devices. Partitioning on NFTL 'devices' is a different - that's the
'normal' form of partitioning used on a block device.
+config MTD_ROOTFS_ROOT_DEV
+ bool "Automatically set 'rootfs' partition to be root filesystem"
+ depends on MTD_PARTITIONS
+ default y
+
+config MTD_ROOTFS_SPLIT
+ bool "Automatically split 'rootfs' partition for squashfs"
+ depends on MTD_PARTITIONS
+ default y
+
config MTD_REDBOOT_PARTS
tristate "RedBoot partition table parsing"
depends on MTD_PARTITIONS
--- a/drivers/mtd/mtdpart.c
+++ b/drivers/mtd/mtdpart.c
@@ -18,6 +18,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/compatmac.h>
+#include <linux/squashfs_fs.h>
+#include <linux/root_dev.h>
/* Our partition linked list */
static LIST_HEAD(mtd_partitions);
@@ -37,7 +39,7 @@ struct mtd_part {
* the pointer to that structure with this macro.
*/
#define PART(x) ((struct mtd_part *)(x))
-
+#define IS_PART(mtd) (mtd->read == part_read)
/*
* MTD methods which simply translate the effective address and pass through
@@ -489,6 +491,148 @@ out_register:
return slave;
}
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+#define ROOTFS_SPLIT_NAME "rootfs_data"
+#define ROOTFS_REMOVED_NAME "<removed>"
+static int split_squashfs(struct mtd_info *master, int offset, int *split_offset)
+{
+ char buf[512];
+ struct squashfs_super_block *sb = (struct squashfs_super_block *) buf;
+ int len, ret;
+
+ ret = master->read(master, offset, sizeof(*sb), &len, buf);
+ if (ret || (len != sizeof(*sb))) {
+ printk(KERN_ALERT "split_squashfs: error occured while reading "
+ "from \"%s\"\n", master->name);
+ return -EINVAL;
+ }
+
+ if (*((u32 *) buf) != SQUASHFS_MAGIC) {
+ printk(KERN_ALERT "split_squashfs: no squashfs found in \"%s\"\n",
+ master->name);
+ *split_offset = 0;
+ return 0;
+ }
+
+ if (sb->bytes_used <= 0) {
+ printk(KERN_ALERT "split_squashfs: squashfs is empty in \"%s\"\n",
+ master->name);
+ *split_offset = 0;
+ return 0;
+ }
+
+ len = (u32) sb->bytes_used;
+ len += (offset & 0x000fffff);
+ len += (master->erasesize - 1);
+ len &= ~(master->erasesize - 1);
+ len -= (offset & 0x000fffff);
+ *split_offset = offset + len;
+
+ return 0;
+}
+
+static int split_rootfs_data(struct mtd_info *master, struct mtd_info *rpart, const struct mtd_partition *part,
+ int index)
+{
+ struct mtd_partition *dpart;
+ struct mtd_part *slave = NULL;
+ int split_offset = 0;
+ int ret;
+
+ ret = split_squashfs(master, part->offset, &split_offset);
+ if (ret)
+ return ret;
+
+ if (split_offset <= 0)
+ return 0;
+
+ dpart = kmalloc(sizeof(*part)+sizeof(ROOTFS_SPLIT_NAME)+1, GFP_KERNEL);
+ if (dpart == NULL) {
+ printk(KERN_INFO "split_squashfs: no memory for partition \"%s\"\n",
+ ROOTFS_SPLIT_NAME);
+ return -ENOMEM;
+ }
+
+ memcpy(dpart, part, sizeof(*part));
+ dpart->name = (unsigned char *)&dpart[1];
+ strcpy(dpart->name, ROOTFS_SPLIT_NAME);
+
+ dpart->size -= split_offset - dpart->offset;
+ dpart->offset = split_offset;
+
+ if (dpart == NULL)
+ return 1;
+
+ printk(KERN_INFO "mtd: partition \"%s\" created automatically, ofs=%X, len=%X \n",
+ ROOTFS_SPLIT_NAME, dpart->offset, dpart->size);
+
+ slave = add_one_partition(master, dpart, index, split_offset);
+ if (!slave) {
+ kfree(dpart);
+ return -ENOMEM;
+ }
+ rpart->split = &slave->mtd;
+
+ return 0;
+}
+
+static int refresh_rootfs_split(struct mtd_info *mtd)
+{
+ struct mtd_partition tpart;
+ struct mtd_part *part;
+ char *name;
+ int index = 0;
+ int offset, size;
+ int ret;
+
+ part = PART(mtd);
+
+ /* check for the new squashfs offset first */
+ ret = split_squashfs(part->master, part->offset, &offset);
+ if (ret)
+ return ret;
+
+ if ((offset > 0) && !mtd->split) {
+ printk(KERN_INFO "%s: creating new split partition for \"%s\"\n", __func__, mtd->name);
+ /* if we don't have a rootfs split partition, create a new one */
+ tpart.name = (char *) mtd->name;
+ tpart.size = mtd->size;
+ tpart.offset = part->offset;
+
+ /* find the index of the last partition */
+ if (!list_empty(&mtd_partitions))
+ index = list_first_entry(&mtd_partitions, struct mtd_part, list)->index + 1;
+
+ return split_rootfs_data(part->master, &part->mtd, &tpart, index);
+ } else if ((offset > 0) && mtd->split) {
+ /* update the offsets of the existing partition */
+ size = mtd->size + part->offset - offset;
+
+ part = PART(mtd->split);
+ part->offset = offset;
+ part->mtd.size = size;
+ printk(KERN_INFO "%s: %s partition \"" ROOTFS_SPLIT_NAME "\", offset: 0x%06x (0x%06x)\n",
+ __func__, (!strcmp(part->mtd.name, ROOTFS_SPLIT_NAME) ? "updating" : "creating"),
+ part->offset, part->mtd.size);
+ name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+ strcpy(name, ROOTFS_SPLIT_NAME);
+ part->mtd.name = name;
+ } else if ((offset <= 0) && mtd->split) {
+ printk(KERN_INFO "%s: removing partition \"%s\"\n", __func__, mtd->split->name);
+
+ /* mark existing partition as removed */
+ part = PART(mtd->split);
+ name = kmalloc(sizeof(ROOTFS_SPLIT_NAME) + 1, GFP_KERNEL);
+ strcpy(name, ROOTFS_REMOVED_NAME);
+ part->mtd.name = name;
+ part->offset = 0;
+ part->mtd.size = 0;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_MTD_ROOTFS_SPLIT */
+
/*
* This function, given a master MTD object and a partition table, creates
* and registers slave MTD objects which are bound to the master according to
@@ -502,14 +646,29 @@ int add_mtd_partitions(struct mtd_info *
{
struct mtd_part *slave;
u_int32_t cur_offset = 0;
- int i;
+ int i, j, ret;
printk(KERN_NOTICE "Creating %d MTD partitions on \"%s\":\n", nbparts, master->name);
- for (i = 0; i < nbparts; i++) {
- slave = add_one_partition(master, parts + i, i, cur_offset);
+ for (i = 0, j = 0; i < nbparts; i++) {
+ slave = add_one_partition(master, parts + i, j++, cur_offset);
if (!slave)
return -ENOMEM;
+
+ if (!strcmp(parts[i].name, "rootfs") && slave->registered) {
+#ifdef CONFIG_MTD_ROOTFS_ROOT_DEV
+ if (ROOT_DEV == 0) {
+ printk(KERN_NOTICE "mtd: partition \"rootfs\" "
+ "set to be root filesystem\n");
+ ROOT_DEV = MKDEV(MTD_BLOCK_MAJOR, slave->mtd.index);
+ }
+#endif
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+ ret = split_rootfs_data(master, &slave->mtd, &parts[i], j);
+ if (ret == 0)
+ j++;
+#endif
+ }
cur_offset = slave->offset + slave->mtd.size;
}
@@ -517,6 +676,32 @@ int add_mtd_partitions(struct mtd_info *
}
EXPORT_SYMBOL(add_mtd_partitions);
+int refresh_mtd_partitions(struct mtd_info *mtd)
+{
+ int ret = 0;
+
+ if (IS_PART(mtd)) {
+ struct mtd_part *part;
+ struct mtd_info *master;
+
+ part = PART(mtd);
+ master = part->master;
+ if (master->refresh_device)
+ ret = master->refresh_device(master);
+ }
+
+ if (!ret && mtd->refresh_device)
+ ret = mtd->refresh_device(mtd);
+
+#ifdef CONFIG_MTD_ROOTFS_SPLIT
+ if (!ret && IS_PART(mtd) && !strcmp(mtd->name, "rootfs"))
+ refresh_rootfs_split(mtd);
+#endif
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(refresh_mtd_partitions);
+
static DEFINE_SPINLOCK(part_parser_lock);
static LIST_HEAD(part_parsers);
--- a/drivers/mtd/devices/block2mtd.c
+++ b/drivers/mtd/devices/block2mtd.c
@@ -29,6 +29,8 @@ struct block2mtd_dev {
struct block_device *blkdev;
struct mtd_info mtd;
struct mutex write_mutex;
+ rwlock_t bdev_mutex;
+ char devname[0];
};
@@ -81,6 +83,12 @@ static int block2mtd_erase(struct mtd_in
size_t len = instr->len;
int err;
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev) {
+ err = -EINVAL;
+ goto done;
+ }
+
instr->state = MTD_ERASING;
mutex_lock(&dev->write_mutex);
err = _block2mtd_erase(dev, from, len);
@@ -93,6 +101,10 @@ static int block2mtd_erase(struct mtd_in
instr->state = MTD_ERASE_DONE;
mtd_erase_callback(instr);
+
+done:
+ read_unlock(&dev->bdev_mutex);
+
return err;
}
@@ -104,10 +116,14 @@ static int block2mtd_read(struct mtd_inf
struct page *page;
int index = from >> PAGE_SHIFT;
int offset = from & (PAGE_SIZE-1);
- int cpylen;
+ int cpylen, err = 0;
+
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev || (from > mtd->size)) {
+ err = -EINVAL;
+ goto done;
+ }
- if (from > mtd->size)
- return -EINVAL;
if (from + len > mtd->size)
len = mtd->size - from;
@@ -122,10 +138,14 @@ static int block2mtd_read(struct mtd_inf
len = len - cpylen;
page = page_read(dev->blkdev->bd_inode->i_mapping, index);
- if (!page)
- return -ENOMEM;
- if (IS_ERR(page))
- return PTR_ERR(page);
+ if (!page) {
+ err = -ENOMEM;
+ goto done;
+ }
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto done;
+ }
memcpy(buf, page_address(page) + offset, cpylen);
page_cache_release(page);
@@ -136,7 +156,10 @@ static int block2mtd_read(struct mtd_inf
offset = 0;
index++;
}
- return 0;
+
+done:
+ read_unlock(&dev->bdev_mutex);
+ return err;
}
@@ -188,12 +211,22 @@ static int block2mtd_write(struct mtd_in
size_t *retlen, const u_char *buf)
{
struct block2mtd_dev *dev = mtd->priv;
- int err;
+ int err = 0;
+
+ read_lock(&dev->bdev_mutex);
+ if (!dev->blkdev) {
+ err = -EINVAL;
+ goto done;
+ }
if (!len)
- return 0;
- if (to >= mtd->size)
- return -ENOSPC;
+ goto done;
+
+ if (to >= mtd->size) {
+ err = -ENOSPC;
+ goto done;
+ }
+
if (to + len > mtd->size)
len = mtd->size - to;
@@ -202,6 +235,9 @@ static int block2mtd_write(struct mtd_in
mutex_unlock(&dev->write_mutex);
if (err > 0)
err = 0;
+
+done:
+ read_unlock(&dev->bdev_mutex);
return err;
}
@@ -210,52 +246,29 @@ static int block2mtd_write(struct mtd_in
static void block2mtd_sync(struct mtd_info *mtd)
{
struct block2mtd_dev *dev = mtd->priv;
- sync_blockdev(dev->blkdev);
- return;
-}
-
-
-static void block2mtd_free_device(struct block2mtd_dev *dev)
-{
- if (!dev)
- return;
-
- kfree(dev->mtd.name);
- if (dev->blkdev) {
- invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping,
- 0, -1);
- close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
- }
+ read_lock(&dev->bdev_mutex);
+ if (dev->blkdev)
+ sync_blockdev(dev->blkdev);
+ read_unlock(&dev->bdev_mutex);
- kfree(dev);
+ return;
}
-/* FIXME: ensure that mtd->size % erase_size == 0 */
-static struct block2mtd_dev *add_device(char *devname, int erase_size, const char *mtdname)
+static int _open_bdev(struct block2mtd_dev *dev)
{
struct block_device *bdev;
- struct block2mtd_dev *dev;
- struct mtd_partition *part;
- char *name;
-
- if (!devname)
- return NULL;
-
- dev = kzalloc(sizeof(struct block2mtd_dev), GFP_KERNEL);
- if (!dev)
- return NULL;
/* Get a handle on the device */
- bdev = open_bdev_exclusive(devname, FMODE_READ|FMODE_WRITE, NULL);
+ bdev = open_bdev_exclusive(dev->devname, FMODE_READ|FMODE_WRITE, NULL);
#ifndef MODULE
if (IS_ERR(bdev)) {
/* We might not have rootfs mounted at this point. Try
to resolve the device name by other means. */
- dev_t devt = name_to_dev_t(devname);
+ dev_t devt = name_to_dev_t(dev->devname);
if (devt) {
bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
}
@@ -263,17 +276,97 @@ static struct block2mtd_dev *add_device(
#endif
if (IS_ERR(bdev)) {
- ERROR("error: cannot open device %s", devname);
- goto devinit_err;
+ ERROR("error: cannot open device %s", dev->devname);
+ return 1;
}
dev->blkdev = bdev;
if (MAJOR(bdev->bd_dev) == MTD_BLOCK_MAJOR) {
ERROR("attempting to use an MTD device as a block device");
- goto devinit_err;
+ return 1;
}
+ return 0;
+}
+
+static void _close_bdev(struct block2mtd_dev *dev)
+{
+ struct block_device *bdev;
+
+ if (!dev->blkdev)
+ return;
+
+ bdev = dev->blkdev;
+ invalidate_mapping_pages(dev->blkdev->bd_inode->i_mapping, 0, -1);
+ close_bdev_exclusive(dev->blkdev, FMODE_READ|FMODE_WRITE);
+ dev->blkdev = NULL;
+}
+
+static void block2mtd_free_device(struct block2mtd_dev *dev)
+{
+ if (!dev)
+ return;
+
+ kfree(dev->mtd.name);
+ _close_bdev(dev);
+ kfree(dev);
+}
+
+
+static int block2mtd_refresh(struct mtd_info *mtd)
+{
+ struct block2mtd_dev *dev = mtd->priv;
+ struct block_device *bdev;
+ dev_t devt;
+ int err = 0;
+
+ /* no other mtd function can run at this point */
+ write_lock(&dev->bdev_mutex);
+
+ /* get the device number for the whole disk */
+ devt = MKDEV(MAJOR(dev->blkdev->bd_dev), 0);
+
+ /* close the old block device */
+ _close_bdev(dev);
+
+ /* open the whole disk, issue a partition rescan, then */
+ bdev = open_by_devnum(devt, FMODE_WRITE | FMODE_READ);
+ if (!bdev || !bdev->bd_disk)
+ err = -EINVAL;
+ else {
+ err = rescan_partitions(bdev->bd_disk, bdev);
+ }
+ if (bdev)
+ close_bdev_exclusive(bdev, FMODE_READ|FMODE_WRITE);
+
+ /* try to open the partition block device again */
+ _open_bdev(dev);
+ write_unlock(&dev->bdev_mutex);
+
+ return err;
+}
+
+/* FIXME: ensure that mtd->size % erase_size == 0 */
+static struct block2mtd_dev *add_device(char *devname, int erase_size, char *mtdname)
+{
+ struct block2mtd_dev *dev;
+ struct mtd_partition *part;
+ char *name;
+
+ if (!devname)
+ return NULL;
+
+ dev = kzalloc(sizeof(struct block2mtd_dev) + strlen(devname) + 1, GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ strcpy(dev->devname, devname);
+
+ if (_open_bdev(dev))
+ goto devinit_err;
+
mutex_init(&dev->write_mutex);
+ rwlock_init(&dev->bdev_mutex);
if (!mtdname)
mtdname = devname;
@@ -297,6 +390,7 @@ static struct block2mtd_dev *add_device(
dev->mtd.read = block2mtd_read;
dev->mtd.priv = dev;
dev->mtd.owner = THIS_MODULE;
+ dev->mtd.refresh_device = block2mtd_refresh;
part = kzalloc(sizeof(struct mtd_partition), GFP_KERNEL);
part->name = dev->mtd.name;
--- a/drivers/mtd/mtdchar.c
+++ b/drivers/mtd/mtdchar.c
@@ -16,6 +16,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/compatmac.h>
+#include <linux/mtd/partitions.h>
#include <asm/uaccess.h>
@@ -769,6 +770,13 @@ static int mtd_ioctl(struct inode *inode
file->f_pos = 0;
break;
}
+#ifdef CONFIG_MTD_PARTITIONS
+ case MTDREFRESH:
+ {
+ ret = refresh_mtd_partitions(mtd);
+ break;
+ }
+#endif
default:
ret = -ENOTTY;
--- a/include/linux/mtd/mtd.h
+++ b/include/linux/mtd/mtd.h
@@ -98,6 +98,7 @@ struct mtd_oob_ops {
uint8_t *oobbuf;
};
+struct mtd_info;
struct mtd_info {
u_char type;
u_int32_t flags;
@@ -213,6 +214,9 @@ struct mtd_info {
struct module *owner;
int usecount;
+ int (*refresh_device)(struct mtd_info *mtd);
+ struct mtd_info *split;
+
/* If the driver is something smart, like UBI, it may need to maintain
* its own reference counting. The below functions are only for driver.
* The driver may register its callbacks. These callbacks are not
--- a/include/linux/mtd/partitions.h
+++ b/include/linux/mtd/partitions.h
@@ -34,6 +34,7 @@
* erasesize aligned (e.g. use MTDPART_OFS_NEXTBLK).
*/
+struct mtd_partition;
struct mtd_partition {
char *name; /* identifier string */
u_int32_t size; /* partition size */
@@ -41,6 +42,7 @@ struct mtd_partition {
u_int32_t mask_flags; /* master MTD flags to mask out for this partition */
struct nand_ecclayout *ecclayout; /* out of band layout for this partition (NAND only)*/
struct mtd_info **mtdp; /* pointer to store the MTD object */
+ int (*refresh_partition)(struct mtd_info *);
};
#define MTDPART_OFS_NXTBLK (-2)
@@ -50,6 +52,7 @@ struct mtd_partition {
int add_mtd_partitions(struct mtd_info *, const struct mtd_partition *, int);
int del_mtd_partitions(struct mtd_info *);
+int refresh_mtd_partitions(struct mtd_info *);
/*
* Functions dealing with the various ways of partitioning the space
--- a/include/mtd/mtd-abi.h
+++ b/include/mtd/mtd-abi.h
@@ -93,6 +93,7 @@ struct otp_info {
#define ECCGETLAYOUT _IOR('M', 17, struct nand_ecclayout)
#define ECCGETSTATS _IOR('M', 18, struct mtd_ecc_stats)
#define MTDFILEMODE _IO('M', 19)
+#define MTDREFRESH _IO('M', 23)
/*
* Obsolete legacy interface. Keep it in order not to break userspace

View file

@ -0,0 +1,30 @@
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -249,14 +249,21 @@ static int parse_redboot_partitions(stru
#endif
names += strlen(names)+1;
-#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if(fl->next && fl->img->flash_base + fl->img->size + master->erasesize <= fl->next->img->flash_base) {
- i++;
- parts[i].offset = parts[i-1].size + parts[i-1].offset;
- parts[i].size = fl->next->img->flash_base - parts[i].offset;
- parts[i].name = nullname;
- }
+ if (!strcmp(parts[i].name, "rootfs")) {
+ parts[i].size = fl->next->img->flash_base;
+ parts[i].size &= ~(master->erasesize - 1);
+ parts[i].size -= parts[i].offset;
+#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
+ nrparts--;
+ } else {
+ i++;
+ parts[i].offset = parts[i-1].size + parts[i-1].offset;
+ parts[i].size = fl->next->img->flash_base - parts[i].offset;
+ parts[i].name = nullname;
#endif
+ }
+ }
tmp_fl = fl;
fl = fl->next;
kfree(tmp_fl);

View file

@ -0,0 +1,60 @@
--- a/drivers/mtd/redboot.c
+++ b/drivers/mtd/redboot.c
@@ -11,6 +11,8 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
+#define BOARD_CONFIG_PART "boardconfig"
+
struct fis_image_desc {
unsigned char name[16]; // Null terminated name
uint32_t flash_base; // Address within FLASH of image
@@ -41,6 +43,7 @@ static int parse_redboot_partitions(stru
struct mtd_partition **pparts,
unsigned long fis_origin)
{
+ unsigned long max_offset = 0;
int nrparts = 0;
struct fis_image_desc *buf;
struct mtd_partition *parts;
@@ -209,14 +212,14 @@ static int parse_redboot_partitions(stru
}
}
#endif
- parts = kzalloc(sizeof(*parts)*nrparts + nulllen + namelen, GFP_KERNEL);
+ parts = kzalloc(sizeof(*parts) * (nrparts + 1) + nulllen + namelen + sizeof(BOARD_CONFIG_PART), GFP_KERNEL);
if (!parts) {
ret = -ENOMEM;
goto out;
}
- nullname = (char *)&parts[nrparts];
+ nullname = (char *)&parts[nrparts + 1];
#ifdef CONFIG_MTD_REDBOOT_PARTS_UNALLOCATED
if (nulllen > 0) {
strcpy(nullname, nullstring);
@@ -235,6 +238,8 @@ static int parse_redboot_partitions(stru
}
#endif
for ( ; i<nrparts; i++) {
+ if(max_offset < buf[i].flash_base + buf[i].size)
+ max_offset = buf[i].flash_base + buf[i].size;
parts[i].size = fl->img->size;
parts[i].offset = fl->img->flash_base;
parts[i].name = names;
@@ -268,6 +273,14 @@ static int parse_redboot_partitions(stru
fl = fl->next;
kfree(tmp_fl);
}
+ if(master->size - max_offset >= master->erasesize)
+ {
+ parts[nrparts].size = master->size - max_offset;
+ parts[nrparts].offset = max_offset;
+ parts[nrparts].name = names;
+ strcpy(names, BOARD_CONFIG_PART);
+ nrparts++;
+ }
ret = nrparts;
*pparts = parts;
out:

View file

@ -0,0 +1,32 @@
--- a/include/linux/mtd/nand.h
+++ b/include/linux/mtd/nand.h
@@ -579,6 +579,7 @@ struct platform_nand_chip {
int chip_delay;
unsigned int options;
const char **part_probe_types;
+ int (*chip_fixup)(struct mtd_info *mtd);
void *priv;
};
--- a/drivers/mtd/nand/plat_nand.c
+++ b/drivers/mtd/nand/plat_nand.c
@@ -71,7 +71,18 @@ static int __init plat_nand_probe(struct
platform_set_drvdata(pdev, data);
/* Scan to find existance of the device */
- if (nand_scan(&data->mtd, 1)) {
+ if (nand_scan_ident(&data->mtd, 1)) {
+ res = -ENXIO;
+ goto out;
+ }
+
+ if (pdata->chip.chip_fixup) {
+ res = pdata->chip.chip_fixup(&data->mtd);
+ if (res)
+ goto out;
+ }
+
+ if (nand_scan_tail(&data->mtd)) {
res = -ENXIO;
goto out;
}

View file

@ -0,0 +1,35 @@
--- a/drivers/mtd/Kconfig
+++ b/drivers/mtd/Kconfig
@@ -172,6 +172,22 @@ config MTD_AR7_PARTS
---help---
TI AR7 partitioning support
+config MTD_MYLOADER_PARTS
+ tristate "MyLoader partition parsing"
+ depends on MTD_PARTITIONS && (ADM5120 || ATHEROS || ATHEROS_AR71XX)
+ ---help---
+ MyLoader is a bootloader which allows the user to define partitions
+ in flash devices, by putting a table in the second erase block
+ on the device, similar to a partition table. This table gives the
+ offsets and lengths of the user defined partitions.
+
+ If you need code which can detect and parse these tables, and
+ register MTD 'partitions' corresponding to each image detected,
+ enable this option.
+
+ You will still need the parsing functions to be called by the driver
+ for your particular device. It won't happen automatically.
+
comment "User Modules And Translation Layers"
config MTD_CHAR
--- a/drivers/mtd/Makefile
+++ b/drivers/mtd/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_MTD_CMDLINE_PARTS) += cmdli
obj-$(CONFIG_MTD_AFS_PARTS) += afs.o
obj-$(CONFIG_MTD_AR7_PARTS) += ar7part.o
obj-$(CONFIG_MTD_OF_PARTS) += ofpart.o
+obj-$(CONFIG_MTD_MYLOADER_PARTS) += myloader.o
# 'Users' - code which presents functionality to userspace.
obj-$(CONFIG_MTD_CHAR) += mtdchar.o

View file

@ -0,0 +1,21 @@
--- a/drivers/rtc/rtc-ds1672.c
+++ b/drivers/rtc/rtc-ds1672.c
@@ -209,12 +209,18 @@ static int ds1672_probe(struct i2c_clien
return err;
}
+static struct i2c_device_id ds1672_id[] = {
+ { "ds1672", 0 },
+ { }
+};
+
static struct i2c_driver ds1672_driver = {
.driver = {
.name = "rtc-ds1672",
},
.probe = &ds1672_probe,
.remove = &ds1672_remove,
+ .id_table = ds1672_id,
};
static int __init ds1672_init(void)

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
--- a/include/linux/netfilter/xt_layer7.h
+++ b/include/linux/netfilter/xt_layer7.h
@@ -8,6 +8,7 @@ struct xt_layer7_info {
char protocol[MAX_PROTOCOL_LEN];
char pattern[MAX_PATTERN_LEN];
u_int8_t invert;
+ u_int8_t pkt;
};
#endif /* _XT_LAYER7_H */
--- a/net/netfilter/xt_layer7.c
+++ b/net/netfilter/xt_layer7.c
@@ -314,33 +314,35 @@ static int match_no_append(struct nf_con
}
/* add the new app data to the conntrack. Return number of bytes added. */
-static int add_data(struct nf_conn * master_conntrack,
- char * app_data, int appdatalen)
+static int add_datastr(char *target, int offset, char *app_data, int len)
{
int length = 0, i;
- int oldlength = master_conntrack->layer7.app_data_len;
-
- /* This is a fix for a race condition by Deti Fliegl. However, I'm not
- clear on whether the race condition exists or whether this really
- fixes it. I might just be being dense... Anyway, if it's not really
- a fix, all it does is waste a very small amount of time. */
- if(!master_conntrack->layer7.app_data) return 0;
+ if (!target) return 0;
/* Strip nulls. Make everything lower case (our regex lib doesn't
do case insensitivity). Add it to the end of the current data. */
- for(i = 0; i < maxdatalen-oldlength-1 &&
- i < appdatalen; i++) {
+ for(i = 0; i < maxdatalen-offset-1 && i < len; i++) {
if(app_data[i] != '\0') {
/* the kernel version of tolower mungs 'upper ascii' */
- master_conntrack->layer7.app_data[length+oldlength] =
+ target[length+offset] =
isascii(app_data[i])?
tolower(app_data[i]) : app_data[i];
length++;
}
}
+ target[length+offset] = '\0';
+
+ return length;
+}
+
+/* add the new app data to the conntrack. Return number of bytes added. */
+static int add_data(struct nf_conn * master_conntrack,
+ char * app_data, int appdatalen)
+{
+ int length;
- master_conntrack->layer7.app_data[length+oldlength] = '\0';
- master_conntrack->layer7.app_data_len = length + oldlength;
+ length = add_datastr(master_conntrack->layer7.app_data, master_conntrack->layer7.app_data_len, app_data, appdatalen);
+ master_conntrack->layer7.app_data_len += length;
return length;
}
@@ -428,7 +430,7 @@ match(const struct sk_buff *skbin,
const struct xt_layer7_info * info = matchinfo;
enum ip_conntrack_info master_ctinfo, ctinfo;
struct nf_conn *master_conntrack, *conntrack;
- unsigned char * app_data;
+ unsigned char *app_data, *tmp_data;
unsigned int pattern_result, appdatalen;
regexp * comppattern;
@@ -456,8 +458,8 @@ match(const struct sk_buff *skbin,
master_conntrack = master_ct(master_conntrack);
/* if we've classified it or seen too many packets */
- if(total_acct_packets(master_conntrack) > num_packets ||
- master_conntrack->layer7.app_proto) {
+ if(!info->pkt && (total_acct_packets(master_conntrack) > num_packets ||
+ master_conntrack->layer7.app_proto)) {
pattern_result = match_no_append(conntrack, master_conntrack,
ctinfo, master_ctinfo, info);
@@ -490,6 +492,25 @@ match(const struct sk_buff *skbin,
/* the return value gets checked later, when we're ready to use it */
comppattern = compile_and_cache(info->pattern, info->protocol);
+ if (info->pkt) {
+ tmp_data = kmalloc(maxdatalen, GFP_ATOMIC);
+ if(!tmp_data){
+ if (net_ratelimit())
+ printk(KERN_ERR "layer7: out of memory in match, bailing.\n");
+ return info->invert;
+ }
+
+ tmp_data[0] = '\0';
+ add_datastr(tmp_data, 0, app_data, appdatalen);
+ pattern_result = ((comppattern && regexec(comppattern, tmp_data)) ? 1 : 0);
+
+ kfree(tmp_data);
+ tmp_data = NULL;
+ spin_unlock_bh(&l7_lock);
+
+ return (pattern_result ^ info->invert);
+ }
+
/* On the first packet of a connection, allocate space for app data */
if(total_acct_packets(master_conntrack) == 1 && !skb->cb[0] &&
!master_conntrack->layer7.app_data){

View file

@ -0,0 +1,919 @@
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_ipp2p.h
@@ -0,0 +1,31 @@
+#ifndef __IPT_IPP2P_H
+#define __IPT_IPP2P_H
+#define IPP2P_VERSION "0.8.1_rc1"
+
+struct ipt_p2p_info {
+ int cmd;
+ int debug;
+};
+
+#endif //__IPT_IPP2P_H
+
+#define SHORT_HAND_IPP2P 1 /* --ipp2p switch*/
+//#define SHORT_HAND_DATA 4 /* --ipp2p-data switch*/
+#define SHORT_HAND_NONE 5 /* no short hand*/
+
+#define IPP2P_EDK (1 << 1)
+#define IPP2P_DATA_KAZAA (1 << 2)
+#define IPP2P_DATA_EDK (1 << 3)
+#define IPP2P_DATA_DC (1 << 4)
+#define IPP2P_DC (1 << 5)
+#define IPP2P_DATA_GNU (1 << 6)
+#define IPP2P_GNU (1 << 7)
+#define IPP2P_KAZAA (1 << 8)
+#define IPP2P_BIT (1 << 9)
+#define IPP2P_APPLE (1 << 10)
+#define IPP2P_SOUL (1 << 11)
+#define IPP2P_WINMX (1 << 12)
+#define IPP2P_ARES (1 << 13)
+#define IPP2P_MUTE (1 << 14)
+#define IPP2P_WASTE (1 << 15)
+#define IPP2P_XDCC (1 << 16)
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_ipp2p.c
@@ -0,0 +1,856 @@
+#if defined(MODVERSIONS)
+#include <linux/modversions.h>
+#endif
+#include <linux/module.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/version.h>
+#include <linux/netfilter_ipv4/ipt_ipp2p.h>
+#include <net/tcp.h>
+#include <net/udp.h>
+
+#define get_u8(X,O) (*(__u8 *)(X + O))
+#define get_u16(X,O) (*(__u16 *)(X + O))
+#define get_u32(X,O) (*(__u32 *)(X + O))
+
+MODULE_AUTHOR("Eicke Friedrich/Klaus Degner <ipp2p@ipp2p.org>");
+MODULE_DESCRIPTION("An extension to iptables to identify P2P traffic.");
+MODULE_LICENSE("GPL");
+
+
+/*Search for UDP eDonkey/eMule/Kad commands*/
+int
+udp_search_edk (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+ t += 8;
+
+ switch (t[0]) {
+ case 0xe3:
+ { /*edonkey*/
+ switch (t[1])
+ {
+ /* client -> server status request */
+ case 0x96:
+ if (packet_len == 14) return ((IPP2P_EDK * 100) + 50);
+ break;
+ /* server -> client status request */
+ case 0x97: if (packet_len == 42) return ((IPP2P_EDK * 100) + 51);
+ break;
+ /* server description request */
+ /* e3 2a ff f0 .. | size == 6 */
+ case 0xa2: if ( (packet_len == 14) && ( get_u16(t,2) == __constant_htons(0xfff0) ) ) return ((IPP2P_EDK * 100) + 52);
+ break;
+ /* server description response */
+ /* e3 a3 ff f0 .. | size > 40 && size < 200 */
+ //case 0xa3: return ((IPP2P_EDK * 100) + 53);
+ // break;
+ case 0x9a: if (packet_len==26) return ((IPP2P_EDK * 100) + 54);
+ break;
+
+ case 0x92: if (packet_len==18) return ((IPP2P_EDK * 100) + 55);
+ break;
+ }
+ break;
+ }
+ case 0xe4:
+ {
+ switch (t[1])
+ {
+ /* e4 20 .. | size == 43 */
+ case 0x20: if ((packet_len == 43) && (t[2] != 0x00) && (t[34] != 0x00)) return ((IPP2P_EDK * 100) + 60);
+ break;
+ /* e4 00 .. 00 | size == 35 ? */
+ case 0x00: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 61);
+ break;
+ /* e4 10 .. 00 | size == 35 ? */
+ case 0x10: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 62);
+ break;
+ /* e4 18 .. 00 | size == 35 ? */
+ case 0x18: if ((packet_len == 35) && (t[26] == 0x00)) return ((IPP2P_EDK * 100) + 63);
+ break;
+ /* e4 52 .. | size = 44 */
+ case 0x52: if (packet_len == 44 ) return ((IPP2P_EDK * 100) + 64);
+ break;
+ /* e4 58 .. | size == 6 */
+ case 0x58: if (packet_len == 14 ) return ((IPP2P_EDK * 100) + 65);
+ break;
+ /* e4 59 .. | size == 2 */
+ case 0x59: if (packet_len == 10 )return ((IPP2P_EDK * 100) + 66);
+ break;
+ /* e4 28 .. | packet_len == 52,77,102,127... */
+ case 0x28: if (((packet_len-52) % 25) == 0) return ((IPP2P_EDK * 100) + 67);
+ break;
+ /* e4 50 xx xx | size == 4 */
+ case 0x50: if (packet_len == 12) return ((IPP2P_EDK * 100) + 68);
+ break;
+ /* e4 40 xx xx | size == 48 */
+ case 0x40: if (packet_len == 56) return ((IPP2P_EDK * 100) + 69);
+ break;
+ }
+ break;
+ }
+ } /* end of switch (t[0]) */
+ return 0;
+}/*udp_search_edk*/
+
+
+/*Search for UDP Gnutella commands*/
+int
+udp_search_gnu (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+ t += 8;
+
+ if (memcmp(t, "GND", 3) == 0) return ((IPP2P_GNU * 100) + 51);
+ if (memcmp(t, "GNUTELLA ", 9) == 0) return ((IPP2P_GNU * 100) + 52);
+ return 0;
+}/*udp_search_gnu*/
+
+
+/*Search for UDP KaZaA commands*/
+int
+udp_search_kazaa (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+
+ if (t[packet_len-1] == 0x00){
+ t += (packet_len - 6);
+ if (memcmp(t, "KaZaA", 5) == 0) return (IPP2P_KAZAA * 100 +50);
+ }
+
+ return 0;
+}/*udp_search_kazaa*/
+
+/*Search for UDP DirectConnect commands*/
+int
+udp_search_directconnect (unsigned char *haystack, int packet_len)
+{
+ unsigned char *t = haystack;
+ if ((*(t + 8) == 0x24) && (*(t + packet_len - 1) == 0x7c)) {
+ t+=8;
+ if (memcmp(t, "SR ", 3) == 0) return ((IPP2P_DC * 100) + 60);
+ if (memcmp(t, "Ping ", 5) == 0) return ((IPP2P_DC * 100) + 61);
+ }
+ return 0;
+}/*udp_search_directconnect*/
+
+
+
+/*Search for UDP BitTorrent commands*/
+int
+udp_search_bit (unsigned char *haystack, int packet_len)
+{
+ switch(packet_len)
+ {
+ case 24:
+ /* ^ 00 00 04 17 27 10 19 80 */
+ if ((ntohl(get_u32(haystack, 8)) == 0x00000417) && (ntohl(get_u32(haystack, 12)) == 0x27101980))
+ return (IPP2P_BIT * 100 + 50);
+ break;
+ case 44:
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000400) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
+ return (IPP2P_BIT * 100 + 51);
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000400))
+ return (IPP2P_BIT * 100 + 61);
+ break;
+ case 65:
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000404) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
+ return (IPP2P_BIT * 100 + 52);
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000404))
+ return (IPP2P_BIT * 100 + 62);
+ break;
+ case 67:
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000406) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
+ return (IPP2P_BIT * 100 + 53);
+ if (get_u32(haystack, 16) == __constant_htonl(0x00000406))
+ return (IPP2P_BIT * 100 + 63);
+ break;
+ case 211:
+ if (get_u32(haystack, 8) == __constant_htonl(0x00000405))
+ return (IPP2P_BIT * 100 + 54);
+ break;
+ case 29:
+ if ((get_u32(haystack, 8) == __constant_htonl(0x00000401)))
+ return (IPP2P_BIT * 100 + 55);
+ break;
+ case 52:
+ if (get_u32(haystack,8) == __constant_htonl(0x00000827) &&
+ get_u32(haystack,12) == __constant_htonl(0x37502950))
+ return (IPP2P_BIT * 100 + 80);
+ break;
+ default:
+ /* this packet does not have a constant size */
+ if (packet_len >= 40 && get_u32(haystack, 16) == __constant_htonl(0x00000402) && get_u32(haystack, 36) == __constant_htonl(0x00000104))
+ return (IPP2P_BIT * 100 + 56);
+ break;
+ }
+
+ /* some extra-bitcomet rules:
+ * "d1:" [a|r] "d2:id20:"
+ */
+ if (packet_len > 30 && get_u8(haystack, 8) == 'd' && get_u8(haystack, 9) == '1' && get_u8(haystack, 10) == ':' )
+ {
+ if (get_u8(haystack, 11) == 'a' || get_u8(haystack, 11) == 'r')
+ {
+ if (memcmp(haystack+12,"d2:id20:",8)==0)
+ return (IPP2P_BIT * 100 + 57);
+ }
+ }
+
+#if 0
+ /* bitlord rules */
+ /* packetlen must be bigger than 40 */
+ /* first 4 bytes are zero */
+ if (packet_len > 40 && get_u32(haystack, 8) == 0x00000000)
+ {
+ /* first rule: 00 00 00 00 01 00 00 xx xx xx xx 00 00 00 00*/
+ if (get_u32(haystack, 12) == 0x00000000 &&
+ get_u32(haystack, 16) == 0x00010000 &&
+ get_u32(haystack, 24) == 0x00000000 )
+ return (IPP2P_BIT * 100 + 71);
+
+ /* 00 01 00 00 0d 00 00 xx xx xx xx 00 00 00 00*/
+ if (get_u32(haystack, 12) == 0x00000001 &&
+ get_u32(haystack, 16) == 0x000d0000 &&
+ get_u32(haystack, 24) == 0x00000000 )
+ return (IPP2P_BIT * 100 + 71);
+
+
+ }
+#endif
+
+ return 0;
+}/*udp_search_bit*/
+
+
+
+/*Search for Ares commands*/
+//#define IPP2P_DEBUG_ARES
+int
+search_ares (const unsigned char *payload, const u16 plen)
+//int search_ares (unsigned char *haystack, int packet_len, int head_len)
+{
+// const unsigned char *t = haystack + head_len;
+
+ /* all ares packets start with */
+ if (payload[1] == 0 && (plen - payload[0]) == 3)
+ {
+ switch (payload[2])
+ {
+ case 0x5a:
+ /* ares connect */
+ if ( plen == 6 && payload[5] == 0x05 ) return ((IPP2P_ARES * 100) + 1);
+ break;
+ case 0x09:
+ /* ares search, min 3 chars --> 14 bytes
+ * lets define a search can be up to 30 chars --> max 34 bytes
+ */
+ if ( plen >= 14 && plen <= 34 ) return ((IPP2P_ARES * 100) + 1);
+ break;
+#ifdef IPP2P_DEBUG_ARES
+ default:
+ printk(KERN_DEBUG "Unknown Ares command %x recognized, len: %u \n", (unsigned int) payload[2],plen);
+#endif /* IPP2P_DEBUG_ARES */
+ }
+ }
+
+#if 0
+ /* found connect packet: 03 00 5a 04 03 05 */
+ /* new version ares 1.8: 03 00 5a xx xx 05 */
+ if ((plen) == 6){ /* possible connect command*/
+ if ((payload[0] == 0x03) && (payload[1] == 0x00) && (payload[2] == 0x5a) && (payload[5] == 0x05))
+ return ((IPP2P_ARES * 100) + 1);
+ }
+ if ((plen) == 60){ /* possible download command*/
+ if ((payload[59] == 0x0a) && (payload[58] == 0x0a)){
+ if (memcmp(t, "PUSH SHA1:", 10) == 0) /* found download command */
+ return ((IPP2P_ARES * 100) + 2);
+ }
+ }
+#endif
+
+ return 0;
+} /*search_ares*/
+
+/*Search for SoulSeek commands*/
+int
+search_soul (const unsigned char *payload, const u16 plen)
+{
+//#define IPP2P_DEBUG_SOUL
+ /* match: xx xx xx xx | xx = sizeof(payload) - 4 */
+ if (get_u32(payload, 0) == (plen - 4)){
+ const __u32 m=get_u32(payload, 4);
+ /* match 00 yy yy 00, yy can be everything */
+ if ( get_u8(payload, 4) == 0x00 && get_u8(payload, 7) == 0x00 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "0: Soulseek command 0x%x recognized\n",get_u32(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 1);
+ }
+
+ /* next match: 01 yy 00 00 | yy can be everything */
+ if ( get_u8(payload, 4) == 0x01 && get_u16(payload, 6) == 0x0000 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "1: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 2);
+ }
+
+ /* other soulseek commandos are: 1-5,7,9,13-18,22,23,26,28,35-37,40-46,50,51,60,62-69,91,92,1001 */
+ /* try to do this in an intelligent way */
+ /* get all small commandos */
+ switch(m)
+ {
+ case 7:
+ case 9:
+ case 22:
+ case 23:
+ case 26:
+ case 28:
+ case 50:
+ case 51:
+ case 60:
+ case 91:
+ case 92:
+ case 1001:
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "2: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 3);
+ }
+
+ if (m > 0 && m < 6 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "3: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 4);
+ }
+ if (m > 12 && m < 19 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "4: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 5);
+ }
+
+ if (m > 34 && m < 38 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "5: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 6);
+ }
+
+ if (m > 39 && m < 47 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "6: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 7);
+ }
+
+ if (m > 61 && m < 70 )
+ {
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "7: Soulseek command 0x%x recognized\n",get_u16(payload, 4));
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 8);
+ }
+
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "unknown SOULSEEK command: 0x%x, first 16 bit: 0x%x, first 8 bit: 0x%x ,soulseek ???\n",get_u32(payload, 4),get_u16(payload, 4) >> 16,get_u8(payload, 4) >> 24);
+#endif /* IPP2P_DEBUG_SOUL */
+ }
+
+ /* match 14 00 00 00 01 yy 00 00 00 STRING(YY) 01 00 00 00 00 46|50 00 00 00 00 */
+ /* without size at the beginning !!! */
+ if ( get_u32(payload, 0) == 0x14 && get_u8(payload, 4) == 0x01 )
+ {
+ __u32 y=get_u32(payload, 5);
+ /* we need 19 chars + string */
+ if ( (y + 19) <= (plen) )
+ {
+ const unsigned char *w=payload+9+y;
+ if (get_u32(w, 0) == 0x01 && ( get_u16(w, 4) == 0x4600 || get_u16(w, 4) == 0x5000) && get_u32(w, 6) == 0x00);
+#ifdef IPP2P_DEBUG_SOUL
+ printk(KERN_DEBUG "Soulssek special client command recognized\n");
+#endif /* IPP2P_DEBUG_SOUL */
+ return ((IPP2P_SOUL * 100) + 9);
+ }
+ }
+ return 0;
+}
+
+
+/*Search for WinMX commands*/
+int
+search_winmx (const unsigned char *payload, const u16 plen)
+{
+//#define IPP2P_DEBUG_WINMX
+ if (((plen) == 4) && (memcmp(payload, "SEND", 4) == 0)) return ((IPP2P_WINMX * 100) + 1);
+ if (((plen) == 3) && (memcmp(payload, "GET", 3) == 0)) return ((IPP2P_WINMX * 100) + 2);
+ //if (packet_len < (head_len + 10)) return 0;
+ if (plen < 10) return 0;
+
+ if ((memcmp(payload, "SEND", 4) == 0) || (memcmp(payload, "GET", 3) == 0)){
+ u16 c=4;
+ const u16 end=plen-2;
+ u8 count=0;
+ while (c < end)
+ {
+ if (payload[c]== 0x20 && payload[c+1] == 0x22)
+ {
+ c++;
+ count++;
+ if (count>=2) return ((IPP2P_WINMX * 100) + 3);
+ }
+ c++;
+ }
+ }
+
+ if ( plen == 149 && payload[0] == '8' )
+ {
+#ifdef IPP2P_DEBUG_WINMX
+ printk(KERN_INFO "maybe WinMX\n");
+#endif
+ if (get_u32(payload,17) == 0 && get_u32(payload,21) == 0 && get_u32(payload,25) == 0 &&
+// get_u32(payload,33) == __constant_htonl(0x71182b1a) && get_u32(payload,37) == __constant_htonl(0x05050000) &&
+// get_u32(payload,133) == __constant_htonl(0x31097edf) && get_u32(payload,145) == __constant_htonl(0xdcb8f792))
+ get_u16(payload,39) == 0 && get_u16(payload,135) == __constant_htons(0x7edf) && get_u16(payload,147) == __constant_htons(0xf792))
+
+ {
+#ifdef IPP2P_DEBUG_WINMX
+ printk(KERN_INFO "got WinMX\n");
+#endif
+ return ((IPP2P_WINMX * 100) + 4);
+ }
+ }
+ return 0;
+} /*search_winmx*/
+
+
+/*Search for appleJuice commands*/
+int
+search_apple (const unsigned char *payload, const u16 plen)
+{
+ if ( (plen > 7) && (payload[6] == 0x0d) && (payload[7] == 0x0a) && (memcmp(payload, "ajprot", 6) == 0)) return (IPP2P_APPLE * 100);
+
+ return 0;
+}
+
+
+/*Search for BitTorrent commands*/
+int
+search_bittorrent (const unsigned char *payload, const u16 plen)
+{
+ if (plen > 20)
+ {
+ /* test for match 0x13+"BitTorrent protocol" */
+ if (payload[0] == 0x13)
+ {
+ if (memcmp(payload+1, "BitTorrent protocol", 19) == 0) return (IPP2P_BIT * 100);
+ }
+
+ /* get tracker commandos, all starts with GET /
+ * then it can follow: scrape| announce
+ * and then ?hash_info=
+ */
+ if (memcmp(payload,"GET /",5) == 0)
+ {
+ /* message scrape */
+ if ( memcmp(payload+5,"scrape?info_hash=",17)==0 ) return (IPP2P_BIT * 100 + 1);
+ /* message announce */
+ if ( memcmp(payload+5,"announce?info_hash=",19)==0 ) return (IPP2P_BIT * 100 + 2);
+ }
+ }
+ else
+ {
+ /* bitcomet encryptes the first packet, so we have to detect another
+ * one later in the flow */
+ /* first try failed, too many missdetections */
+ //if ( size == 5 && get_u32(t,0) == __constant_htonl(1) && t[4] < 3) return (IPP2P_BIT * 100 + 3);
+
+ /* second try: block request packets */
+ if ( plen == 17 && get_u32(payload,0) == __constant_htonl(0x0d) && payload[4] == 0x06 && get_u32(payload,13) == __constant_htonl(0x4000) ) return (IPP2P_BIT * 100 + 3);
+ }
+
+ return 0;
+}
+
+
+
+/*check for Kazaa get command*/
+int
+search_kazaa (const unsigned char *payload, const u16 plen)
+
+{
+ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a) && memcmp(payload, "GET /.hash=", 11) == 0)
+ return (IPP2P_DATA_KAZAA * 100);
+
+ return 0;
+}
+
+
+/*check for gnutella get command*/
+int
+search_gnu (const unsigned char *payload, const u16 plen)
+{
+ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
+ {
+ if (memcmp(payload, "GET /get/", 9) == 0) return ((IPP2P_DATA_GNU * 100) + 1);
+ if (memcmp(payload, "GET /uri-res/", 13) == 0) return ((IPP2P_DATA_GNU * 100) + 2);
+ }
+ return 0;
+}
+
+
+/*check for gnutella get commands and other typical data*/
+int
+search_all_gnu (const unsigned char *payload, const u16 plen)
+{
+
+ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
+ {
+
+ if (memcmp(payload, "GNUTELLA CONNECT/", 17) == 0) return ((IPP2P_GNU * 100) + 1);
+ if (memcmp(payload, "GNUTELLA/", 9) == 0) return ((IPP2P_GNU * 100) + 2);
+
+
+ if ((memcmp(payload, "GET /get/", 9) == 0) || (memcmp(payload, "GET /uri-res/", 13) == 0))
+ {
+ u16 c=8;
+ const u16 end=plen-22;
+ while (c < end) {
+ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Gnutella-", 11) == 0) || (memcmp(&payload[c+2], "X-Queue:", 8) == 0)))
+ return ((IPP2P_GNU * 100) + 3);
+ c++;
+ }
+ }
+ }
+ return 0;
+}
+
+
+/*check for KaZaA download commands and other typical data*/
+int
+search_all_kazaa (const unsigned char *payload, const u16 plen)
+{
+ if ((payload[plen-2] == 0x0d) && (payload[plen-1] == 0x0a))
+ {
+
+ if (memcmp(payload, "GIVE ", 5) == 0) return ((IPP2P_KAZAA * 100) + 1);
+
+ if (memcmp(payload, "GET /", 5) == 0) {
+ u16 c = 8;
+ const u16 end=plen-22;
+ while (c < end) {
+ if ( payload[c] == 0x0a && payload[c+1] == 0x0d && ((memcmp(&payload[c+2], "X-Kazaa-Username: ", 18) == 0) || (memcmp(&payload[c+2], "User-Agent: PeerEnabler/", 24) == 0)))
+ return ((IPP2P_KAZAA * 100) + 2);
+ c++;
+ }
+ }
+ }
+ return 0;
+}
+
+/*fast check for edonkey file segment transfer command*/
+int
+search_edk (const unsigned char *payload, const u16 plen)
+{
+ if (payload[0] != 0xe3)
+ return 0;
+ else {
+ if (payload[5] == 0x47)
+ return (IPP2P_DATA_EDK * 100);
+ else
+ return 0;
+ }
+}
+
+
+
+/*intensive but slower search for some edonkey packets including size-check*/
+int
+search_all_edk (const unsigned char *payload, const u16 plen)
+{
+ if (payload[0] != 0xe3)
+ return 0;
+ else {
+ //t += head_len;
+ const u16 cmd = get_u16(payload, 1);
+ if (cmd == (plen - 5)) {
+ switch (payload[5]) {
+ case 0x01: return ((IPP2P_EDK * 100) + 1); /*Client: hello or Server:hello*/
+ case 0x4c: return ((IPP2P_EDK * 100) + 9); /*Client: Hello-Answer*/
+ }
+ }
+ return 0;
+ }
+}
+
+
+/*fast check for Direct Connect send command*/
+int
+search_dc (const unsigned char *payload, const u16 plen)
+{
+
+ if (payload[0] != 0x24 )
+ return 0;
+ else {
+ if (memcmp(&payload[1], "Send|", 5) == 0)
+ return (IPP2P_DATA_DC * 100);
+ else
+ return 0;
+ }
+
+}
+
+
+/*intensive but slower check for all direct connect packets*/
+int
+search_all_dc (const unsigned char *payload, const u16 plen)
+{
+// unsigned char *t = haystack;
+
+ if (payload[0] == 0x24 && payload[plen-1] == 0x7c)
+ {
+ const unsigned char *t=&payload[1];
+ /* Client-Hub-Protocol */
+ if (memcmp(t, "Lock ", 5) == 0) return ((IPP2P_DC * 100) + 1);
+ /* Client-Client-Protocol, some are already recognized by client-hub (like lock) */
+ if (memcmp(t, "MyNick ", 7) == 0) return ((IPP2P_DC * 100) + 38);
+ }
+ return 0;
+}
+
+/*check for mute*/
+int
+search_mute (const unsigned char *payload, const u16 plen)
+{
+ if ( plen == 209 || plen == 345 || plen == 473 || plen == 609 || plen == 1121 )
+ {
+ //printk(KERN_DEBUG "size hit: %u",size);
+ if (memcmp(payload,"PublicKey: ",11) == 0 )
+ {
+ return ((IPP2P_MUTE * 100) + 0);
+
+/* if (memcmp(t+size-14,"\x0aEndPublicKey\x0a",14) == 0)
+ {
+ printk(KERN_DEBUG "end pubic key hit: %u",size);
+
+ }*/
+ }
+ }
+ return 0;
+}
+
+
+/* check for xdcc */
+int
+search_xdcc (const unsigned char *payload, const u16 plen)
+{
+ /* search in small packets only */
+ if (plen > 20 && plen < 200 && payload[plen-1] == 0x0a && payload[plen-2] == 0x0d && memcmp(payload,"PRIVMSG ",8) == 0)
+ {
+
+ u16 x=10;
+ const u16 end=plen - 13;
+
+ /* is seems to be a irc private massage, chedck for xdcc command */
+ while (x < end)
+ {
+ if (payload[x] == ':')
+ {
+ if ( memcmp(&payload[x+1],"xdcc send #",11) == 0 )
+ return ((IPP2P_XDCC * 100) + 0);
+ }
+ x++;
+ }
+ }
+ return 0;
+}
+
+/* search for waste */
+int search_waste(const unsigned char *payload, const u16 plen)
+{
+ if ( plen >= 8 && memcmp(payload,"GET.sha1:",9) == 0)
+ return ((IPP2P_WASTE * 100) + 0);
+
+ return 0;
+}
+
+
+static struct {
+ int command;
+ __u8 short_hand; /*for fucntions included in short hands*/
+ int packet_len;
+ int (*function_name) (const unsigned char *, const u16);
+} matchlist[] = {
+ {IPP2P_EDK,SHORT_HAND_IPP2P,20, &search_all_edk},
+// {IPP2P_DATA_KAZAA,SHORT_HAND_DATA,200, &search_kazaa},
+// {IPP2P_DATA_EDK,SHORT_HAND_DATA,60, &search_edk},
+// {IPP2P_DATA_DC,SHORT_HAND_DATA,26, &search_dc},
+ {IPP2P_DC,SHORT_HAND_IPP2P,5, search_all_dc},
+// {IPP2P_DATA_GNU,SHORT_HAND_DATA,40, &search_gnu},
+ {IPP2P_GNU,SHORT_HAND_IPP2P,5, &search_all_gnu},
+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,5, &search_all_kazaa},
+ {IPP2P_BIT,SHORT_HAND_IPP2P,20, &search_bittorrent},
+ {IPP2P_APPLE,SHORT_HAND_IPP2P,5, &search_apple},
+ {IPP2P_SOUL,SHORT_HAND_IPP2P,5, &search_soul},
+ {IPP2P_WINMX,SHORT_HAND_IPP2P,2, &search_winmx},
+ {IPP2P_ARES,SHORT_HAND_IPP2P,5, &search_ares},
+ {IPP2P_MUTE,SHORT_HAND_NONE,200, &search_mute},
+ {IPP2P_WASTE,SHORT_HAND_NONE,5, &search_waste},
+ {IPP2P_XDCC,SHORT_HAND_NONE,5, &search_xdcc},
+ {0,0,0,NULL}
+};
+
+
+static struct {
+ int command;
+ __u8 short_hand; /*for fucntions included in short hands*/
+ int packet_len;
+ int (*function_name) (unsigned char *, int);
+} udp_list[] = {
+ {IPP2P_KAZAA,SHORT_HAND_IPP2P,14, &udp_search_kazaa},
+ {IPP2P_BIT,SHORT_HAND_IPP2P,23, &udp_search_bit},
+ {IPP2P_GNU,SHORT_HAND_IPP2P,11, &udp_search_gnu},
+ {IPP2P_EDK,SHORT_HAND_IPP2P,9, &udp_search_edk},
+ {IPP2P_DC,SHORT_HAND_IPP2P,12, &udp_search_directconnect},
+ {0,0,0,NULL}
+};
+
+
+static bool
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
+{
+ const struct ipt_p2p_info *info = matchinfo;
+ unsigned char *haystack;
+ struct iphdr *ip = ip_hdr(skb);
+ int p2p_result = 0, i = 0;
+// int head_len;
+ int hlen = ntohs(ip->tot_len)-(ip->ihl*4); /*hlen = packet-data length*/
+
+ /*must not be a fragment*/
+ if (offset) {
+ if (info->debug) printk("IPP2P.match: offset found %i \n",offset);
+ return 0;
+ }
+
+ /*make sure that skb is linear*/
+ if(skb_is_nonlinear(skb)){
+ if (info->debug) printk("IPP2P.match: nonlinear skb found\n");
+ return 0;
+ }
+
+
+ haystack=(char *)ip+(ip->ihl*4); /*haystack = packet data*/
+
+ switch (ip->protocol){
+ case IPPROTO_TCP: /*what to do with a TCP packet*/
+ {
+ struct tcphdr *tcph = (void *) ip + ip->ihl * 4;
+
+ if (tcph->fin) return 0; /*if FIN bit is set bail out*/
+ if (tcph->syn) return 0; /*if SYN bit is set bail out*/
+ if (tcph->rst) return 0; /*if RST bit is set bail out*/
+
+ haystack += tcph->doff * 4; /*get TCP-Header-Size*/
+ hlen -= tcph->doff * 4;
+ while (matchlist[i].command) {
+ if ((((info->cmd & matchlist[i].command) == matchlist[i].command) ||
+ ((info->cmd & matchlist[i].short_hand) == matchlist[i].short_hand)) &&
+ (hlen > matchlist[i].packet_len)) {
+ p2p_result = matchlist[i].function_name(haystack, hlen);
+ if (p2p_result)
+ {
+ if (info->debug) printk("IPP2P.debug:TCP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
+ p2p_result, NIPQUAD(ip->saddr),ntohs(tcph->source), NIPQUAD(ip->daddr),ntohs(tcph->dest),hlen);
+ return p2p_result;
+ }
+ }
+ i++;
+ }
+ return p2p_result;
+ }
+
+ case IPPROTO_UDP: /*what to do with an UDP packet*/
+ {
+ struct udphdr *udph = (void *) ip + ip->ihl * 4;
+
+ while (udp_list[i].command){
+ if ((((info->cmd & udp_list[i].command) == udp_list[i].command) ||
+ ((info->cmd & udp_list[i].short_hand) == udp_list[i].short_hand)) &&
+ (hlen > udp_list[i].packet_len)) {
+ p2p_result = udp_list[i].function_name(haystack, hlen);
+ if (p2p_result){
+ if (info->debug) printk("IPP2P.debug:UDP-match: %i from: %u.%u.%u.%u:%i to: %u.%u.%u.%u:%i Length: %i\n",
+ p2p_result, NIPQUAD(ip->saddr),ntohs(udph->source), NIPQUAD(ip->daddr),ntohs(udph->dest),hlen);
+ return p2p_result;
+ }
+ }
+ i++;
+ }
+ return p2p_result;
+ }
+
+ default: return 0;
+ }
+}
+
+
+
+static bool
+checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
+{
+ /* Must specify -p tcp */
+/* if (ip->proto != IPPROTO_TCP || (ip->invflags & IPT_INV_PROTO)) {
+ * printk("ipp2p: Only works on TCP packets, use -p tcp\n");
+ * return 0;
+ * }*/
+ return 1;
+}
+
+
+
+
+static struct ipt_match ipp2p_match = {
+ .name = "ipp2p",
+ .match = &match,
+ .family = AF_INET,
+ .matchsize = sizeof(struct ipt_p2p_info),
+ .checkentry = &checkentry,
+ .me = THIS_MODULE,
+};
+
+
+static int __init init(void)
+{
+ printk(KERN_INFO "IPP2P v%s loading\n", IPP2P_VERSION);
+ return xt_register_match(&ipp2p_match);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_match(&ipp2p_match);
+ printk(KERN_INFO "IPP2P v%s unloaded\n", IPP2P_VERSION);
+}
+
+module_init(init);
+module_exit(fini);
+
+
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -64,6 +64,12 @@ config IP_NF_IPTABLES
if IP_NF_IPTABLES
# The matches.
+config IP_NF_MATCH_IPP2P
+ tristate "IPP2P"
+ depends on NETFILTER_ADVANCED
+ help
+ Module for matching traffic of various Peer-to-Peer applications
+
config IP_NF_MATCH_ADDRTYPE
tristate '"addrtype" address type match support'
depends on NETFILTER_ADVANCED
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -53,6 +53,8 @@ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
+obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o
+
# targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,239 @@
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_time.h
@@ -0,0 +1,18 @@
+#ifndef __ipt_time_h_included__
+#define __ipt_time_h_included__
+
+
+struct ipt_time_info {
+ u_int8_t days_match; /* 1 bit per day. -SMTWTFS */
+ u_int16_t time_start; /* 0 < time_start < 23*60+59 = 1439 */
+ u_int16_t time_stop; /* 0:0 < time_stat < 23:59 */
+
+ /* FIXME: Keep this one for userspace iptables binary compability: */
+ u_int8_t kerneltime; /* ignore skb time (and use kerneltime) or not. */
+
+ time_t date_start;
+ time_t date_stop;
+};
+
+
+#endif /* __ipt_time_h_included__ */
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_time.c
@@ -0,0 +1,180 @@
+/*
+ This is a module which is used for time matching
+ It is using some modified code from dietlibc (localtime() function)
+ that you can find at http://www.fefe.de/dietlibc/
+ This file is distributed under the terms of the GNU General Public
+ License (GPL). Copies of the GPL can be obtained from: ftp://prep.ai.mit.edu/pub/gnu/GPL
+ 2001-05-04 Fabrice MARIE <fabrice@netfilter.org> : initial development.
+ 2001-21-05 Fabrice MARIE <fabrice@netfilter.org> : bug fix in the match code,
+ thanks to "Zeng Yu" <zengy@capitel.com.cn> for bug report.
+ 2001-26-09 Fabrice MARIE <fabrice@netfilter.org> : force the match to be in LOCAL_IN or PRE_ROUTING only.
+ 2001-30-11 Fabrice : added the possibility to use the match in FORWARD/OUTPUT with a little hack,
+ added Nguyen Dang Phuoc Dong <dongnd@tlnet.com.vn> patch to support timezones.
+ 2004-05-02 Fabrice : added support for date matching, from an idea of Fabien COELHO.
+*/
+
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_time.h>
+#include <linux/time.h>
+
+MODULE_AUTHOR("Fabrice MARIE <fabrice@netfilter.org>");
+MODULE_DESCRIPTION("Match arrival timestamp/date");
+MODULE_LICENSE("GPL");
+
+struct tm
+{
+ int tm_sec; /* Seconds. [0-60] (1 leap second) */
+ int tm_min; /* Minutes. [0-59] */
+ int tm_hour; /* Hours. [0-23] */
+ int tm_mday; /* Day. [1-31] */
+ int tm_mon; /* Month. [0-11] */
+ int tm_year; /* Year - 1900. */
+ int tm_wday; /* Day of week. [0-6] */
+ int tm_yday; /* Days in year.[0-365] */
+ int tm_isdst; /* DST. [-1/0/1]*/
+
+ long int tm_gmtoff; /* we don't care, we count from GMT */
+ const char *tm_zone; /* we don't care, we count from GMT */
+};
+
+void
+localtime(const u32 time, struct tm *r);
+
+static bool
+match(const struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ const struct xt_match *match,
+ const void *matchinfo,
+ int offset,
+ unsigned int protoff,
+ bool *hotdrop)
+{
+ const struct ipt_time_info *info = matchinfo; /* match info for rule */
+ struct timeval tv;
+ struct tm currenttime; /* time human readable */
+ u_int8_t days_of_week[7] = {64, 32, 16, 8, 4, 2, 1};
+ u_int16_t packet_time;
+
+ /* We might not have a timestamp, get one */
+ if (skb->tstamp.tv64 == 0)
+ __net_timestamp((struct sk_buff *)skb);
+
+ skb_get_timestamp(skb, &tv);
+ /* First we make sure we are in the date start-stop boundaries */
+ if ((tv.tv_sec < info->date_start) || (tv.tv_sec > info->date_stop))
+ return 0; /* We are outside the date boundaries */
+
+ /* Transform the timestamp of the packet, in a human readable form */
+ localtime(tv.tv_sec, &currenttime);
+
+ /* check if we match this timestamp, we start by the days... */
+ if ((days_of_week[currenttime.tm_wday] & info->days_match) != days_of_week[currenttime.tm_wday])
+ return 0; /* the day doesn't match */
+
+ /* ... check the time now */
+ packet_time = (currenttime.tm_hour * 60) + currenttime.tm_min;
+ if ((packet_time < info->time_start) || (packet_time > info->time_stop))
+ return 0;
+
+ /* here we match ! */
+ return 1;
+}
+
+static bool
+checkentry(const char *tablename,
+ const void *ip,
+ const struct xt_match *match,
+ void *matchinfo,
+ unsigned int hook_mask)
+{
+ struct ipt_time_info *info = matchinfo; /* match info for rule */
+
+ /* First, check that we are in the correct hooks */
+ if (hook_mask
+ & ~((1 << NF_INET_PRE_ROUTING) | (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) | (1 << NF_INET_LOCAL_OUT)))
+ {
+ printk("ipt_time: error, only valid for PRE_ROUTING, LOCAL_IN, FORWARD and OUTPUT)\n");
+ return 0;
+ }
+
+ /* Now check the coherence of the data ... */
+ if ((info->time_start > 1439) || /* 23*60+59 = 1439*/
+ (info->time_stop > 1439))
+ {
+ printk(KERN_WARNING "ipt_time: invalid argument\n");
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct ipt_match time_match = {
+ .name = "time",
+ .match = &match,
+ .matchsize = sizeof(struct ipt_time_info),
+ .checkentry = &checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ printk("ipt_time loading\n");
+ return xt_register_match(&time_match);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_match(&time_match);
+ printk("ipt_time unloaded\n");
+}
+
+module_init(init);
+module_exit(fini);
+
+
+/* The part below is borowed and modified from dietlibc */
+
+/* seconds per day */
+#define SPD 24*60*60
+
+void
+localtime(const u32 time, struct tm *r) {
+ u32 i, timep;
+ extern struct timezone sys_tz;
+ const unsigned int __spm[12] =
+ { 0,
+ (31),
+ (31+28),
+ (31+28+31),
+ (31+28+31+30),
+ (31+28+31+30+31),
+ (31+28+31+30+31+30),
+ (31+28+31+30+31+30+31),
+ (31+28+31+30+31+30+31+31),
+ (31+28+31+30+31+30+31+31+30),
+ (31+28+31+30+31+30+31+31+30+31),
+ (31+28+31+30+31+30+31+31+30+31+30),
+ };
+ register u32 work;
+
+ timep = time - (sys_tz.tz_minuteswest * 60);
+ work=timep%(SPD);
+ r->tm_sec=work%60; work/=60;
+ r->tm_min=work%60; r->tm_hour=work/60;
+ work=timep/(SPD);
+ r->tm_wday=(4+work)%7;
+ for (i=1970; ; ++i) {
+ register time_t k= (!(i%4) && ((i%100) || !(i%400)))?366:365;
+ if (work>k)
+ work-=k;
+ else
+ break;
+ }
+ r->tm_year=i-1900;
+ for (i=11; i && __spm[i]>work; --i) ;
+ r->tm_mon=i;
+ r->tm_mday=work-__spm[i]+1;
+}
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -70,6 +70,22 @@ config IP_NF_MATCH_IPP2P
help
Module for matching traffic of various Peer-to-Peer applications
+
+config IP_NF_MATCH_TIME
+ tristate 'TIME match support'
+ depends on NETFILTER_ADVANCED
+ help
+ This option adds a `time' match, which allows you
+ to match based on the packet arrival time/date
+ (arrival time/date at the machine which netfilter is running on) or
+ departure time/date (for locally generated packets).
+
+ If you say Y here, try iptables -m time --help for more information.
+ If you want to compile it as a module, say M here and read
+
+ Documentation/modules.txt. If unsure, say `N'.
+
+
config IP_NF_MATCH_ADDRTYPE
tristate '"addrtype" address type match support'
depends on NETFILTER_ADVANCED
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -53,6 +53,7 @@ obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
obj-$(CONFIG_IP_NF_MATCH_SET) += ipt_set.o
+obj-$(CONFIG_IP_NF_MATCH_TIME) += ipt_time.o
obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_ipp2p.o

View file

@ -0,0 +1,914 @@
--- /dev/null
+++ b/drivers/net/imq.c
@@ -0,0 +1,474 @@
+/*
+ * Pseudo-driver for the intermediate queue device.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Patrick McHardy, <kaber@trash.net>
+ *
+ * The first version was written by Martin Devera, <devik@cdi.cz>
+ *
+ * Credits: Jan Rafaj <imq2t@cedric.vabo.cz>
+ * - Update patch to 2.4.21
+ * Sebastian Strollo <sstrollo@nortelnetworks.com>
+ * - Fix "Dead-loop on netdevice imq"-issue
+ * Marcel Sebek <sebek64@post.cz>
+ * - Update to 2.6.2-rc1
+ *
+ * After some time of inactivity there is a group taking care
+ * of IMQ again: http://www.linuximq.net
+ *
+ *
+ * 2004/06/30 - New version of IMQ patch to kernels <=2.6.7
+ * including the following changes:
+ *
+ * - Correction of ipv6 support "+"s issue (Hasso Tepper)
+ * - Correction of imq_init_devs() issue that resulted in
+ * kernel OOPS unloading IMQ as module (Norbert Buchmuller)
+ * - Addition of functionality to choose number of IMQ devices
+ * during kernel config (Andre Correa)
+ * - Addition of functionality to choose how IMQ hooks on
+ * PRE and POSTROUTING (after or before NAT) (Andre Correa)
+ * - Cosmetic corrections (Norbert Buchmuller) (Andre Correa)
+ *
+ *
+ * 2005/12/16 - IMQ versions between 2.6.7 and 2.6.13 were
+ * released with almost no problems. 2.6.14-x was released
+ * with some important changes: nfcache was removed; After
+ * some weeks of trouble we figured out that some IMQ fields
+ * in skb were missing in skbuff.c - skb_clone and copy_skb_header.
+ * These functions are correctly patched by this new patch version.
+ *
+ * Thanks for all who helped to figure out all the problems with
+ * 2.6.14.x: Patrick McHardy, Rune Kock, VeNoMouS, Max CtRiX,
+ * Kevin Shanahan, Richard Lucassen, Valery Dachev (hopefully
+ * I didn't forget anybody). I apologize again for my lack of time.
+ *
+ *
+ * 2008/06/17 - 2.6.25 - Changed imq.c to use qdisc_run() instead
+ * of qdisc_restart() and moved qdisc_run() to tasklet to avoid
+ * recursive locking. New initialization routines to fix 'rmmod' not
+ * working anymore. Used code from ifb.c. (Jussi Kivilinna)
+ *
+ * Also, many thanks to pablo Sebastian Greco for making the initial
+ * patch and to those who helped the testing.
+ *
+ * More info at: http://www.linuximq.net/ (Andre Correa)
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/netdevice.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/netfilter.h>
+#include <linux/netfilter_ipv4.h>
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ #include <linux/netfilter_ipv6.h>
+#endif
+#include <linux/imq.h>
+#include <net/pkt_sched.h>
+#include <net/netfilter/nf_queue.h>
+
+struct imq_private {
+ struct tasklet_struct tasklet;
+ unsigned long tasklet_pending;
+};
+
+static nf_hookfn imq_nf_hook;
+
+static struct nf_hook_ops imq_ingress_ipv4 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_PRE_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ .priority = NF_IP_PRI_MANGLE + 1
+#else
+ .priority = NF_IP_PRI_NAT_DST + 1
+#endif
+};
+
+static struct nf_hook_ops imq_egress_ipv4 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET,
+ .hooknum = NF_INET_POST_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
+ .priority = NF_IP_PRI_LAST
+#else
+ .priority = NF_IP_PRI_NAT_SRC - 1
+#endif
+};
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+static struct nf_hook_ops imq_ingress_ipv6 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_PRE_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ .priority = NF_IP6_PRI_MANGLE + 1
+#else
+ .priority = NF_IP6_PRI_NAT_DST + 1
+#endif
+};
+
+static struct nf_hook_ops imq_egress_ipv6 = {
+ .hook = imq_nf_hook,
+ .owner = THIS_MODULE,
+ .pf = PF_INET6,
+ .hooknum = NF_INET_POST_ROUTING,
+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA)
+ .priority = NF_IP6_PRI_LAST
+#else
+ .priority = NF_IP6_PRI_NAT_SRC - 1
+#endif
+};
+#endif
+
+#if defined(CONFIG_IMQ_NUM_DEVS)
+static unsigned int numdevs = CONFIG_IMQ_NUM_DEVS;
+#else
+static unsigned int numdevs = IMQ_MAX_DEVS;
+#endif
+
+static struct net_device *imq_devs_cache[IMQ_MAX_DEVS];
+
+static struct net_device_stats *imq_get_stats(struct net_device *dev)
+{
+ return &dev->stats;
+}
+
+/* called for packets kfree'd in qdiscs at places other than enqueue */
+static void imq_skb_destructor(struct sk_buff *skb)
+{
+ struct nf_queue_entry *entry = skb->nf_queue_entry;
+
+ if (entry) {
+ if (entry->indev)
+ dev_put(entry->indev);
+ if (entry->outdev)
+ dev_put(entry->outdev);
+ kfree(entry);
+ }
+}
+
+static int imq_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ dev->stats.tx_bytes += skb->len;
+ dev->stats.tx_packets++;
+
+ skb->imq_flags = 0;
+ skb->destructor = NULL;
+
+ dev->trans_start = jiffies;
+ nf_reinject(skb->nf_queue_entry, NF_ACCEPT);
+ return 0;
+}
+
+static int imq_nf_queue(struct nf_queue_entry *entry, unsigned queue_num)
+{
+ struct net_device *dev;
+ struct imq_private *priv;
+ struct sk_buff *skb2 = NULL;
+ struct Qdisc *q;
+ unsigned int index = entry->skb->imq_flags & IMQ_F_IFMASK;
+ int ret = -1;
+
+ if (index > numdevs)
+ return -1;
+
+ /* check for imq device by index from cache */
+ dev = imq_devs_cache[index];
+ if (!dev) {
+ char buf[8];
+
+ /* get device by name and cache result */
+ snprintf(buf, sizeof(buf), "imq%d", index);
+ dev = dev_get_by_name(&init_net, buf);
+ if (!dev) {
+ /* not found ?!*/
+ BUG();
+ return -1;
+ }
+
+ imq_devs_cache[index] = dev;
+ }
+
+ priv = netdev_priv(dev);
+ if (!(dev->flags & IFF_UP)) {
+ entry->skb->imq_flags = 0;
+ nf_reinject(entry, NF_ACCEPT);
+ return 0;
+ }
+ dev->last_rx = jiffies;
+
+ if (entry->skb->destructor) {
+ skb2 = entry->skb;
+ entry->skb = skb_clone(entry->skb, GFP_ATOMIC);
+ if (!entry->skb)
+ return -1;
+ }
+ entry->skb->nf_queue_entry = entry;
+
+ dev->stats.rx_bytes += entry->skb->len;
+ dev->stats.rx_packets++;
+
+ spin_lock_bh(&dev->queue_lock);
+ q = dev->qdisc;
+ if (q->enqueue) {
+ q->enqueue(skb_get(entry->skb), q);
+ if (skb_shared(entry->skb)) {
+ entry->skb->destructor = imq_skb_destructor;
+ kfree_skb(entry->skb);
+ ret = 0;
+ }
+ }
+ if (!test_and_set_bit(1, &priv->tasklet_pending))
+ tasklet_schedule(&priv->tasklet);
+ spin_unlock_bh(&dev->queue_lock);
+
+ if (skb2)
+ kfree_skb(ret ? entry->skb : skb2);
+
+ return ret;
+}
+
+static struct nf_queue_handler nfqh = {
+ .name = "imq",
+ .outfn = imq_nf_queue,
+};
+
+static void qdisc_run_tasklet(unsigned long arg)
+{
+ struct net_device *dev = (struct net_device *)arg;
+ struct imq_private *priv = netdev_priv(dev);
+
+ spin_lock(&dev->queue_lock);
+ qdisc_run(dev);
+ clear_bit(1, &priv->tasklet_pending);
+ spin_unlock(&dev->queue_lock);
+}
+
+static unsigned int imq_nf_hook(unsigned int hook, struct sk_buff *pskb,
+ const struct net_device *indev,
+ const struct net_device *outdev,
+ int (*okfn)(struct sk_buff *))
+{
+ if (pskb->imq_flags & IMQ_F_ENQUEUE)
+ return NF_QUEUE;
+
+ return NF_ACCEPT;
+}
+
+static int imq_close(struct net_device *dev)
+{
+ struct imq_private *priv = netdev_priv(dev);
+
+ tasklet_kill(&priv->tasklet);
+ netif_stop_queue(dev);
+
+ return 0;
+}
+
+static int imq_open(struct net_device *dev)
+{
+ struct imq_private *priv = netdev_priv(dev);
+
+ tasklet_init(&priv->tasklet, qdisc_run_tasklet, (unsigned long)dev);
+ netif_start_queue(dev);
+
+ return 0;
+}
+
+static void imq_setup(struct net_device *dev)
+{
+ dev->hard_start_xmit = imq_dev_xmit;
+ dev->open = imq_open;
+ dev->get_stats = imq_get_stats;
+ dev->stop = imq_close;
+ dev->type = ARPHRD_VOID;
+ dev->mtu = 16000;
+ dev->tx_queue_len = 11000;
+ dev->flags = IFF_NOARP;
+}
+
+static struct rtnl_link_ops imq_link_ops __read_mostly = {
+ .kind = "imq",
+ .priv_size = sizeof(struct imq_private),
+ .setup = imq_setup,
+};
+
+static int __init imq_init_hooks(void)
+{
+ int err;
+
+ err = nf_register_queue_handler(PF_INET, &nfqh);
+ if (err)
+ goto err1;
+
+ err = nf_register_hook(&imq_ingress_ipv4);
+ if (err)
+ goto err2;
+
+ err = nf_register_hook(&imq_egress_ipv4);
+ if (err)
+ goto err3;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ err = nf_register_queue_handler(PF_INET6, &nfqh);
+ if (err)
+ goto err4;
+
+ err = nf_register_hook(&imq_ingress_ipv6);
+ if (err)
+ goto err5;
+
+ err = nf_register_hook(&imq_egress_ipv6);
+ if (err)
+ goto err6;
+#endif
+
+ return 0;
+
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+err6:
+ nf_unregister_hook(&imq_ingress_ipv6);
+err5:
+ nf_unregister_queue_handler(PF_INET6, &nfqh);
+err4:
+ nf_unregister_hook(&imq_egress_ipv4);
+#endif
+err3:
+ nf_unregister_hook(&imq_ingress_ipv4);
+err2:
+ nf_unregister_queue_handler(PF_INET, &nfqh);
+err1:
+ return err;
+}
+
+static int __init imq_init_one(int index)
+{
+ struct net_device *dev;
+ int ret;
+
+ dev = alloc_netdev(sizeof(struct imq_private), "imq%d", imq_setup);
+ if (!dev)
+ return -ENOMEM;
+
+ ret = dev_alloc_name(dev, dev->name);
+ if (ret < 0)
+ goto fail;
+
+ dev->rtnl_link_ops = &imq_link_ops;
+ ret = register_netdevice(dev);
+ if (ret < 0)
+ goto fail;
+
+ return 0;
+fail:
+ free_netdev(dev);
+ return ret;
+}
+
+static int __init imq_init_devs(void)
+{
+ int err, i;
+
+ if (!numdevs || numdevs > IMQ_MAX_DEVS) {
+ printk(KERN_ERR "IMQ: numdevs has to be betweed 1 and %u\n",
+ IMQ_MAX_DEVS);
+ return -EINVAL;
+ }
+
+ rtnl_lock();
+ err = __rtnl_link_register(&imq_link_ops);
+
+ for (i = 0; i < numdevs && !err; i++)
+ err = imq_init_one(i);
+
+ if (err) {
+ __rtnl_link_unregister(&imq_link_ops);
+ memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
+ }
+ rtnl_unlock();
+
+ return err;
+}
+
+static int __init imq_init_module(void)
+{
+ int err;
+
+ err = imq_init_devs();
+ if (err) {
+ printk(KERN_ERR "IMQ: Error trying imq_init_devs(net)\n");
+ return err;
+ }
+
+ err = imq_init_hooks();
+ if (err) {
+ printk(KERN_ERR "IMQ: Error trying imq_init_hooks()\n");
+ rtnl_link_unregister(&imq_link_ops);
+ memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
+ return err;
+ }
+
+ printk(KERN_INFO "IMQ driver loaded successfully.\n");
+
+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ printk(KERN_INFO "\tHooking IMQ before NAT on PREROUTING.\n");
+#else
+ printk(KERN_INFO "\tHooking IMQ after NAT on PREROUTING.\n");
+#endif
+#if defined(CONFIG_IMQ_BEHAVIOR_AB) || defined(CONFIG_IMQ_BEHAVIOR_BB)
+ printk(KERN_INFO "\tHooking IMQ before NAT on POSTROUTING.\n");
+#else
+ printk(KERN_INFO "\tHooking IMQ after NAT on POSTROUTING.\n");
+#endif
+
+ return 0;
+}
+
+static void __exit imq_unhook(void)
+{
+#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE)
+ nf_unregister_hook(&imq_ingress_ipv6);
+ nf_unregister_hook(&imq_egress_ipv6);
+ nf_unregister_queue_handler(PF_INET6, &nfqh);
+#endif
+ nf_unregister_hook(&imq_ingress_ipv4);
+ nf_unregister_hook(&imq_egress_ipv4);
+ nf_unregister_queue_handler(PF_INET, &nfqh);
+}
+
+static void __exit imq_cleanup_devs(void)
+{
+ rtnl_link_unregister(&imq_link_ops);
+ memset(imq_devs_cache, 0, sizeof(imq_devs_cache));
+}
+
+static void __exit imq_exit_module(void)
+{
+ imq_unhook();
+ imq_cleanup_devs();
+ printk(KERN_INFO "IMQ driver unloaded successfully.\n");
+}
+
+module_init(imq_init_module);
+module_exit(imq_exit_module);
+
+module_param(numdevs, int, 0);
+MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will "
+ "be created)");
+MODULE_AUTHOR("http://www.linuximq.net");
+MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See "
+ "http://www.linuximq.net/ for more information.");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS_RTNL_LINK("imq");
+
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -109,6 +109,129 @@ config EQUALIZER
To compile this driver as a module, choose M here: the module
will be called eql. If unsure, say N.
+config IMQ
+ tristate "IMQ (intermediate queueing device) support"
+ depends on NETDEVICES && NETFILTER
+ ---help---
+ The IMQ device(s) is used as placeholder for QoS queueing
+ disciplines. Every packet entering/leaving the IP stack can be
+ directed through the IMQ device where it's enqueued/dequeued to the
+ attached qdisc. This allows you to treat network devices as classes
+ and distribute bandwidth among them. Iptables is used to specify
+ through which IMQ device, if any, packets travel.
+
+ More information at: http://www.linuximq.net/
+
+ To compile this driver as a module, choose M here: the module
+ will be called imq. If unsure, say N.
+
+choice
+ prompt "IMQ behavior (PRE/POSTROUTING)"
+ depends on IMQ
+ default IMQ_BEHAVIOR_AB
+ help
+
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ IMQ can work in any of the following ways:
+
+ PREROUTING | POSTROUTING
+ -----------------|-------------------
+ #1 After NAT | After NAT
+ #2 After NAT | Before NAT
+ #3 Before NAT | After NAT
+ #4 Before NAT | Before NAT
+
+ The default behavior is to hook before NAT on PREROUTING
+ and after NAT on POSTROUTING (#3).
+
+ This settings are specially usefull when trying to use IMQ
+ to shape NATed clients.
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AA
+ bool "IMQ AA"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: After NAT
+ POSTROUTING: After NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_AB
+ bool "IMQ AB"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: After NAT
+ POSTROUTING: Before NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BA
+ bool "IMQ BA"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: Before NAT
+ POSTROUTING: After NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+config IMQ_BEHAVIOR_BB
+ bool "IMQ BB"
+ help
+ This settings defines how IMQ behaves in respect to its
+ hooking in PREROUTING and POSTROUTING.
+
+ Choosing this option will make IMQ hook like this:
+
+ PREROUTING: Before NAT
+ POSTROUTING: Before NAT
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
+endchoice
+
+config IMQ_NUM_DEVS
+
+ int "Number of IMQ devices"
+ range 2 16
+ depends on IMQ
+ default "16"
+ help
+
+ This settings defines how many IMQ devices will be
+ created.
+
+ The default value is 16.
+
+ More information can be found at: www.linuximq.net
+
+ If not sure leave the default settings alone.
+
config TUN
tristate "Universal TUN/TAP device driver support"
select CRC32
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -148,6 +148,7 @@ obj-$(CONFIG_SLHC) += slhc.o
obj-$(CONFIG_XEN_NETDEV_FRONTEND) += xen-netfront.o
obj-$(CONFIG_DUMMY) += dummy.o
+obj-$(CONFIG_IMQ) += imq.o
obj-$(CONFIG_IFB) += ifb.o
obj-$(CONFIG_MACVLAN) += macvlan.o
obj-$(CONFIG_DE600) += de600.o
--- /dev/null
+++ b/include/linux/imq.h
@@ -0,0 +1,9 @@
+#ifndef _IMQ_H
+#define _IMQ_H
+
+#define IMQ_MAX_DEVS 16
+
+#define IMQ_F_IFMASK 0x7f
+#define IMQ_F_ENQUEUE 0x80
+
+#endif /* _IMQ_H */
--- /dev/null
+++ b/include/linux/netfilter_ipv4/ipt_IMQ.h
@@ -0,0 +1,8 @@
+#ifndef _IPT_IMQ_H
+#define _IPT_IMQ_H
+
+struct ipt_imq_info {
+ unsigned int todev; /* target imq device */
+};
+
+#endif /* _IPT_IMQ_H */
--- /dev/null
+++ b/include/linux/netfilter_ipv6/ip6t_IMQ.h
@@ -0,0 +1,8 @@
+#ifndef _IP6T_IMQ_H
+#define _IP6T_IMQ_H
+
+struct ip6t_imq_info {
+ unsigned int todev; /* target imq device */
+};
+
+#endif /* _IP6T_IMQ_H */
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -308,6 +308,10 @@ struct sk_buff {
struct nf_conntrack *nfct;
struct sk_buff *nfct_reasm;
#endif
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ unsigned char imq_flags;
+ struct nf_queue_entry *nf_queue_entry;
+#endif
#ifdef CONFIG_BRIDGE_NETFILTER
struct nf_bridge_info *nf_bridge;
#endif
@@ -1813,6 +1817,10 @@ static inline void __nf_copy(struct sk_b
dst->nfct_reasm = src->nfct_reasm;
nf_conntrack_get_reasm(src->nfct_reasm);
#endif
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ dst->imq_flags = src->imq_flags;
+ dst->nf_queue_entry = src->nf_queue_entry;
+#endif
#ifdef CONFIG_BRIDGE_NETFILTER
dst->nf_bridge = src->nf_bridge;
nf_bridge_get(src->nf_bridge);
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -96,6 +96,9 @@
#include <net/net_namespace.h>
#include <net/sock.h>
#include <linux/rtnetlink.h>
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+#include <linux/imq.h>
+#endif
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/stat.h>
@@ -1655,7 +1658,11 @@ int dev_hard_start_xmit(struct sk_buff *
struct netdev_queue *txq)
{
if (likely(!skb->next)) {
- if (!list_empty(&ptype_all))
+ if (!list_empty(&ptype_all)
+#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE)
+ && !(skb->imq_flags & IMQ_F_ENQUEUE)
+#endif
+ )
dev_queue_xmit_nit(skb, dev);
if (netif_needs_gso(dev, skb)) {
--- /dev/null
+++ b/net/ipv4/netfilter/ipt_IMQ.c
@@ -0,0 +1,69 @@
+/*
+ * This target marks packets to be enqueued to an imq device
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+#include <linux/netfilter_ipv4/ipt_IMQ.h>
+#include <linux/imq.h>
+
+static unsigned int imq_target(struct sk_buff *pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ struct ipt_imq_info *mr = (struct ipt_imq_info *)targinfo;
+
+ pskb->imq_flags = mr->todev | IMQ_F_ENQUEUE;
+
+ return XT_CONTINUE;
+}
+
+static bool imq_checkentry(const char *tablename,
+ const void *e,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
+{
+ struct ipt_imq_info *mr;
+
+ mr = (struct ipt_imq_info *)targinfo;
+
+ if (mr->todev > IMQ_MAX_DEVS) {
+ printk(KERN_WARNING
+ "IMQ: invalid device specified, highest is %u\n",
+ IMQ_MAX_DEVS);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct xt_target ipt_imq_reg = {
+ .name = "IMQ",
+ .family = AF_INET,
+ .target = imq_target,
+ .targetsize = sizeof(struct ipt_imq_info),
+ .checkentry = imq_checkentry,
+ .me = THIS_MODULE,
+ .table = "mangle"
+};
+
+static int __init init(void)
+{
+ return xt_register_target(&ipt_imq_reg);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_target(&ipt_imq_reg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("http://www.linuximq.net");
+MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
+MODULE_LICENSE("GPL");
--- a/net/ipv4/netfilter/Kconfig
+++ b/net/ipv4/netfilter/Kconfig
@@ -134,6 +134,17 @@ config IP_NF_FILTER
To compile it as a module, choose M here. If unsure, say N.
+config IP_NF_TARGET_IMQ
+ tristate "IMQ target support"
+ depends on IP_NF_MANGLE && IMQ
+ help
+ This option adds a `IMQ' target which is used to specify if and
+ to which IMQ device packets should get enqueued/dequeued.
+
+ For more information visit: http://www.linuximq.net/
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP_NF_TARGET_REJECT
tristate "REJECT target support"
depends on IP_NF_FILTER
--- a/net/ipv4/netfilter/Makefile
+++ b/net/ipv4/netfilter/Makefile
@@ -61,6 +61,7 @@ obj-$(CONFIG_IP_NF_MATCH_IPP2P) += ipt_i
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
obj-$(CONFIG_IP_NF_TARGET_ECN) += ipt_ECN.o
obj-$(CONFIG_IP_NF_TARGET_LOG) += ipt_LOG.o
+obj-$(CONFIG_IP_NF_TARGET_IMQ) += ipt_IMQ.o
obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
--- /dev/null
+++ b/net/ipv6/netfilter/ip6t_IMQ.c
@@ -0,0 +1,69 @@
+/*
+ * This target marks packets to be enqueued to an imq device
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/netfilter_ipv6/ip6_tables.h>
+#include <linux/netfilter_ipv6/ip6t_IMQ.h>
+#include <linux/imq.h>
+
+static unsigned int imq_target(struct sk_buff *pskb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ struct ip6t_imq_info *mr = (struct ip6t_imq_info *)targinfo;
+
+ pskb->imq_flags = mr->todev | IMQ_F_ENQUEUE;
+
+ return XT_CONTINUE;
+}
+
+static bool imq_checkentry(const char *tablename,
+ const void *entry,
+ const struct xt_target *target,
+ void *targinfo,
+ unsigned int hook_mask)
+{
+ struct ip6t_imq_info *mr;
+
+ mr = (struct ip6t_imq_info *)targinfo;
+
+ if (mr->todev > IMQ_MAX_DEVS) {
+ printk(KERN_WARNING
+ "IMQ: invalid device specified, highest is %u\n",
+ IMQ_MAX_DEVS);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct xt_target ip6t_imq_reg = {
+ .name = "IMQ",
+ .family = AF_INET6,
+ .target = imq_target,
+ .targetsize = sizeof(struct ip6t_imq_info),
+ .table = "mangle",
+ .checkentry = imq_checkentry,
+ .me = THIS_MODULE
+};
+
+static int __init init(void)
+{
+ return xt_register_target(&ip6t_imq_reg);
+}
+
+static void __exit fini(void)
+{
+ xt_unregister_target(&ip6t_imq_reg);
+}
+
+module_init(init);
+module_exit(fini);
+
+MODULE_AUTHOR("http://www.linuximq.net");
+MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See http://www.linuximq.net/ for more information.");
+MODULE_LICENSE("GPL");
--- a/net/ipv6/netfilter/Kconfig
+++ b/net/ipv6/netfilter/Kconfig
@@ -170,6 +170,15 @@ config IP6_NF_MANGLE
To compile it as a module, choose M here. If unsure, say N.
+config IP6_NF_TARGET_IMQ
+ tristate "IMQ target support"
+ depends on IP6_NF_MANGLE && IMQ
+ help
+ This option adds a `IMQ' target which is used to specify if and
+ to which imq device packets should get enqueued/dequeued.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config IP6_NF_TARGET_HL
tristate 'HL (hoplimit) target support'
depends on IP6_NF_MANGLE
--- a/net/ipv6/netfilter/Makefile
+++ b/net/ipv6/netfilter/Makefile
@@ -6,6 +6,7 @@
obj-$(CONFIG_IP6_NF_IPTABLES) += ip6_tables.o
obj-$(CONFIG_IP6_NF_FILTER) += ip6table_filter.o
obj-$(CONFIG_IP6_NF_MANGLE) += ip6table_mangle.o
+obj-$(CONFIG_IP6_NF_TARGET_IMQ) += ip6t_IMQ.o
obj-$(CONFIG_IP6_NF_QUEUE) += ip6_queue.o
obj-$(CONFIG_IP6_NF_RAW) += ip6table_raw.o
obj-$(CONFIG_IP6_NF_SECURITY) += ip6table_security.o
--- a/net/sched/sch_generic.c
+++ b/net/sched/sch_generic.c
@@ -195,6 +195,7 @@ void __qdisc_run(struct Qdisc *q)
clear_bit(__QDISC_STATE_RUNNING, &q->state);
}
+EXPORT_SYMBOL(__qdisc_run);
static void dev_watchdog(unsigned long arg)
{

View file

@ -0,0 +1,857 @@
--- a/include/linux/netfilter/Kbuild
+++ b/include/linux/netfilter/Kbuild
@@ -3,6 +3,7 @@ header-y += nf_conntrack_tuple_common.h
header-y += nfnetlink_conntrack.h
header-y += nfnetlink_log.h
header-y += nfnetlink_queue.h
+header-y += xt_CHAOS.h
header-y += xt_CLASSIFY.h
header-y += xt_CONNMARK.h
header-y += xt_CONNSECMARK.h
--- /dev/null
+++ b/include/linux/netfilter/oot_conntrack.h
@@ -0,0 +1,5 @@
+#if defined(CONFIG_IP_NF_CONNTRACK) || defined(CONFIG_IP_NF_CONNTRACK_MODULE)
+# include <linux/netfilter_ipv4/ip_conntrack.h>
+#else /* linux-2.6.20+ */
+# include <net/netfilter/nf_nat_rule.h>
+#endif
--- /dev/null
+++ b/include/linux/netfilter/oot_trans.h
@@ -0,0 +1,14 @@
+/* Out of tree workarounds */
+#include <linux/version.h>
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 18)
+# define HAVE_MATCHINFOSIZE 1
+# define HAVE_TARGUSERINFO 1
+# define HAVE_TARGINFOSIZE 1
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 20)
+# define nfmark mark
+#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 21)
+# define tcp_v4_check(tcph, tcph_sz, s, d, csp) \
+ tcp_v4_check((tcph_sz), (s), (d), (csp))
+#endif
--- /dev/null
+++ b/include/linux/netfilter/xt_CHAOS.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_NETFILTER_XT_CHAOS_H
+#define _LINUX_NETFILTER_XT_CHAOS_H 1
+
+enum xt_chaos_target_variant {
+ XTCHAOS_NORMAL,
+ XTCHAOS_TARPIT,
+ XTCHAOS_DELUDE,
+};
+
+struct xt_chaos_target_info {
+ uint8_t variant;
+};
+
+#endif /* _LINUX_NETFILTER_XT_CHAOS_H */
--- /dev/null
+++ b/include/linux/netfilter/xt_portscan.h
@@ -0,0 +1,8 @@
+#ifndef _LINUX_NETFILTER_XT_PORTSCAN_H
+#define _LINUX_NETFILTER_XT_PORTSCAN_H 1
+
+struct xt_portscan_match_info {
+ uint8_t match_stealth, match_syn, match_cn, match_gr;
+};
+
+#endif /* _LINUX_NETFILTER_XT_PORTSCAN_H */
--- /dev/null
+++ b/net/netfilter/find_match.c
@@ -0,0 +1,39 @@
+/*
+ xt_request_find_match
+ by Jan Engelhardt <jengelh [at] gmx de>, 2006 - 2007
+
+ Based upon linux-2.6.18.5/net/netfilter/x_tables.c:
+ Copyright (C) 2006-2006 Harald Welte <laforge@netfilter.org>
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+*/
+#include <linux/err.h>
+#include <linux/netfilter_arp.h>
+#include <linux/socket.h>
+#include <linux/netfilter/x_tables.h>
+
+/*
+ * Yeah this code is sub-optimal, but the function is missing in
+ * mainline so far. -jengelh
+ */
+static struct xt_match *xt_request_find_match_lo(int af, const char *name,
+ u8 revision)
+{
+ static const char *const xt_prefix[] = {
+ [AF_INET] = "ip",
+ [AF_INET6] = "ip6",
+ [NF_ARP] = "arp",
+ };
+ struct xt_match *match;
+
+ match = try_then_request_module(xt_find_match(af, name, revision),
+ "%st_%s", xt_prefix[af], name);
+ if (IS_ERR(match) || match == NULL)
+ return NULL;
+
+ return match;
+}
+
+/* In case it goes into mainline, let this out-of-tree package compile */
+#define xt_request_find_match xt_request_find_match_lo
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -303,6 +303,14 @@ if NETFILTER_XTABLES
# alphabetically ordered list of targets
+config NETFILTER_XT_TARGET_CHAOS
+ tristate '"CHAOS" target support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a `CHAOS' target.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_TARGET_CLASSIFY
tristate '"CLASSIFY" target support'
depends on NETFILTER_ADVANCED
@@ -341,6 +349,14 @@ config NETFILTER_XT_TARGET_CONNSECMARK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_TARGET_DELUDE
+ tristate '"DELUDE" target support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a `DELUDE' target.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_TARGET_DSCP
tristate '"DSCP" and "TOS" target support'
depends on IP_NF_MANGLE || IP6_NF_MANGLE
@@ -654,6 +670,14 @@ config NETFILTER_XT_MATCH_MARK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_MATCH_PORTSCAN
+ tristate '"portscan" match support'
+ depends on NETFILTER_XTABLES
+ help
+ This option adds a 'portscan' match support.
+
+ To compile it as a module, choose M here. If unsure, say N.
+
config NETFILTER_XT_MATCH_MULTIPORT
tristate '"multiport" Multiple port match support'
depends on NETFILTER_ADVANCED
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -55,6 +55,8 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY)
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TRACE) += xt_TRACE.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_CHAOS) += xt_CHAOS.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_DELUDE) += xt_DELUDE.o
# matches
obj-$(CONFIG_NETFILTER_XT_MATCH_COMMENT) += xt_comment.o
@@ -90,6 +92,7 @@ obj-$(CONFIG_NETFILTER_XT_MATCH_STRING)
obj-$(CONFIG_NETFILTER_XT_MATCH_TCPMSS) += xt_tcpmss.o
obj-$(CONFIG_NETFILTER_XT_MATCH_TIME) += xt_time.o
obj-$(CONFIG_NETFILTER_XT_MATCH_U32) += xt_u32.o
+obj-$(CONFIG_NETFILTER_XT_MATCH_PORTSCAN) += xt_portscan.o
# IPVS
obj-$(CONFIG_IP_VS) += ipvs/
--- /dev/null
+++ b/net/netfilter/xt_CHAOS.c
@@ -0,0 +1,200 @@
+/*
+ * CHAOS target for netfilter
+ * Copyright © CC Computer Consultants GmbH, 2006 - 2007
+ * Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License; either version
+ * 2 or 3 as published by the Free Software Foundation.
+ */
+#include <linux/icmp.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/stat.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <linux/netfilter_ipv4/ipt_REJECT.h>
+#include <net/ip.h>
+#if defined(_LOCAL)
+# include "xt_CHAOS.h"
+# include "find_match.c"
+#elif defined(CONFIG_NETFILTER_XT_TARGET_CHAOS) || \
+ defined(CONFIG_NETFILTER_XT_TARGET_CHAOS_MODULE)
+# include <linux/netfilter/xt_CHAOS.h>
+# include "find_match.c"
+#else
+# include "xt_CHAOS.h"
+# include "find_match.c"
+#endif
+#define PFX KBUILD_MODNAME ": "
+
+/* Module parameters */
+static unsigned int reject_percentage = ~0U * .01;
+static unsigned int delude_percentage = ~0U * .0101;
+module_param(reject_percentage, uint, S_IRUGO | S_IWUSR);
+module_param(delude_percentage, uint, S_IRUGO | S_IWUSR);
+
+/* References to other matches/targets */
+static struct xt_match *xm_tcp;
+static struct xt_target *xt_delude, *xt_reject, *xt_tarpit;
+
+static int have_delude, have_tarpit;
+
+/* Static data for other matches/targets */
+static const struct ipt_reject_info reject_params = {
+ .with = ICMP_HOST_UNREACH,
+};
+
+static const struct xt_tcp tcp_params = {
+ .spts = {0, ~0},
+ .dpts = {0, ~0},
+};
+
+/* CHAOS functions */
+static void xt_chaos_total(const struct xt_chaos_target_info *info,
+ struct sk_buff *skb, const struct net_device *in,
+ const struct net_device *out, unsigned int hooknum)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ const int protoff = 4 * iph->ihl;
+ const int offset = ntohs(iph->frag_off) & IP_OFFSET;
+ const struct xt_target *destiny;
+ bool hotdrop = false, ret;
+
+ ret = xm_tcp->match(skb, in, out, xm_tcp, &tcp_params,
+ offset, protoff, &hotdrop);
+ if (!ret || hotdrop || (unsigned int)net_random() > delude_percentage)
+ return;
+
+ destiny = (info->variant == XTCHAOS_TARPIT) ? xt_tarpit : xt_delude;
+ destiny->target(skb, in, out, hooknum, destiny, NULL);
+ return;
+}
+
+static unsigned int chaos_tg(struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ unsigned int hooknum, const struct xt_target *target, const void *targinfo)
+{
+ /*
+ * Equivalent to:
+ * -A chaos -m statistic --mode random --probability \
+ * $reject_percentage -j REJECT --reject-with host-unreach;
+ * -A chaos -p tcp -m statistic --mode random --probability \
+ * $delude_percentage -j DELUDE;
+ * -A chaos -j DROP;
+ */
+ const struct xt_chaos_target_info *info = targinfo;
+ const struct iphdr *iph = ip_hdr(skb);
+
+ if ((unsigned int)net_random() <= reject_percentage)
+ return xt_reject->target(skb, in, out, hooknum, target,
+ &reject_params);
+
+ /* TARPIT/DELUDE may not be called from the OUTPUT chain */
+ if (iph->protocol == IPPROTO_TCP &&
+ info->variant != XTCHAOS_NORMAL && hooknum != NF_INET_LOCAL_OUT)
+ xt_chaos_total(info, skb, in, out, hooknum);
+
+ return NF_DROP;
+}
+
+static bool chaos_tg_check(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo, unsigned int hook_mask)
+{
+ const struct xt_chaos_target_info *info = targinfo;
+
+ if (info->variant == XTCHAOS_DELUDE && !have_delude) {
+ printk(KERN_WARNING PFX "Error: Cannot use --delude when "
+ "DELUDE module not available\n");
+ return false;
+ }
+ if (info->variant == XTCHAOS_TARPIT && !have_tarpit) {
+ printk(KERN_WARNING PFX "Error: Cannot use --tarpit when "
+ "TARPIT module not available\n");
+ return false;
+ }
+
+ return true;
+}
+
+static struct xt_target chaos_tg_reg = {
+ .name = "CHAOS",
+ .family = AF_INET,
+ .table = "filter",
+ .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD) |
+ (1 << NF_INET_LOCAL_OUT),
+ .checkentry = chaos_tg_check,
+ .target = chaos_tg,
+ .targetsize = sizeof(struct xt_chaos_target_info),
+ .me = THIS_MODULE,
+};
+
+static int __init chaos_tg_init(void)
+{
+ int ret = -EINVAL;
+
+ xm_tcp = xt_request_find_match(AF_INET, "tcp", 0);
+ if (xm_tcp == NULL) {
+ printk(KERN_WARNING PFX "Error: Could not find or load "
+ "\"tcp\" match\n");
+ return -EINVAL;
+ }
+
+ xt_reject = xt_request_find_target(AF_INET, "REJECT", 0);
+ if (xt_reject == NULL) {
+ printk(KERN_WARNING PFX "Error: Could not find or load "
+ "\"REJECT\" target\n");
+ goto out2;
+ }
+
+ xt_tarpit = xt_request_find_target(AF_INET, "TARPIT", 0);
+ have_tarpit = xt_tarpit != NULL;
+ if (!have_tarpit)
+ printk(KERN_WARNING PFX "Warning: Could not find or load "
+ "\"TARPIT\" target\n");
+
+ xt_delude = xt_request_find_target(AF_INET, "DELUDE", 0);
+ have_delude = xt_delude != NULL;
+ if (!have_delude)
+ printk(KERN_WARNING PFX "Warning: Could not find or load "
+ "\"DELUDE\" target\n");
+
+ if ((ret = xt_register_target(&chaos_tg_reg)) != 0) {
+ printk(KERN_WARNING PFX "xt_register_target returned "
+ "error %d\n", ret);
+ goto out3;
+ }
+
+ return 0;
+
+ out3:
+ if (have_delude)
+ module_put(xt_delude->me);
+ if (have_tarpit)
+ module_put(xt_tarpit->me);
+ module_put(xt_reject->me);
+ out2:
+ module_put(xm_tcp->me);
+ return ret;
+}
+
+static void __exit chaos_tg_exit(void)
+{
+ xt_unregister_target(&chaos_tg_reg);
+ module_put(xm_tcp->me);
+ module_put(xt_reject->me);
+ if (have_delude)
+ module_put(xt_delude->me);
+ if (have_tarpit)
+ module_put(xt_tarpit->me);
+ return;
+}
+
+module_init(chaos_tg_init);
+module_exit(chaos_tg_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("netfilter \"CHAOS\" target");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_CHAOS");
--- /dev/null
+++ b/net/netfilter/xt_DELUDE.c
@@ -0,0 +1,197 @@
+/*
+ * DELUDE target
+ * Copyright © CC Computer Consultants GmbH, 2007
+ * Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * Based upon linux-2.6.18.5/net/ipv4/netfilter/ipt_REJECT.c:
+ * (C) 1999-2001 Paul `Rusty' Russell
+ * (C) 2002-2004 Netfilter Core Team <coreteam@netfilter.org>
+ *
+ * xt_DELUDE acts like REJECT, but does reply with SYN-ACK on SYN.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <linux/tcp.h>
+#include <linux/netfilter/x_tables.h>
+#ifdef CONFIG_BRIDGE_NETFILTER
+# include <linux/netfilter_bridge.h>
+#endif
+#include <net/tcp.h>
+#define PFX KBUILD_MODNAME ": "
+
+static void delude_send_reset(struct sk_buff *oldskb, unsigned int hook)
+{
+ struct tcphdr _otcph, *oth, *tcph;
+ unsigned int addr_type;
+ struct sk_buff *nskb;
+ u_int16_t tmp_port;
+ u_int32_t tmp_addr;
+ struct iphdr *niph;
+ bool needs_ack;
+
+ /* IP header checks: fragment. */
+ if (ip_hdr(oldskb)->frag_off & htons(IP_OFFSET))
+ return;
+
+ oth = skb_header_pointer(oldskb, ip_hdrlen(oldskb),
+ sizeof(_otcph), &_otcph);
+ if (oth == NULL)
+ return;
+
+ /* No RST for RST. */
+ if (oth->rst)
+ return;
+
+ /* Check checksum */
+ if (nf_ip_checksum(oldskb, hook, ip_hdrlen(oldskb), IPPROTO_TCP))
+ return;
+
+ /* We need a linear, writeable skb. We also need to expand
+ headroom in case hh_len of incoming interface < hh_len of
+ outgoing interface */
+ nskb = skb_copy_expand(oldskb, LL_MAX_HEADER, skb_tailroom(oldskb),
+ GFP_ATOMIC);
+ if (!nskb)
+ return;
+
+ /* This packet will not be the same as the other: clear nf fields */
+ nf_reset(nskb);
+ nskb->mark = 0;
+ skb_init_secmark(nskb);
+
+ skb_shinfo(nskb)->gso_size = 0;
+ skb_shinfo(nskb)->gso_segs = 0;
+ skb_shinfo(nskb)->gso_type = 0;
+
+ tcph = (struct tcphdr *)(skb_network_header(nskb) + ip_hdrlen(nskb));
+
+ /* Swap source and dest */
+ niph = ip_hdr(nskb);
+ tmp_addr = niph->saddr;
+ niph->saddr = niph->daddr;
+ niph->daddr = tmp_addr;
+ tmp_port = tcph->source;
+ tcph->source = tcph->dest;
+ tcph->dest = tmp_port;
+
+ /* Truncate to length (no data) */
+ tcph->doff = sizeof(struct tcphdr) / 4;
+ skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
+ niph->tot_len = htons(nskb->len);
+
+ if (oth->syn && !oth->ack && !oth->rst && !oth->fin) {
+ /* DELUDE essential part */
+ tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn + oth->fin +
+ oldskb->len - ip_hdrlen(oldskb) -
+ (oth->doff << 2));
+ tcph->seq = false;
+ tcph->ack = true;
+ } else {
+ if (!tcph->ack) {
+ needs_ack = true;
+ tcph->ack_seq = htonl(ntohl(oth->seq) + oth->syn +
+ oth->fin + oldskb->len -
+ ip_hdrlen(oldskb) - (oth->doff<<2));
+ tcph->seq = false;
+ } else {
+ needs_ack = false;
+ tcph->seq = oth->ack_seq;
+ tcph->ack_seq = false;
+ }
+
+ /* Reset flags */
+ ((u_int8_t *)tcph)[13] = 0;
+ tcph->rst = true;
+ tcph->ack = needs_ack;
+ }
+
+ tcph->window = 0;
+ tcph->urg_ptr = 0;
+
+ /* Adjust TCP checksum */
+ tcph->check = 0;
+ tcph->check = tcp_v4_check(sizeof(struct tcphdr), niph->saddr,
+ niph->daddr, csum_partial((char *)tcph,
+ sizeof(struct tcphdr), 0));
+
+ /* Set DF, id = 0 */
+ niph->frag_off = htons(IP_DF);
+ niph->id = 0;
+
+ addr_type = RTN_UNSPEC;
+#ifdef CONFIG_BRIDGE_NETFILTER
+ if (hook != NF_INET_FORWARD || (nskb->nf_bridge != NULL &&
+ nskb->nf_bridge->mask & BRNF_BRIDGED))
+#else
+ if (hook != NF_INET_FORWARD)
+#endif
+ addr_type = RTN_LOCAL;
+
+ if (ip_route_me_harder(nskb, addr_type))
+ goto free_nskb;
+
+ nskb->ip_summed = CHECKSUM_NONE;
+
+ /* Adjust IP TTL */
+ niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+
+ /* Adjust IP checksum */
+ niph->check = 0;
+ niph->check = ip_fast_csum(skb_network_header(nskb), niph->ihl);
+
+ /* "Never happens" */
+ if (nskb->len > dst_mtu(nskb->dst))
+ goto free_nskb;
+
+ nf_ct_attach(nskb, oldskb);
+
+ NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, nskb, NULL, nskb->dst->dev,
+ dst_output);
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
+}
+
+static unsigned int delude_tg(struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ unsigned int hooknum, const struct xt_target *target, const void *targinfo)
+{
+ /* WARNING: This code causes reentry within iptables.
+ This means that the iptables jump stack is now crap. We
+ must return an absolute verdict. --RR */
+ delude_send_reset(skb, hooknum);
+ return NF_DROP;
+}
+
+static struct xt_target delude_tg_reg = {
+ .name = "DELUDE",
+ .family = AF_INET,
+ .table = "filter",
+ .hooks = (1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD),
+ .target = delude_tg,
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+};
+
+static int __init delude_tg_init(void)
+{
+ return xt_register_target(&delude_tg_reg);
+}
+
+static void __exit delude_tg_exit(void)
+{
+ xt_unregister_target(&delude_tg_reg);
+}
+
+module_init(delude_tg_init);
+module_exit(delude_tg_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("netfilter \"DELUDE\" target");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_DELUDE");
--- /dev/null
+++ b/net/netfilter/xt_portscan.c
@@ -0,0 +1,269 @@
+/*
+ * portscan match for netfilter
+ * Copyright © CC Computer Consultants GmbH, 2006 - 2007
+ * Contact: Jan Engelhardt <jengelh@computergmbh.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License; either version
+ * 2 or 3 as published by the Free Software Foundation.
+ */
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/skbuff.h>
+#include <linux/stat.h>
+#include <linux/tcp.h>
+#include <linux/types.h>
+#include <linux/version.h>
+#include <linux/netfilter/x_tables.h>
+#include <linux/netfilter/xt_tcpudp.h>
+#include <net/netfilter/nf_nat_rule.h>
+#if defined(_LOCAL)
+# include "xt_portscan.h"
+#elif defined(CONFIG_NETFILTER_XT_MATCH_PORTSCAN) || \
+ defined(CONFIG_NETFILTER_XT_MATCH_PORTSCAN_MODULE)
+# include <linux/netfilter/xt_portscan.h>
+#else
+# include "xt_portscan.h"
+#endif
+#define PFX KBUILD_MODNAME ": "
+
+enum {
+ TCP_FLAGS_ALL3 = TCP_FLAG_FIN | TCP_FLAG_RST | TCP_FLAG_SYN,
+ TCP_FLAGS_ALL4 = TCP_FLAGS_ALL3 | TCP_FLAG_ACK,
+ TCP_FLAGS_ALL6 = TCP_FLAGS_ALL4 | TCP_FLAG_PSH | TCP_FLAG_URG,
+};
+
+/* Module parameters */
+static unsigned int
+ connmark_mask = ~0,
+ packet_mask = ~0,
+ mark_seen = 0x9,
+ mark_synrcv = 0x1,
+ mark_closed = 0x2,
+ mark_synscan = 0x3,
+ mark_estab1 = 0x4,
+ mark_estab2 = 0x5,
+ mark_cnscan = 0x6,
+ mark_grscan = 0x7,
+ mark_valid = 0x8;
+
+module_param(connmark_mask, uint, S_IRUGO | S_IWUSR);
+module_param(packet_mask, uint, S_IRUGO | S_IWUSR);
+module_param(mark_seen, uint, S_IRUGO | S_IWUSR);
+module_param(mark_synrcv, uint, S_IRUGO | S_IWUSR);
+module_param(mark_closed, uint, S_IRUGO | S_IWUSR);
+module_param(mark_synscan, uint, S_IRUGO | S_IWUSR);
+module_param(mark_estab1, uint, S_IRUGO | S_IWUSR);
+module_param(mark_estab2, uint, S_IRUGO | S_IWUSR);
+module_param(mark_cnscan, uint, S_IRUGO | S_IWUSR);
+module_param(mark_grscan, uint, S_IRUGO | S_IWUSR);
+module_param(mark_valid, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(connmark_mask, "only set specified bits in connection mark");
+MODULE_PARM_DESC(packet_mask, "only set specified bits in packet mark");
+MODULE_PARM_DESC(mark_seen, "nfmark value for packet-seen state");
+MODULE_PARM_DESC(mark_synrcv, "connmark value for SYN Received state");
+MODULE_PARM_DESC(mark_closed, "connmark value for closed state");
+MODULE_PARM_DESC(mark_synscan, "connmark value for SYN Scan state");
+MODULE_PARM_DESC(mark_estab1, "connmark value for Established-1 state");
+MODULE_PARM_DESC(mark_estab2, "connmark value for Established-2 state");
+MODULE_PARM_DESC(mark_cnscan, "connmark value for Connect Scan state");
+MODULE_PARM_DESC(mark_grscan, "connmark value for Grab Scan state");
+MODULE_PARM_DESC(mark_valid, "connmark value for Valid state");
+
+/* TCP flag functions */
+static inline bool tflg_ack4(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == TCP_FLAG_ACK;
+}
+
+static inline bool tflg_ack6(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL6) == TCP_FLAG_ACK;
+}
+
+static inline bool tflg_fin(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL3) == TCP_FLAG_FIN;
+}
+
+static inline bool tflg_rst(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL3) == TCP_FLAG_RST;
+}
+
+static inline bool tflg_rstack(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL4) ==
+ (TCP_FLAG_ACK | TCP_FLAG_RST);
+}
+
+static inline bool tflg_syn(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL4) == TCP_FLAG_SYN;
+}
+
+static inline bool tflg_synack(const struct tcphdr *th)
+{
+ return (tcp_flag_word(th) & TCP_FLAGS_ALL4) ==
+ (TCP_FLAG_SYN | TCP_FLAG_ACK);
+}
+
+/* portscan functions */
+static inline bool portscan_mt_stealth(const struct tcphdr *th)
+{
+ /*
+ * "Connection refused" replies to our own probes must not be matched.
+ */
+ if (tflg_rstack(th))
+ return false;
+
+ if (tflg_rst(th) && printk_ratelimit()) {
+ printk(KERN_WARNING PFX "Warning: Pure RST received\n");
+ return false;
+ }
+
+ /*
+ * -p tcp ! --syn -m conntrack --ctstate INVALID: Looking for non-start
+ * packets that are not associated with any connection -- this will
+ * match most scan types (NULL, XMAS, FIN) and ridiculous flag
+ * combinations (SYN-RST, SYN-FIN, SYN-FIN-RST, FIN-RST, etc.).
+ */
+ return !tflg_syn(th);
+}
+
+static inline unsigned int portscan_mt_full(int mark,
+ enum ip_conntrack_info ctstate, bool loopback, const struct tcphdr *tcph,
+ unsigned int payload_len)
+{
+ if (mark == mark_estab2) {
+ /*
+ * -m connmark --mark $ESTAB2
+ */
+ if (tflg_ack4(tcph) && payload_len == 0)
+ return mark; /* keep mark */
+ else if (tflg_rst(tcph) || tflg_fin(tcph))
+ return mark_grscan;
+ else
+ return mark_valid;
+ } else if (mark == mark_estab1) {
+ /*
+ * -m connmark --mark $ESTAB1
+ */
+ if (tflg_rst(tcph) || tflg_fin(tcph))
+ return mark_cnscan;
+ else if (!loopback && tflg_ack4(tcph) && payload_len == 0)
+ return mark_estab2;
+ else
+ return mark_valid;
+ } else if (mark == mark_synrcv) {
+ /*
+ * -m connmark --mark $SYN
+ */
+ if (loopback && tflg_synack(tcph))
+ return mark; /* keep mark */
+ else if (loopback && tflg_rstack(tcph))
+ return mark_closed;
+ else if (tflg_ack6(tcph))
+ return mark_estab1;
+ else
+ return mark_synscan;
+ } else if (ctstate == IP_CT_NEW && tflg_syn(tcph)) {
+ /*
+ * -p tcp --syn --ctstate NEW
+ */
+ return mark_synrcv;
+ }
+ return mark;
+}
+
+static bool portscan_mt(const struct sk_buff *skb,
+ const struct net_device *in, const struct net_device *out,
+ const struct xt_match *match, const void *matchinfo, int offset,
+ unsigned int protoff, bool *hotdrop)
+{
+ const struct xt_portscan_match_info *info = matchinfo;
+ enum ip_conntrack_info ctstate;
+ const struct tcphdr *tcph;
+ struct nf_conn *ctdata;
+ struct tcphdr tcph_buf;
+
+ tcph = skb_header_pointer(skb, protoff, sizeof(tcph_buf), &tcph_buf);
+ if (tcph == NULL)
+ return false;
+
+ /* Check for invalid packets: -m conntrack --ctstate INVALID */
+ if ((ctdata = nf_ct_get(skb, &ctstate)) == NULL) {
+ if (info->match_stealth)
+ return portscan_mt_stealth(tcph);
+ /*
+ * If @ctdata is NULL, we cannot match the other scan
+ * types, return.
+ */
+ return false;
+ }
+
+ /*
+ * If -m portscan was previously applied to this packet, the rules we
+ * simulate must not be run through again. And for speedup, do not call
+ * it either when the connection is already VALID.
+ */
+ if ((ctdata->mark & connmark_mask) == mark_valid ||
+ (skb->mark & packet_mask) != mark_seen) {
+ unsigned int n;
+
+ n = portscan_mt_full(ctdata->mark & connmark_mask, ctstate,
+ (in->flags & IFF_LOOPBACK) == IFF_LOOPBACK, tcph,
+ skb->len - protoff - 4 * tcph->doff);
+
+ ctdata->mark = (ctdata->mark & ~connmark_mask) | n;
+ ((struct sk_buff *)skb)->mark =
+ (skb->mark & ~packet_mask) ^ mark_seen;
+ }
+
+ return (info->match_syn && ctdata->mark == mark_synscan) ||
+ (info->match_cn && ctdata->mark == mark_cnscan) ||
+ (info->match_gr && ctdata->mark == mark_grscan);
+}
+
+static bool portscan_mt_check(const char *tablename, const void *entry,
+ const struct xt_match *match, void *matchinfo, unsigned int hook_mask)
+{
+ const struct xt_portscan_match_info *info = matchinfo;
+
+ if ((info->match_stealth & ~1) || (info->match_syn & ~1) ||
+ (info->match_cn & ~1) || (info->match_gr & ~1)) {
+ printk(KERN_WARNING PFX "Invalid flags\n");
+ return false;
+ }
+ return true;
+}
+
+static struct xt_match portscan_mt_reg __read_mostly = {
+ .name = "portscan",
+ .family = AF_INET,
+ .match = portscan_mt,
+ .checkentry = portscan_mt_check,
+ .matchsize = sizeof(struct xt_portscan_match_info),
+ .proto = IPPROTO_TCP,
+ .me = THIS_MODULE,
+};
+
+static int __init portscan_mt_init(void)
+{
+ return xt_register_match(&portscan_mt_reg);
+}
+
+static void __exit portscan_mt_exit(void)
+{
+ xt_unregister_match(&portscan_mt_reg);
+ return;
+}
+
+module_init(portscan_mt_init);
+module_exit(portscan_mt_exit);
+MODULE_AUTHOR("Jan Engelhardt <jengelh@computergmbh.de>");
+MODULE_DESCRIPTION("netfilter \"portscan\" match");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_portscan");
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -1574,6 +1574,8 @@ __u32 secure_tcp_sequence_number(__be32
return seq;
}
+EXPORT_SYMBOL(secure_tcp_sequence_number);
+
/* Generate secure starting point for ephemeral IPV4 transport port search */
u32 secure_ipv4_port_ephemeral(__be32 saddr, __be32 daddr, __be16 dport)
{

View file

@ -0,0 +1,318 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -469,6 +469,23 @@ config NETFILTER_XT_TARGET_SECMARK
To compile it as a module, choose M here. If unsure, say N.
+config NETFILTER_XT_TARGET_TARPIT
+ tristate '"TARPIT" target support'
+ depends on NETFILTER_XTABLES
+ ---help---
+ Adds a TARPIT target to iptables, which captures and holds
+ incoming TCP connections using no local per-connection resources.
+ Connections are accepted, but immediately switched to the persist
+ state (0 byte window), in which the remote side stops sending data
+ and asks to continue every 60-240 seconds. Attempts to close the
+ connection are ignored, forcing the remote side to time out the
+ connection in 12-24 minutes.
+
+ This offers similar functionality to LaBrea
+ <http://www.hackbusters.net/LaBrea/>, but does not require dedicated
+ hardware or IPs. Any TCP port that you would normally DROP or REJECT
+ can instead become a tarpit.
+
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
depends on (IPV6 || IPV6=n)
--- a/net/netfilter/Makefile
+++ b/net/netfilter/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_NFQUEUE
obj-$(CONFIG_NETFILTER_XT_TARGET_NOTRACK) += xt_NOTRACK.o
obj-$(CONFIG_NETFILTER_XT_TARGET_RATEEST) += xt_RATEEST.o
obj-$(CONFIG_NETFILTER_XT_TARGET_SECMARK) += xt_SECMARK.o
+obj-$(CONFIG_NETFILTER_XT_TARGET_TARPIT) += xt_TARPIT.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TPROXY) += xt_TPROXY.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPMSS) += xt_TCPMSS.o
obj-$(CONFIG_NETFILTER_XT_TARGET_TCPOPTSTRIP) += xt_TCPOPTSTRIP.o
--- /dev/null
+++ b/net/netfilter/xt_TARPIT.c
@@ -0,0 +1,279 @@
+/*
+ * Kernel module to capture and hold incoming TCP connections using
+ * no local per-connection resources.
+ *
+ * Based on ipt_REJECT.c and offering functionality similar to
+ * LaBrea <http://www.hackbusters.net/LaBrea/>.
+ *
+ * Copyright (c) 2002 Aaron Hopkins <tools@die.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ * Goal:
+ * - Allow incoming TCP connections to be established.
+ * - Passing data should result in the connection being switched to the
+ * persist state (0 byte window), in which the remote side stops sending
+ * data and asks to continue every 60 seconds.
+ * - Attempts to shut down the connection should be ignored completely, so
+ * the remote side ends up having to time it out.
+ *
+ * This means:
+ * - Reply to TCP SYN,!ACK,!RST,!FIN with SYN-ACK, window 5 bytes
+ * - Reply to TCP SYN,ACK,!RST,!FIN with RST to prevent spoofing
+ * - Reply to TCP !SYN,!RST,!FIN with ACK, window 0 bytes, rate-limited
+ */
+
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/ip.h>
+#include <net/ip.h>
+#include <net/tcp.h>
+#include <net/icmp.h>
+struct in_device;
+#include <net/route.h>
+#include <linux/random.h>
+#include <linux/netfilter_ipv4/ip_tables.h>
+
+#if 0
+#define DEBUGP printk
+#else
+#define DEBUGP(format, args...)
+#endif
+
+/* Stolen from ip_finish_output2 */
+static int ip_direct_send(struct sk_buff *skb)
+{
+ struct dst_entry *dst = skb->dst;
+
+ if (dst->hh != NULL)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour != NULL)
+ return dst->neighbour->output(skb);
+
+ if (net_ratelimit())
+ printk(KERN_DEBUG "TARPIT ip_direct_send: no header cache and no neighbor!\n");
+
+ kfree_skb(skb);
+ return -EINVAL;
+}
+
+
+/* Send reply */
+static void tarpit_tcp(const struct sk_buff *oskb, struct rtable *ort,
+ unsigned int local)
+{
+ struct sk_buff *nskb;
+ struct rtable *nrt;
+ struct tcphdr *otcph, *ntcph;
+ struct flowi fl = {};
+ unsigned int otcplen;
+ u_int16_t tmp;
+
+ const struct iphdr *oiph = ip_hdr(oskb);
+ struct iphdr *niph;
+
+ /* A truncated TCP header is not going to be useful */
+ if (oskb->len < ip_hdrlen(oskb) + sizeof(struct tcphdr))
+ return;
+
+ otcph = (void *)oiph + ip_hdrlen(oskb);
+ otcplen = oskb->len - ip_hdrlen(oskb);
+
+ /* No replies for RST or FIN */
+ if (otcph->rst || otcph->fin)
+ return;
+
+ /* No reply to !SYN,!ACK. Rate-limit replies to !SYN,ACKs */
+ if (!otcph->syn && (!otcph->ack || !xrlim_allow(&ort->u.dst, 1*HZ)))
+ return;
+
+ /* Check checksum. */
+ if (tcp_v4_check(otcplen, oiph->saddr, oiph->daddr,
+ csum_partial((char *)otcph, otcplen, 0)) != 0)
+ return;
+
+ /*
+ * Copy skb (even if skb is about to be dropped, we cannot just
+ * clone it because there may be other things, such as tcpdump,
+ * interested in it)
+ */
+ nskb = skb_copy(oskb, GFP_ATOMIC);
+ if (nskb == NULL)
+ return;
+
+ niph = ip_hdr(nskb);
+
+ /* This packet will not be the same as the other: clear nf fields */
+ nf_conntrack_put(nskb->nfct);
+ nskb->nfct = NULL;
+#ifdef CONFIG_NETFILTER_DEBUG
+ nskb->nf_debug = 0;
+#endif
+
+ ntcph = (void *)niph + ip_hdrlen(nskb);
+
+ /* Truncate to length (no data) */
+ ntcph->doff = sizeof(struct tcphdr)/4;
+ skb_trim(nskb, ip_hdrlen(nskb) + sizeof(struct tcphdr));
+ niph->tot_len = htons(nskb->len);
+
+ /* Swap source and dest */
+ niph->daddr = xchg(&niph->saddr, niph->daddr);
+ tmp = ntcph->source;
+ ntcph->source = ntcph->dest;
+ ntcph->dest = tmp;
+
+ /* Use supplied sequence number or make a new one */
+ ntcph->seq = otcph->ack ? otcph->ack_seq
+ : htonl(secure_tcp_sequence_number(niph->saddr,
+ niph->daddr,
+ ntcph->source,
+ ntcph->dest));
+
+ /* Our SYN-ACKs must have a >0 window */
+ ntcph->window = (otcph->syn && !otcph->ack) ? htons(5) : 0;
+
+ ntcph->urg_ptr = 0;
+
+ /* Reset flags */
+ ((u_int8_t *)ntcph)[13] = 0;
+
+ if (otcph->syn && otcph->ack) {
+ ntcph->rst = 1;
+ ntcph->ack_seq = 0;
+ } else {
+ ntcph->syn = otcph->syn;
+ ntcph->ack = 1;
+ ntcph->ack_seq = htonl(ntohl(otcph->seq) + otcph->syn);
+ }
+
+ /* Adjust TCP checksum */
+ ntcph->check = 0;
+ ntcph->check = tcp_v4_check(sizeof(struct tcphdr),
+ niph->saddr,
+ niph->daddr,
+ csum_partial((char *)ntcph,
+ sizeof(struct tcphdr), 0));
+
+ fl.nl_u.ip4_u.daddr = niph->daddr;
+ fl.nl_u.ip4_u.saddr = local ? niph->saddr : 0;
+ fl.nl_u.ip4_u.tos = RT_TOS(niph->tos) | RTO_CONN;
+ fl.oif = 0;
+
+ if (ip_route_output_key(&init_net, &nrt, &fl))
+ goto free_nskb;
+
+ dst_release(nskb->dst);
+ nskb->dst = &nrt->u.dst;
+
+ /* Adjust IP TTL */
+ niph->ttl = dst_metric(nskb->dst, RTAX_HOPLIMIT);
+
+ /* Set DF, id = 0 */
+ niph->frag_off = htons(IP_DF);
+ niph->id = 0;
+
+ /* Adjust IP checksum */
+ niph->check = 0;
+ niph->check = ip_fast_csum((unsigned char *)niph, niph->ihl);
+
+ /* "Never happens" */
+ if (nskb->len > dst_mtu(nskb->dst))
+ goto free_nskb;
+
+ ip_direct_send(nskb);
+ return;
+
+ free_nskb:
+ kfree_skb(nskb);
+}
+
+static unsigned int xt_tarpit_target(struct sk_buff *skb,
+ const struct net_device *in,
+ const struct net_device *out,
+ unsigned int hooknum,
+ const struct xt_target *target,
+ const void *targinfo)
+{
+ const struct iphdr *iph = ip_hdr(skb);
+ struct rtable *rt = (void *)skb->dst;
+
+ /* Do we have an input route cache entry? */
+ if (rt == NULL)
+ return NF_DROP;
+
+ /* No replies to physical multicast/broadcast */
+ if (skb->pkt_type != PACKET_HOST && skb->pkt_type != PACKET_OTHERHOST)
+ return NF_DROP;
+
+ /* Now check at the protocol level */
+ if (rt->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
+ return NF_DROP;
+
+ /*
+ * Our naive response construction does not deal with IP
+ * options, and probably should not try.
+ */
+ if (iph->ihl * 4 != sizeof(struct iphdr))
+ return NF_DROP;
+
+ /* We are not interested in fragments */
+ if (iph->frag_off & htons(IP_OFFSET))
+ return NF_DROP;
+
+ tarpit_tcp(skb, rt, hooknum == NF_INET_LOCAL_IN);
+ return NF_DROP;
+}
+
+static bool xt_tarpit_check(const char *tablename, const void *entry,
+ const struct xt_target *target, void *targinfo,
+ unsigned int hook_mask)
+{
+ bool invalid;
+
+ if (strcmp(tablename, "raw") == 0 && hook_mask == NF_INET_PRE_ROUTING)
+ return true;
+ if (strcmp(tablename, "filter") != 0)
+ return false;
+ invalid = hook_mask & ~((1 << NF_INET_LOCAL_IN) | (1 << NF_INET_FORWARD));
+ return !invalid;
+}
+
+static struct xt_target xt_tarpit_reg = {
+ .name = "TARPIT",
+ .family = AF_INET,
+ .proto = IPPROTO_TCP,
+ .target = xt_tarpit_target,
+ .checkentry = xt_tarpit_check,
+ .me = THIS_MODULE,
+};
+
+static int __init xt_tarpit_init(void)
+{
+ return xt_register_target(&xt_tarpit_reg);
+}
+
+static void __exit xt_tarpit_exit(void)
+{
+ xt_unregister_target(&xt_tarpit_reg);
+}
+
+module_init(xt_tarpit_init);
+module_exit(xt_tarpit_exit);
+MODULE_DESCRIPTION("netfilter xt_TARPIT target module");
+MODULE_AUTHOR("Jan Engelhardt <jengelh@gmx.de>");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("ipt_TARPIT");

View file

@ -0,0 +1,18 @@
--- a/net/netfilter/Kconfig
+++ b/net/netfilter/Kconfig
@@ -160,7 +160,6 @@ config NF_CONNTRACK_FTP
config NF_CONNTRACK_H323
tristate "H.323 protocol support"
- depends on (IPV6 || IPV6=n)
depends on NETFILTER_ADVANCED
help
H.323 is a VoIP signalling protocol from ITU-T. As one of the most
@@ -488,7 +487,6 @@ config NETFILTER_XT_TARGET_TARPIT
config NETFILTER_XT_TARGET_TCPMSS
tristate '"TCPMSS" target support'
- depends on (IPV6 || IPV6=n)
default m if NETFILTER_ADVANCED=n
---help---
This option adds a `TCPMSS' target, which allows you to alter the

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,795 @@
--- a/include/linux/pkt_sched.h
+++ b/include/linux/pkt_sched.h
@@ -180,8 +180,37 @@ struct tc_sfq_xstats
*
* The only reason for this is efficiency, it is possible
* to change these parameters in compile time.
+ *
+ * If you need to play with these values, use esfq instead.
*/
+/* ESFQ section */
+
+enum
+{
+ /* traditional */
+ TCA_SFQ_HASH_CLASSIC,
+ TCA_SFQ_HASH_DST,
+ TCA_SFQ_HASH_SRC,
+ TCA_SFQ_HASH_FWMARK,
+ /* conntrack */
+ TCA_SFQ_HASH_CTORIGDST,
+ TCA_SFQ_HASH_CTORIGSRC,
+ TCA_SFQ_HASH_CTREPLDST,
+ TCA_SFQ_HASH_CTREPLSRC,
+ TCA_SFQ_HASH_CTNATCHG,
+};
+
+struct tc_esfq_qopt
+{
+ unsigned quantum; /* Bytes per round allocated to flow */
+ int perturb_period; /* Period of hash perturbation */
+ __u32 limit; /* Maximal packets in queue */
+ unsigned divisor; /* Hash divisor */
+ unsigned flows; /* Maximal number of flows */
+ unsigned hash_kind; /* Hash function to use for flow identification */
+};
+
/* RED section */
enum
--- a/net/sched/Kconfig
+++ b/net/sched/Kconfig
@@ -137,6 +137,37 @@ config NET_SCH_SFQ
To compile this code as a module, choose M here: the
module will be called sch_sfq.
+config NET_SCH_ESFQ
+ tristate "Enhanced Stochastic Fairness Queueing (ESFQ)"
+ ---help---
+ Say Y here if you want to use the Enhanced Stochastic Fairness
+ Queueing (ESFQ) packet scheduling algorithm for some of your network
+ devices or as a leaf discipline for a classful qdisc such as HTB or
+ CBQ (see the top of <file:net/sched/sch_esfq.c> for details and
+ references to the SFQ algorithm).
+
+ This is an enchanced SFQ version which allows you to control some
+ hardcoded values in the SFQ scheduler.
+
+ ESFQ also adds control of the hash function used to identify packet
+ flows. The original SFQ discipline hashes by connection; ESFQ add
+ several other hashing methods, such as by src IP or by dst IP, which
+ can be more fair to users in some networking situations.
+
+ To compile this code as a module, choose M here: the
+ module will be called sch_esfq.
+
+config NET_SCH_ESFQ_NFCT
+ bool "Connection Tracking Hash Types"
+ depends on NET_SCH_ESFQ && NF_CONNTRACK
+ ---help---
+ Say Y here to enable support for hashing based on netfilter connection
+ tracking information. This is useful for a router that is also using
+ NAT to connect privately-addressed hosts to the Internet. If you want
+ to provide fair distribution of upstream bandwidth, ESFQ must use
+ connection tracking information, since all outgoing packets will share
+ the same source address.
+
config NET_SCH_TEQL
tristate "True Link Equalizer (TEQL)"
---help---
--- a/net/sched/Makefile
+++ b/net/sched/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_NET_SCH_GRED) += sch_gred.o
obj-$(CONFIG_NET_SCH_INGRESS) += sch_ingress.o
obj-$(CONFIG_NET_SCH_DSMARK) += sch_dsmark.o
obj-$(CONFIG_NET_SCH_SFQ) += sch_sfq.o
+obj-$(CONFIG_NET_SCH_ESFQ) += sch_esfq.o
obj-$(CONFIG_NET_SCH_TBF) += sch_tbf.o
obj-$(CONFIG_NET_SCH_TEQL) += sch_teql.o
obj-$(CONFIG_NET_SCH_PRIO) += sch_prio.o
--- /dev/null
+++ b/net/sched/sch_esfq.c
@@ -0,0 +1,702 @@
+/*
+ * net/sched/sch_esfq.c Extended Stochastic Fairness Queueing discipline.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Authors: Alexey Kuznetsov, <kuznet@ms2.inr.ac.ru>
+ *
+ * Changes: Alexander Atanasov, <alex@ssi.bg>
+ * Added dynamic depth,limit,divisor,hash_kind options.
+ * Added dst and src hashes.
+ *
+ * Alexander Clouter, <alex@digriz.org.uk>
+ * Ported ESFQ to Linux 2.6.
+ *
+ * Corey Hickey, <bugfood-c@fatooh.org>
+ * Maintenance of the Linux 2.6 port.
+ * Added fwmark hash (thanks to Robert Kurjata).
+ * Added usage of jhash.
+ * Added conntrack support.
+ * Added ctnatchg hash (thanks to Ben Pfountz).
+ */
+
+#include <linux/module.h>
+#include <asm/uaccess.h>
+#include <asm/system.h>
+#include <linux/bitops.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/jiffies.h>
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/socket.h>
+#include <linux/sockios.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/interrupt.h>
+#include <linux/if_ether.h>
+#include <linux/inet.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/notifier.h>
+#include <linux/init.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <net/route.h>
+#include <linux/skbuff.h>
+#include <net/sock.h>
+#include <net/pkt_sched.h>
+#include <linux/jhash.h>
+#include <net/netfilter/nf_conntrack.h>
+
+/* Stochastic Fairness Queuing algorithm.
+ For more comments look at sch_sfq.c.
+ The difference is that you can change limit, depth,
+ hash table size and choose alternate hash types.
+
+ classic: same as in sch_sfq.c
+ dst: destination IP address
+ src: source IP address
+ fwmark: netfilter mark value
+ ctorigdst: original destination IP address
+ ctorigsrc: original source IP address
+ ctrepldst: reply destination IP address
+ ctreplsrc: reply source IP
+
+*/
+
+#define ESFQ_HEAD 0
+#define ESFQ_TAIL 1
+
+/* This type should contain at least SFQ_DEPTH*2 values */
+typedef unsigned int esfq_index;
+
+struct esfq_head
+{
+ esfq_index next;
+ esfq_index prev;
+};
+
+struct esfq_sched_data
+{
+/* Parameters */
+ int perturb_period;
+ unsigned quantum; /* Allotment per round: MUST BE >= MTU */
+ int limit;
+ unsigned depth;
+ unsigned hash_divisor;
+ unsigned hash_kind;
+/* Variables */
+ struct timer_list perturb_timer;
+ int perturbation;
+ esfq_index tail; /* Index of current slot in round */
+ esfq_index max_depth; /* Maximal depth */
+
+ esfq_index *ht; /* Hash table */
+ esfq_index *next; /* Active slots link */
+ short *allot; /* Current allotment per slot */
+ unsigned short *hash; /* Hash value indexed by slots */
+ struct sk_buff_head *qs; /* Slot queue */
+ struct esfq_head *dep; /* Linked list of slots, indexed by depth */
+};
+
+/* This contains the info we will hash. */
+struct esfq_packet_info
+{
+ u32 proto; /* protocol or port */
+ u32 src; /* source from packet header */
+ u32 dst; /* destination from packet header */
+ u32 ctorigsrc; /* original source from conntrack */
+ u32 ctorigdst; /* original destination from conntrack */
+ u32 ctreplsrc; /* reply source from conntrack */
+ u32 ctrepldst; /* reply destination from conntrack */
+ u32 mark; /* netfilter mark (fwmark) */
+};
+
+static __inline__ unsigned esfq_jhash_1word(struct esfq_sched_data *q,u32 a)
+{
+ return jhash_1word(a, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_2words(struct esfq_sched_data *q, u32 a, u32 b)
+{
+ return jhash_2words(a, b, q->perturbation) & (q->hash_divisor-1);
+}
+
+static __inline__ unsigned esfq_jhash_3words(struct esfq_sched_data *q, u32 a, u32 b, u32 c)
+{
+ return jhash_3words(a, b, c, q->perturbation) & (q->hash_divisor-1);
+}
+
+static unsigned esfq_hash(struct esfq_sched_data *q, struct sk_buff *skb)
+{
+ struct esfq_packet_info info;
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ enum ip_conntrack_info ctinfo;
+ struct nf_conn *ct = nf_ct_get(skb, &ctinfo);
+#endif
+
+ switch (skb->protocol) {
+ case __constant_htons(ETH_P_IP):
+ {
+ struct iphdr *iph = ip_hdr(skb);
+ info.dst = iph->daddr;
+ info.src = iph->saddr;
+ if (!(iph->frag_off&htons(IP_MF|IP_OFFSET)) &&
+ (iph->protocol == IPPROTO_TCP ||
+ iph->protocol == IPPROTO_UDP ||
+ iph->protocol == IPPROTO_SCTP ||
+ iph->protocol == IPPROTO_DCCP ||
+ iph->protocol == IPPROTO_ESP))
+ info.proto = *(((u32*)iph) + iph->ihl);
+ else
+ info.proto = iph->protocol;
+ break;
+ }
+ case __constant_htons(ETH_P_IPV6):
+ {
+ struct ipv6hdr *iph = ipv6_hdr(skb);
+ /* Hash ipv6 addresses into a u32. This isn't ideal,
+ * but the code is simple. */
+ info.dst = jhash2(iph->daddr.s6_addr32, 4, q->perturbation);
+ info.src = jhash2(iph->saddr.s6_addr32, 4, q->perturbation);
+ if (iph->nexthdr == IPPROTO_TCP ||
+ iph->nexthdr == IPPROTO_UDP ||
+ iph->nexthdr == IPPROTO_SCTP ||
+ iph->nexthdr == IPPROTO_DCCP ||
+ iph->nexthdr == IPPROTO_ESP)
+ info.proto = *(u32*)&iph[1];
+ else
+ info.proto = iph->nexthdr;
+ break;
+ }
+ default:
+ info.dst = (u32)(unsigned long)skb->dst;
+ info.src = (u32)(unsigned long)skb->sk;
+ info.proto = skb->protocol;
+ }
+
+ info.mark = skb->mark;
+
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ /* defaults if there is no conntrack info */
+ info.ctorigsrc = info.src;
+ info.ctorigdst = info.dst;
+ info.ctreplsrc = info.dst;
+ info.ctrepldst = info.src;
+ /* collect conntrack info */
+ if (ct && ct != &nf_conntrack_untracked) {
+ if (skb->protocol == __constant_htons(ETH_P_IP)) {
+ info.ctorigsrc = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip;
+ info.ctorigdst = ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip;
+ info.ctreplsrc = ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip;
+ info.ctrepldst = ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip;
+ }
+ else if (skb->protocol == __constant_htons(ETH_P_IPV6)) {
+ /* Again, hash ipv6 addresses into a single u32. */
+ info.ctorigsrc = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip6, 4, q->perturbation);
+ info.ctorigdst = jhash2(ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.dst.u3.ip6, 4, q->perturbation);
+ info.ctreplsrc = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.src.u3.ip6, 4, q->perturbation);
+ info.ctrepldst = jhash2(ct->tuplehash[IP_CT_DIR_REPLY].tuple.dst.u3.ip6, 4, q->perturbation);
+ }
+
+ }
+#endif
+
+ switch(q->hash_kind) {
+ case TCA_SFQ_HASH_CLASSIC:
+ return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+ case TCA_SFQ_HASH_DST:
+ return esfq_jhash_1word(q, info.dst);
+ case TCA_SFQ_HASH_SRC:
+ return esfq_jhash_1word(q, info.src);
+ case TCA_SFQ_HASH_FWMARK:
+ return esfq_jhash_1word(q, info.mark);
+#ifdef CONFIG_NET_SCH_ESFQ_NFCT
+ case TCA_SFQ_HASH_CTORIGDST:
+ return esfq_jhash_1word(q, info.ctorigdst);
+ case TCA_SFQ_HASH_CTORIGSRC:
+ return esfq_jhash_1word(q, info.ctorigsrc);
+ case TCA_SFQ_HASH_CTREPLDST:
+ return esfq_jhash_1word(q, info.ctrepldst);
+ case TCA_SFQ_HASH_CTREPLSRC:
+ return esfq_jhash_1word(q, info.ctreplsrc);
+ case TCA_SFQ_HASH_CTNATCHG:
+ {
+ if (info.ctorigdst == info.ctreplsrc)
+ return esfq_jhash_1word(q, info.ctorigsrc);
+ return esfq_jhash_1word(q, info.ctreplsrc);
+ }
+#endif
+ default:
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Unknown hash method. Falling back to classic.\n");
+ }
+ return esfq_jhash_3words(q, info.dst, info.src, info.proto);
+}
+
+static inline void esfq_link(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+ int d = q->qs[x].qlen + q->depth;
+
+ p = d;
+ n = q->dep[d].next;
+ q->dep[x].next = n;
+ q->dep[x].prev = p;
+ q->dep[p].next = q->dep[n].prev = x;
+}
+
+static inline void esfq_dec(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+
+ n = q->dep[x].next;
+ p = q->dep[x].prev;
+ q->dep[p].next = n;
+ q->dep[n].prev = p;
+
+ if (n == p && q->max_depth == q->qs[x].qlen + 1)
+ q->max_depth--;
+
+ esfq_link(q, x);
+}
+
+static inline void esfq_inc(struct esfq_sched_data *q, esfq_index x)
+{
+ esfq_index p, n;
+ int d;
+
+ n = q->dep[x].next;
+ p = q->dep[x].prev;
+ q->dep[p].next = n;
+ q->dep[n].prev = p;
+ d = q->qs[x].qlen;
+ if (q->max_depth < d)
+ q->max_depth = d;
+
+ esfq_link(q, x);
+}
+
+static unsigned int esfq_drop(struct Qdisc *sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_index d = q->max_depth;
+ struct sk_buff *skb;
+ unsigned int len;
+
+ /* Queue is full! Find the longest slot and
+ drop a packet from it */
+
+ if (d > 1) {
+ esfq_index x = q->dep[d+q->depth].next;
+ skb = q->qs[x].prev;
+ len = skb->len;
+ __skb_unlink(skb, &q->qs[x]);
+ kfree_skb(skb);
+ esfq_dec(q, x);
+ sch->q.qlen--;
+ sch->qstats.drops++;
+ sch->qstats.backlog -= len;
+ return len;
+ }
+
+ if (d == 1) {
+ /* It is difficult to believe, but ALL THE SLOTS HAVE LENGTH 1. */
+ d = q->next[q->tail];
+ q->next[q->tail] = q->next[d];
+ q->allot[q->next[d]] += q->quantum;
+ skb = q->qs[d].prev;
+ len = skb->len;
+ __skb_unlink(skb, &q->qs[d]);
+ kfree_skb(skb);
+ esfq_dec(q, d);
+ sch->q.qlen--;
+ q->ht[q->hash[d]] = q->depth;
+ sch->qstats.drops++;
+ sch->qstats.backlog -= len;
+ return len;
+ }
+
+ return 0;
+}
+
+static void esfq_q_enqueue(struct sk_buff *skb, struct esfq_sched_data *q, unsigned int end)
+{
+ unsigned hash = esfq_hash(q, skb);
+ unsigned depth = q->depth;
+ esfq_index x;
+
+ x = q->ht[hash];
+ if (x == depth) {
+ q->ht[hash] = x = q->dep[depth].next;
+ q->hash[x] = hash;
+ }
+
+ if (end == ESFQ_TAIL)
+ __skb_queue_tail(&q->qs[x], skb);
+ else
+ __skb_queue_head(&q->qs[x], skb);
+
+ esfq_inc(q, x);
+ if (q->qs[x].qlen == 1) { /* The flow is new */
+ if (q->tail == depth) { /* It is the first flow */
+ q->tail = x;
+ q->next[x] = x;
+ q->allot[x] = q->quantum;
+ } else {
+ q->next[x] = q->next[q->tail];
+ q->next[q->tail] = x;
+ q->tail = x;
+ }
+ }
+}
+
+static int esfq_enqueue(struct sk_buff *skb, struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_q_enqueue(skb, q, ESFQ_TAIL);
+ sch->qstats.backlog += skb->len;
+ if (++sch->q.qlen < q->limit-1) {
+ sch->bstats.bytes += skb->len;
+ sch->bstats.packets++;
+ return 0;
+ }
+
+ sch->qstats.drops++;
+ esfq_drop(sch);
+ return NET_XMIT_CN;
+}
+
+
+static int esfq_requeue(struct sk_buff *skb, struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_q_enqueue(skb, q, ESFQ_HEAD);
+ sch->qstats.backlog += skb->len;
+ if (++sch->q.qlen < q->limit - 1) {
+ sch->qstats.requeues++;
+ return 0;
+ }
+
+ sch->qstats.drops++;
+ esfq_drop(sch);
+ return NET_XMIT_CN;
+}
+
+static struct sk_buff *esfq_q_dequeue(struct esfq_sched_data *q)
+{
+ struct sk_buff *skb;
+ unsigned depth = q->depth;
+ esfq_index a, old_a;
+
+ /* No active slots */
+ if (q->tail == depth)
+ return NULL;
+
+ a = old_a = q->next[q->tail];
+
+ /* Grab packet */
+ skb = __skb_dequeue(&q->qs[a]);
+ esfq_dec(q, a);
+
+ /* Is the slot empty? */
+ if (q->qs[a].qlen == 0) {
+ q->ht[q->hash[a]] = depth;
+ a = q->next[a];
+ if (a == old_a) {
+ q->tail = depth;
+ return skb;
+ }
+ q->next[q->tail] = a;
+ q->allot[a] += q->quantum;
+ } else if ((q->allot[a] -= skb->len) <= 0) {
+ q->tail = a;
+ a = q->next[a];
+ q->allot[a] += q->quantum;
+ }
+
+ return skb;
+}
+
+static struct sk_buff *esfq_dequeue(struct Qdisc* sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ struct sk_buff *skb;
+
+ skb = esfq_q_dequeue(q);
+ if (skb == NULL)
+ return NULL;
+ sch->q.qlen--;
+ sch->qstats.backlog -= skb->len;
+ return skb;
+}
+
+static void esfq_q_destroy(struct esfq_sched_data *q)
+{
+ del_timer(&q->perturb_timer);
+ if(q->ht)
+ kfree(q->ht);
+ if(q->dep)
+ kfree(q->dep);
+ if(q->next)
+ kfree(q->next);
+ if(q->allot)
+ kfree(q->allot);
+ if(q->hash)
+ kfree(q->hash);
+ if(q->qs)
+ kfree(q->qs);
+}
+
+static void esfq_destroy(struct Qdisc *sch)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ esfq_q_destroy(q);
+}
+
+
+static void esfq_reset(struct Qdisc* sch)
+{
+ struct sk_buff *skb;
+
+ while ((skb = esfq_dequeue(sch)) != NULL)
+ kfree_skb(skb);
+}
+
+static void esfq_perturbation(unsigned long arg)
+{
+ struct Qdisc *sch = (struct Qdisc*)arg;
+ struct esfq_sched_data *q = qdisc_priv(sch);
+
+ q->perturbation = net_random()&0x1F;
+
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ }
+}
+
+static unsigned int esfq_check_hash(unsigned int kind)
+{
+ switch (kind) {
+ case TCA_SFQ_HASH_CTORIGDST:
+ case TCA_SFQ_HASH_CTORIGSRC:
+ case TCA_SFQ_HASH_CTREPLDST:
+ case TCA_SFQ_HASH_CTREPLSRC:
+ case TCA_SFQ_HASH_CTNATCHG:
+#ifndef CONFIG_NET_SCH_ESFQ_NFCT
+ {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Conntrack hash types disabled in kernel config. Falling back to classic.\n");
+ return TCA_SFQ_HASH_CLASSIC;
+ }
+#endif
+ case TCA_SFQ_HASH_CLASSIC:
+ case TCA_SFQ_HASH_DST:
+ case TCA_SFQ_HASH_SRC:
+ case TCA_SFQ_HASH_FWMARK:
+ return kind;
+ default:
+ {
+ if (net_ratelimit())
+ printk(KERN_WARNING "ESFQ: Unknown hash type. Falling back to classic.\n");
+ return TCA_SFQ_HASH_CLASSIC;
+ }
+ }
+}
+
+static int esfq_q_init(struct esfq_sched_data *q, struct rtattr *opt)
+{
+ struct tc_esfq_qopt *ctl = RTA_DATA(opt);
+ esfq_index p = ~0U/2;
+ int i;
+
+ if (opt && opt->rta_len < RTA_LENGTH(sizeof(*ctl)))
+ return -EINVAL;
+
+ q->perturbation = 0;
+ q->hash_kind = TCA_SFQ_HASH_CLASSIC;
+ q->max_depth = 0;
+ if (opt == NULL) {
+ q->perturb_period = 0;
+ q->hash_divisor = 1024;
+ q->tail = q->limit = q->depth = 128;
+
+ } else {
+ struct tc_esfq_qopt *ctl = RTA_DATA(opt);
+ if (ctl->quantum)
+ q->quantum = ctl->quantum;
+ q->perturb_period = ctl->perturb_period*HZ;
+ q->hash_divisor = ctl->divisor ? : 1024;
+ q->tail = q->limit = q->depth = ctl->flows ? : 128;
+
+ if ( q->depth > p - 1 )
+ return -EINVAL;
+
+ if (ctl->limit)
+ q->limit = min_t(u32, ctl->limit, q->depth);
+
+ if (ctl->hash_kind) {
+ q->hash_kind = esfq_check_hash(ctl->hash_kind);
+ }
+ }
+
+ q->ht = kmalloc(q->hash_divisor*sizeof(esfq_index), GFP_KERNEL);
+ if (!q->ht)
+ goto err_case;
+ q->dep = kmalloc((1+q->depth*2)*sizeof(struct esfq_head), GFP_KERNEL);
+ if (!q->dep)
+ goto err_case;
+ q->next = kmalloc(q->depth*sizeof(esfq_index), GFP_KERNEL);
+ if (!q->next)
+ goto err_case;
+ q->allot = kmalloc(q->depth*sizeof(short), GFP_KERNEL);
+ if (!q->allot)
+ goto err_case;
+ q->hash = kmalloc(q->depth*sizeof(unsigned short), GFP_KERNEL);
+ if (!q->hash)
+ goto err_case;
+ q->qs = kmalloc(q->depth*sizeof(struct sk_buff_head), GFP_KERNEL);
+ if (!q->qs)
+ goto err_case;
+
+ for (i=0; i< q->hash_divisor; i++)
+ q->ht[i] = q->depth;
+ for (i=0; i<q->depth; i++) {
+ skb_queue_head_init(&q->qs[i]);
+ q->dep[i+q->depth].next = i+q->depth;
+ q->dep[i+q->depth].prev = i+q->depth;
+ }
+
+ for (i=0; i<q->depth; i++)
+ esfq_link(q, i);
+ return 0;
+err_case:
+ esfq_q_destroy(q);
+ return -ENOBUFS;
+}
+
+static int esfq_init(struct Qdisc *sch, struct rtattr *opt)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ int err;
+
+ q->quantum = psched_mtu(qdisc_dev(sch)); /* default */
+ if ((err = esfq_q_init(q, opt)))
+ return err;
+
+ init_timer(&q->perturb_timer);
+ q->perturb_timer.data = (unsigned long)sch;
+ q->perturb_timer.function = esfq_perturbation;
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ }
+
+ return 0;
+}
+
+static int esfq_change(struct Qdisc *sch, struct rtattr *opt)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ struct esfq_sched_data new;
+ struct sk_buff *skb;
+ int err;
+
+ /* set up new queue */
+ memset(&new, 0, sizeof(struct esfq_sched_data));
+ new.quantum = psched_mtu(qdisc_dev(sch)); /* default */
+ if ((err = esfq_q_init(&new, opt)))
+ return err;
+
+ /* copy all packets from the old queue to the new queue */
+ sch_tree_lock(sch);
+ while ((skb = esfq_q_dequeue(q)) != NULL)
+ esfq_q_enqueue(skb, &new, ESFQ_TAIL);
+
+ /* clean up the old queue */
+ esfq_q_destroy(q);
+
+ /* copy elements of the new queue into the old queue */
+ q->perturb_period = new.perturb_period;
+ q->quantum = new.quantum;
+ q->limit = new.limit;
+ q->depth = new.depth;
+ q->hash_divisor = new.hash_divisor;
+ q->hash_kind = new.hash_kind;
+ q->tail = new.tail;
+ q->max_depth = new.max_depth;
+ q->ht = new.ht;
+ q->dep = new.dep;
+ q->next = new.next;
+ q->allot = new.allot;
+ q->hash = new.hash;
+ q->qs = new.qs;
+
+ /* finish up */
+ if (q->perturb_period) {
+ q->perturb_timer.expires = jiffies + q->perturb_period;
+ add_timer(&q->perturb_timer);
+ } else {
+ q->perturbation = 0;
+ }
+ sch_tree_unlock(sch);
+ return 0;
+}
+
+static int esfq_dump(struct Qdisc *sch, struct sk_buff *skb)
+{
+ struct esfq_sched_data *q = qdisc_priv(sch);
+ unsigned char *b = skb->tail;
+ struct tc_esfq_qopt opt;
+
+ opt.quantum = q->quantum;
+ opt.perturb_period = q->perturb_period/HZ;
+
+ opt.limit = q->limit;
+ opt.divisor = q->hash_divisor;
+ opt.flows = q->depth;
+ opt.hash_kind = q->hash_kind;
+
+ RTA_PUT(skb, TCA_OPTIONS, sizeof(opt), &opt);
+
+ return skb->len;
+
+rtattr_failure:
+ skb_trim(skb, b - skb->data);
+ return -1;
+}
+
+static struct Qdisc_ops esfq_qdisc_ops =
+{
+ .next = NULL,
+ .cl_ops = NULL,
+ .id = "esfq",
+ .priv_size = sizeof(struct esfq_sched_data),
+ .enqueue = esfq_enqueue,
+ .dequeue = esfq_dequeue,
+ .requeue = esfq_requeue,
+ .drop = esfq_drop,
+ .init = esfq_init,
+ .reset = esfq_reset,
+ .destroy = esfq_destroy,
+ .change = esfq_change,
+ .dump = esfq_dump,
+ .owner = THIS_MODULE,
+};
+
+static int __init esfq_module_init(void)
+{
+ return register_qdisc(&esfq_qdisc_ops);
+}
+static void __exit esfq_module_exit(void)
+{
+ unregister_qdisc(&esfq_qdisc_ops);
+}
+module_init(esfq_module_init)
+module_exit(esfq_module_exit)
+MODULE_LICENSE("GPL");

View file

@ -0,0 +1,12 @@
--- a/arch/mips/Makefile
+++ b/arch/mips/Makefile
@@ -586,6 +586,9 @@ core-$(CONFIG_TOSHIBA_RBTX4927) += arch/
core-$(CONFIG_TOSHIBA_RBTX4938) += arch/mips/txx9/rbtx4938/
core-$(CONFIG_TOSHIBA_RBTX4939) += arch/mips/txx9/rbtx4939/
+# temporary until string.h is fixed
+cflags-y += -ffreestanding
+
cflags-y += -I$(srctree)/arch/mips/include/asm/mach-generic
drivers-$(CONFIG_PCI) += arch/mips/pci/

View file

@ -0,0 +1,132 @@
--- a/fs/jffs2/build.c
+++ b/fs/jffs2/build.c
@@ -111,6 +111,17 @@ static int jffs2_build_filesystem(struct
dbg_fsbuild("scanned flash completely\n");
jffs2_dbg_dump_block_lists_nolock(c);
+ if (c->flags & (1 << 7)) {
+ printk("%s(): unlocking the mtd device... ", __func__);
+ if (c->mtd->unlock)
+ c->mtd->unlock(c->mtd, 0, c->mtd->size);
+ printk("done.\n");
+
+ printk("%s(): erasing all blocks after the end marker... ", __func__);
+ jffs2_erase_pending_blocks(c, -1);
+ printk("done.\n");
+ }
+
dbg_fsbuild("pass 1 starting\n");
c->flags |= JFFS2_SB_FLAG_BUILDING;
/* Now scan the directory tree, increasing nlink according to every dirent found. */
--- a/fs/jffs2/scan.c
+++ b/fs/jffs2/scan.c
@@ -72,7 +72,7 @@ static int file_dirty(struct jffs2_sb_in
return ret;
if ((ret = jffs2_scan_dirty_space(c, jeb, jeb->free_size)))
return ret;
- /* Turned wasted size into dirty, since we apparently
+ /* Turned wasted size into dirty, since we apparently
think it's recoverable now. */
jeb->dirty_size += jeb->wasted_size;
c->dirty_size += jeb->wasted_size;
@@ -144,8 +144,11 @@ int jffs2_scan_medium(struct jffs2_sb_in
/* reset summary info for next eraseblock scan */
jffs2_sum_reset_collected(s);
- ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
- buf_size, s);
+ if (c->flags & (1 << 7))
+ ret = BLK_STATE_ALLFF;
+ else
+ ret = jffs2_scan_eraseblock(c, jeb, buf_size?flashbuf:(flashbuf+jeb->offset),
+ buf_size, s);
if (ret < 0)
goto out;
@@ -400,7 +403,7 @@ static int jffs2_scan_xref_node(struct j
if (!ref)
return -ENOMEM;
- /* BEFORE jffs2_build_xattr_subsystem() called,
+ /* BEFORE jffs2_build_xattr_subsystem() called,
* and AFTER xattr_ref is marked as a dead xref,
* ref->xid is used to store 32bit xid, xd is not used
* ref->ino is used to store 32bit inode-number, ic is not used
@@ -473,7 +476,7 @@ static int jffs2_scan_eraseblock (struct
struct jffs2_sum_marker *sm;
void *sumptr = NULL;
uint32_t sumlen;
-
+
if (!buf_size) {
/* XIP case. Just look, point at the summary if it's there */
sm = (void *)buf + c->sector_size - sizeof(*sm);
@@ -489,9 +492,9 @@ static int jffs2_scan_eraseblock (struct
buf_len = sizeof(*sm);
/* Read as much as we want into the _end_ of the preallocated buffer */
- err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
+ err = jffs2_fill_scan_buf(c, buf + buf_size - buf_len,
jeb->offset + c->sector_size - buf_len,
- buf_len);
+ buf_len);
if (err)
return err;
@@ -510,9 +513,9 @@ static int jffs2_scan_eraseblock (struct
}
if (buf_len < sumlen) {
/* Need to read more so that the entire summary node is present */
- err = jffs2_fill_scan_buf(c, sumptr,
+ err = jffs2_fill_scan_buf(c, sumptr,
jeb->offset + c->sector_size - sumlen,
- sumlen - buf_len);
+ sumlen - buf_len);
if (err)
return err;
}
@@ -525,7 +528,7 @@ static int jffs2_scan_eraseblock (struct
if (buf_size && sumlen > buf_size)
kfree(sumptr);
- /* If it returns with a real error, bail.
+ /* If it returns with a real error, bail.
If it returns positive, that's a block classification
(i.e. BLK_STATE_xxx) so return that too.
If it returns zero, fall through to full scan. */
@@ -546,6 +549,17 @@ static int jffs2_scan_eraseblock (struct
return err;
}
+ if ((buf[0] == 0xde) &&
+ (buf[1] == 0xad) &&
+ (buf[2] == 0xc0) &&
+ (buf[3] == 0xde)) {
+ /* end of filesystem. erase everything after this point */
+ printk("%s(): End of filesystem marker found at 0x%x\n", __func__, jeb->offset);
+ c->flags |= (1 << 7);
+
+ return BLK_STATE_ALLFF;
+ }
+
/* We temporarily use 'ofs' as a pointer into the buffer/jeb */
ofs = 0;
@@ -671,7 +685,7 @@ scan_more:
scan_end = buf_len;
goto more_empty;
}
-
+
/* See how much more there is to read in this eraseblock... */
buf_len = min_t(uint32_t, buf_size, jeb->offset + c->sector_size - ofs);
if (!buf_len) {
@@ -907,7 +921,7 @@ scan_more:
D1(printk(KERN_DEBUG "Block at 0x%08x: free 0x%08x, dirty 0x%08x, unchecked 0x%08x, used 0x%08x, wasted 0x%08x\n",
jeb->offset,jeb->free_size, jeb->dirty_size, jeb->unchecked_size, jeb->used_size, jeb->wasted_size));
-
+
/* mark_node_obsolete can add to wasted !! */
if (jeb->wasted_size) {
jeb->dirty_size += jeb->wasted_size;

View file

@ -0,0 +1,9 @@
--- /dev/null
+++ b/include/asm-powerpc/segment.h
@@ -0,0 +1,6 @@
+#ifndef _ASM_SEGMENT_H
+#define _ASM_SEGMENT_H
+
+/* Only here because we have some old header files that expect it.. */
+
+#endif /* _ASM_SEGMENT_H */

View file

@ -0,0 +1,42 @@
--- a/drivers/net/r8169.c
+++ b/drivers/net/r8169.c
@@ -1862,7 +1862,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8169,
.region = 1,
.align = 0,
- .intr_event = SYSErr | LinkChg | RxOverflow |
+ .intr_event = LinkChg | RxOverflow |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII
@@ -1871,7 +1871,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8168,
.region = 2,
.align = 8,
- .intr_event = SYSErr | LinkChg | RxOverflow |
+ .intr_event = LinkChg | RxOverflow |
TxErr | TxOK | RxOK | RxErr,
.napi_event = TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_GMII | RTL_FEATURE_MSI
@@ -1880,7 +1880,7 @@ static const struct rtl_cfg_info {
.hw_start = rtl_hw_start_8101,
.region = 2,
.align = 8,
- .intr_event = SYSErr | LinkChg | RxOverflow | PCSTimeout |
+ .intr_event = LinkChg | RxOverflow | PCSTimeout |
RxFIFOOver | TxErr | TxOK | RxOK | RxErr,
.napi_event = RxFIFOOver | TxErr | TxOK | RxOK | RxOverflow,
.features = RTL_FEATURE_MSI
@@ -3554,10 +3554,12 @@ static irqreturn_t rtl8169_interrupt(int
goto out;
}
+#if 0
if (unlikely(status & SYSErr)) {
rtl8169_pcierr_interrupt(dev);
goto out;
}
+#endif
if (status & LinkChg)
rtl8169_check_link_status(dev, tp, ioaddr);

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,143 @@
--- a/fs/mini_fo/main.c
+++ b/fs/mini_fo/main.c
@@ -79,6 +79,7 @@ mini_fo_tri_interpose(dentry_t *hidden_d
* of the new inode's fields
*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
/*
* original: inode = iget(sb, hidden_inode->i_ino);
*/
@@ -87,6 +88,13 @@ mini_fo_tri_interpose(dentry_t *hidden_d
err = -EACCES; /* should be impossible??? */
goto out;
}
+#else
+ inode = mini_fo_iget(sb, iunique(sb, 25));
+ if (IS_ERR(inode)) {
+ err = PTR_ERR(inode);
+ goto out;
+ }
+#endif
/*
* interpose the inode if not already interposed
@@ -184,9 +192,9 @@ mini_fo_parse_options(super_block_t *sb,
hidden_root = ERR_PTR(err);
goto out;
}
- hidden_root = nd.dentry;
- stopd(sb)->base_dir_dentry = nd.dentry;
- stopd(sb)->hidden_mnt = nd.mnt;
+ hidden_root = nd_get_dentry(&nd);
+ stopd(sb)->base_dir_dentry = nd_get_dentry(&nd);
+ stopd(sb)->hidden_mnt = nd_get_mnt(&nd);
} else if(!strncmp("sto=", options, 4)) {
/* parse the storage dir */
@@ -204,9 +212,9 @@ mini_fo_parse_options(super_block_t *sb,
hidden_root2 = ERR_PTR(err);
goto out;
}
- hidden_root2 = nd2.dentry;
- stopd(sb)->storage_dir_dentry = nd2.dentry;
- stopd(sb)->hidden_mnt2 = nd2.mnt;
+ hidden_root2 = nd_get_dentry(&nd2);
+ stopd(sb)->storage_dir_dentry = nd_get_dentry(&nd2);
+ stopd(sb)->hidden_mnt2 = nd_get_mnt(&nd2);
stohs2(sb) = hidden_root2->d_sb;
/* validate storage dir, this is done in
--- a/fs/mini_fo/mini_fo.h
+++ b/fs/mini_fo/mini_fo.h
@@ -302,6 +302,10 @@ extern int mini_fo_tri_interpose(dentry_
extern int mini_fo_cp_cont(dentry_t *tgt_dentry, struct vfsmount *tgt_mnt,
dentry_t *src_dentry, struct vfsmount *src_mnt);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+extern struct inode *mini_fo_iget(struct super_block *sb, unsigned long ino);
+#endif
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
extern int mini_fo_create(inode_t *dir, dentry_t *dentry, int mode, struct nameidata *nd);
@@ -501,6 +505,29 @@ static inline void double_unlock(struct
#endif /* if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) */
#endif /* __KERNEL__ */
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+static inline dentry_t *nd_get_dentry(struct nameidata *nd)
+{
+ return (nd->path.dentry);
+}
+
+static inline struct vfsmount *nd_get_mnt(struct nameidata *nd)
+{
+ return (nd->path.mnt);
+}
+#else
+static inline dentry_t *nd_get_dentry(struct nameidata *nd)
+{
+ return (nd->dentry);
+}
+
+static inline struct vfsmount *nd_get_mnt(struct nameidata *nd)
+{
+ return (nd->mnt);
+}
+#endif
+
/*
* Definitions for user and kernel code
*/
--- a/fs/mini_fo/super.c
+++ b/fs/mini_fo/super.c
@@ -262,10 +262,31 @@ mini_fo_umount_begin(super_block_t *sb)
}
#endif
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
+struct inode *
+mini_fo_iget(struct super_block *sb, unsigned long ino)
+{
+ struct inode *inode;
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ mini_fo_read_inode(inode);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+#endif /* if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25) */
struct super_operations mini_fo_sops =
{
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
read_inode: mini_fo_read_inode,
+#endif
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
write_inode: mini_fo_write_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
--- a/fs/mini_fo/aux.c
+++ b/fs/mini_fo/aux.c
@@ -164,11 +164,11 @@ dentry_t *bpath_walk(super_block_t *sb,
err = vfs_path_lookup(mnt->mnt_root, mnt, bpath+1, 0, &nd);
/* validate */
- if (err || !nd.dentry || !nd.dentry->d_inode) {
+ if (err || !nd_get_dentry(&nd) || !nd_get_dentry(&nd)->d_inode) {
printk(KERN_CRIT "mini_fo: bpath_walk: path_walk failed.\n");
return NULL;
}
- return nd.dentry;
+ return nd_get_dentry(&nd);
}

View file

@ -0,0 +1,66 @@
--- a/fs/mini_fo/meta.c
+++ b/fs/mini_fo/meta.c
@@ -442,6 +442,11 @@ int meta_write_d_entry(dentry_t *dentry,
S_IRUSR | S_IWUSR);
#endif
}
+
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
@@ -535,6 +540,11 @@ int meta_write_r_entry(dentry_t *dentry,
meta_dentry, S_IRUSR | S_IWUSR);
#endif
}
+
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
@@ -671,14 +681,16 @@ int meta_sync_d_list(dentry_t *dentry, i
}
}
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_d_list: \
ERROR opening meta file.\n");
- /* we don't mntget so we dont't mntput (for now)
- * mntput(meta_mnt);
- */
+ mntput(meta_mnt);
dput(meta_dentry);
err = -1;
goto out;
@@ -811,14 +823,16 @@ int meta_sync_r_list(dentry_t *dentry, i
}
}
+ /* $%& err, is this correct? */
+ meta_mnt = stopd(dentry->d_inode->i_sb)->hidden_mnt2;
+ mntget(meta_mnt);
+
/* open META-file for writing */
meta_file = dentry_open(meta_dentry, meta_mnt, 0x1);
if(!meta_file || IS_ERR(meta_file)) {
printk(KERN_CRIT "mini_fo: meta_sync_r_list: \
ERROR opening meta file.\n");
- /* we don't mntget so we dont't mntput (for now)
- * mntput(meta_mnt);
- */
+ mntput(meta_mnt);
dput(meta_dentry);
err = -1;
goto out;

View file

@ -0,0 +1,37 @@
--- a/fs/mini_fo/super.c
+++ b/fs/mini_fo/super.c
@@ -84,6 +84,7 @@ mini_fo_write_inode(inode_t *inode, int
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
STATIC void
mini_fo_put_inode(inode_t *inode)
{
@@ -99,6 +100,7 @@ mini_fo_put_inode(inode_t *inode)
if (atomic_read(&inode->i_count) == 1)
inode->i_nlink = 0;
}
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) */
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
@@ -238,7 +240,7 @@ mini_fo_clear_inode(inode_t *inode)
* dies.
*/
STATIC void
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,18)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
mini_fo_umount_begin(struct vfsmount *mnt, int flags)
{
struct vfsmount *hidden_mnt;
@@ -290,7 +292,9 @@ struct super_operations mini_fo_sops =
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
write_inode: mini_fo_write_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
put_inode: mini_fo_put_inode,
+#endif /* LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26) */
#if defined(FIST_DEBUG) || defined(FIST_FILTER_SCA)
delete_inode: mini_fo_delete_inode,
#endif /* defined(FIST_DEBUG) || defined(FIST_FILTER_SCA) */

View file

@ -0,0 +1,41 @@
--- a/fs/mini_fo/inode.c
+++ b/fs/mini_fo/inode.c
@@ -439,7 +439,7 @@ mini_fo_symlink(inode_t *dir, dentry_t *
int err=0;
dentry_t *hidden_sto_dentry;
dentry_t *hidden_sto_dir_dentry;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
umode_t mode;
#endif
@@ -466,7 +466,7 @@ mini_fo_symlink(inode_t *dir, dentry_t *
down(&hidden_sto_dir_dentry->d_inode->i_sem);
#endif
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
mode = S_IALLUGO;
err = vfs_symlink(hidden_sto_dir_dentry->d_inode,
hidden_sto_dentry, symname, mode);
@@ -1128,7 +1128,7 @@ void mini_fo_put_link(struct dentry *den
#endif
STATIC int
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)) && (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27))
mini_fo_permission(inode_t *inode, int mask, struct nameidata *nd)
#else
mini_fo_permission(inode_t *inode, int mask)
@@ -1150,8 +1150,9 @@ mini_fo_permission(inode_t *inode, int m
* if (err)
* goto out;
*/
-
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,27)
+ err = inode_permission(hidden_inode, mask);
+#elif LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
err = permission(hidden_inode, mask, nd);
#else
err = permission(hidden_inode, mask);

View file

@ -0,0 +1,42 @@
--- a/lib/kobject_uevent.c
+++ b/lib/kobject_uevent.c
@@ -29,7 +29,8 @@ u64 uevent_seqnum;
char uevent_helper[UEVENT_HELPER_PATH_LEN] = CONFIG_UEVENT_HELPER_PATH;
static DEFINE_SPINLOCK(sequence_lock);
#if defined(CONFIG_NET)
-static struct sock *uevent_sock;
+struct sock *uevent_sock = NULL;
+EXPORT_SYMBOL_GPL(uevent_sock);
#endif
/* the strings here must match the enum in include/linux/kobject.h */
@@ -42,6 +43,18 @@ static const char *kobject_actions[] = {
[KOBJ_OFFLINE] = "offline",
};
+u64 uevent_next_seqnum(void)
+{
+ u64 seq;
+
+ spin_lock(&sequence_lock);
+ seq = ++uevent_seqnum;
+ spin_unlock(&sequence_lock);
+
+ return seq;
+}
+EXPORT_SYMBOL_GPL(uevent_next_seqnum);
+
/**
* kobject_action_type - translate action string to numeric type
*
@@ -194,9 +207,7 @@ int kobject_uevent_env(struct kobject *k
kobj->state_remove_uevent_sent = 1;
/* we will send an event, so request a new sequence number */
- spin_lock(&sequence_lock);
- seq = ++uevent_seqnum;
- spin_unlock(&sequence_lock);
+ seq = uevent_next_seqnum();
retval = add_uevent_var(env, "SEQNUM=%llu", (unsigned long long)seq);
if (retval)
goto exit;

View file

@ -0,0 +1,11 @@
--- a/sound/core/Kconfig
+++ b/sound/core/Kconfig
@@ -7,7 +7,7 @@ config SND_PCM
select SND_TIMER
config SND_HWDEP
- tristate
+ tristate "Sound hardware support"
config SND_RAWMIDI
tristate

View file

@ -0,0 +1,18 @@
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -217,4 +217,8 @@ config LEDS_TRIGGER_DEFAULT_ON
This allows LEDs to be initialised in the ON state.
If unsure, say Y.
+config LEDS_TRIGGER_MORSE
+ tristate "LED Morse Trigger"
+ depends on LEDS_TRIGGERS
+
endif # NEW_LEDS
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -30,3 +30,4 @@ obj-$(CONFIG_LEDS_TRIGGER_IDE_DISK) += l
obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) += ledtrig-heartbeat.o
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
+obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o

View file

@ -0,0 +1,25 @@
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -63,6 +63,12 @@ config LEDS_WRAP
help
This option enables support for the PCEngines WRAP programmable LEDs.
+config LEDS_ALIX
+ tristate "LED Support for the ALIX 2/3 boards"
+ depends on LEDS_CLASS
+ help
+ This option enables support for the three LEDs on the PCEngines ALIX 2/3 boards.
+
config LEDS_H1940
tristate "LED Support for iPAQ H1940 device"
depends on LEDS_CLASS && ARCH_H1940
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -11,6 +11,7 @@ obj-$(CONFIG_LEDS_S3C24XX) += leds-s3c2
obj-$(CONFIG_LEDS_AMS_DELTA) += leds-ams-delta.o
obj-$(CONFIG_LEDS_NET48XX) += leds-net48xx.o
obj-$(CONFIG_LEDS_WRAP) += leds-wrap.o
+obj-$(CONFIG_LEDS_ALIX) += leds-alix.o
obj-$(CONFIG_LEDS_H1940) += leds-h1940.o
obj-$(CONFIG_LEDS_COBALT_QUBE) += leds-cobalt-qube.o
obj-$(CONFIG_LEDS_COBALT_RAQ) += leds-cobalt-raq.o

View file

@ -0,0 +1,21 @@
--- a/drivers/leds/Kconfig
+++ b/drivers/leds/Kconfig
@@ -227,4 +227,11 @@ config LEDS_TRIGGER_MORSE
tristate "LED Morse Trigger"
depends on LEDS_TRIGGERS
+config LEDS_TRIGGER_NETDEV
+ tristate "LED Netdev Trigger"
+ depends on LEDS_TRIGGERS
+ help
+ This allows LEDs to be controlled by network device activity.
+ If unsure, say Y.
+
endif # NEW_LEDS
--- a/drivers/leds/Makefile
+++ b/drivers/leds/Makefile
@@ -32,3 +32,4 @@ obj-$(CONFIG_LEDS_TRIGGER_HEARTBEAT) +=
obj-$(CONFIG_LEDS_TRIGGER_BACKLIGHT) += ledtrig-backlight.o
obj-$(CONFIG_LEDS_TRIGGER_DEFAULT_ON) += ledtrig-default-on.o
obj-$(CONFIG_LEDS_TRIGGER_MORSE) += ledtrig-morse.o
+obj-$(CONFIG_LEDS_TRIGGER_NETDEV) += ledtrig-netdev.o

View file

@ -0,0 +1,30 @@
--- a/drivers/input/misc/Kconfig
+++ b/drivers/input/misc/Kconfig
@@ -220,4 +220,20 @@ config HP_SDC_RTC
Say Y here if you want to support the built-in real time clock
of the HP SDC controller.
+config INPUT_GPIO_BUTTONS
+ tristate "Polled GPIO buttons interface"
+ depends on GENERIC_GPIO
+ select INPUT_POLLDEV
+ help
+ This driver implements support for buttons connected
+ to GPIO pins of various CPUs (and some other chips).
+
+ Say Y here if your device has buttons connected
+ directly to such GPIO pins. Your board-specific
+ setup logic must also provide a platform device,
+ with configuration data saying which GPIOs are used.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gpio-buttons.
+
endif
--- a/drivers/input/misc/Makefile
+++ b/drivers/input/misc/Makefile
@@ -21,3 +21,4 @@ obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
obj-$(CONFIG_INPUT_SGI_BTNS) += sgi_btns.o
+obj-$(CONFIG_INPUT_GPIO_BUTTONS) += gpio_buttons.o

View file

@ -0,0 +1,26 @@
--- a/drivers/char/Kconfig
+++ b/drivers/char/Kconfig
@@ -988,6 +988,13 @@ config CS5535_GPIO
If compiled as a module, it will be called cs5535_gpio.
+config GPIO_DEVICE
+ tristate "GPIO device support"
+ depends on GENERIC_GPIO
+ help
+ Say Y to enable Linux GPIO device support. This allows control of
+ GPIO pins using a character device
+
config GPIO_VR41XX
tristate "NEC VR4100 series General-purpose I/O Unit support"
depends on CPU_VR41XX
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -92,6 +92,7 @@ obj-$(CONFIG_SCx200_GPIO) += scx200_gpio
obj-$(CONFIG_PC8736x_GPIO) += pc8736x_gpio.o
obj-$(CONFIG_NSC_GPIO) += nsc_gpio.o
obj-$(CONFIG_CS5535_GPIO) += cs5535_gpio.o
+obj-$(CONFIG_GPIO_DEVICE) += gpio_dev.o
obj-$(CONFIG_GPIO_VR41XX) += vr41xx_giu.o
obj-$(CONFIG_GPIO_TB0219) += tb0219.o
obj-$(CONFIG_TELCLOCK) += tlclk.o

View file

@ -0,0 +1,134 @@
Subject: [PATCH 2/3] I2C: at24: add kernel interface for reading/writing EEPROM
Date: Monday 25 August 2008
From: Kevin Hilman <khilman@deeprootsystems.com>
To: davinci-linux-open-source@linux.davincidsp.com
This patch adds an interface by which other kernel code can read/write
detected EEPROM.
The platform code registers a 'setup' callback with the
at24_platform_data. When the at24 driver detects an EEPROM, it fills
out the read and write functions of at24_iface and calls the setup
callback. The platform code can then use the read/write functions in
the at24_iface struct for reading and writing the EEPROM.
Original idea, review and updates by David Brownell <david-b@pacbell.net>
Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
---
drivers/i2c/chips/at24.c | 42 +++++++++++++++++++++++++++++++++++-------
include/linux/i2c/at24.h | 10 ++++++++++
2 files changed, 45 insertions(+), 7 deletions(-)
--- a/drivers/i2c/chips/at24.c
+++ b/drivers/i2c/chips/at24.c
@@ -53,6 +53,7 @@
struct at24_data {
struct at24_platform_data chip;
+ struct at24_iface iface;
bool use_smbus;
/*
@@ -264,13 +265,6 @@ static ssize_t at24_bin_read(struct kobj
/*
- * REVISIT: export at24_bin{read,write}() to let other kernel code use
- * eeprom data. For example, it might hold a board's Ethernet address, or
- * board-specific calibration data generated on the manufacturing floor.
- */
-
-
-/*
* Note that if the hardware write-protect pin is pulled high, the whole
* chip is normally write protected. But there are plenty of product
* variants here, including OTP fuses and partial chip protect.
@@ -386,6 +380,30 @@ static ssize_t at24_bin_write(struct kob
/*-------------------------------------------------------------------------*/
+/*
+ * This lets other kernel code access the eeprom data. For example, it
+ * might hold a board's Ethernet address, or board-specific calibration
+ * data generated on the manufacturing floor.
+ */
+
+static ssize_t at24_iface_read(struct at24_iface *iface, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(iface, struct at24_data, iface);
+
+ return at24_eeprom_read(at24, buf, offset, count);
+}
+
+static ssize_t at24_iface_write(struct at24_iface *iface, char *buf,
+ off_t offset, size_t count)
+{
+ struct at24_data *at24 = container_of(iface, struct at24_data, iface);
+
+ return at24_eeprom_write(at24, buf, offset, count);
+}
+
+/*-------------------------------------------------------------------------*/
+
static int at24_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct at24_platform_data chip;
@@ -413,6 +431,9 @@ static int at24_probe(struct i2c_client
* is recommended anyhow.
*/
chip.page_size = 1;
+
+ chip.setup = NULL;
+ chip.context = NULL;
}
if (!is_power_of_2(chip.byte_len))
@@ -449,6 +470,9 @@ static int at24_probe(struct i2c_client
goto err_out;
}
+ at24->iface.read = at24_iface_read;
+ at24->iface.write = at24_iface_write;
+
mutex_init(&at24->lock);
at24->use_smbus = use_smbus;
at24->chip = chip;
@@ -520,6 +544,10 @@ static int at24_probe(struct i2c_client
at24->write_max,
use_smbus ? ", use_smbus" : "");
+ /* export data to kernel code */
+ if (chip.setup)
+ chip.setup(&at24->iface, chip.context);
+
return 0;
err_clients:
--- a/include/linux/i2c/at24.h
+++ b/include/linux/i2c/at24.h
@@ -15,6 +15,13 @@
* is bigger than what the chip actually supports!
*/
+struct at24_iface {
+ ssize_t (*read)(struct at24_iface *, char *buf, off_t offset,
+ size_t count);
+ ssize_t (*write)(struct at24_iface *, char *buf, off_t offset,
+ size_t count);
+};
+
struct at24_platform_data {
u32 byte_len; /* size (sum of all addr) */
u16 page_size; /* for writes */
@@ -23,6 +30,9 @@ struct at24_platform_data {
#define AT24_FLAG_READONLY 0x40 /* sysfs-entry will be read-only */
#define AT24_FLAG_IRUGO 0x20 /* sysfs-entry will be world-readable */
#define AT24_FLAG_TAKE8ADDR 0x10 /* take always 8 addresses (24c00) */
+
+ int (*setup)(struct at24_iface *, void *context);
+ void *context;
};
#endif /* _LINUX_AT24_H */

View file

@ -0,0 +1,17 @@
--- a/fs/Kconfig
+++ b/fs/Kconfig
@@ -182,6 +182,7 @@ config FILE_LOCKING
source "fs/xfs/Kconfig"
source "fs/gfs2/Kconfig"
+source "fs/yaffs2/Kconfig"
config OCFS2_FS
tristate "OCFS2 file system support"
--- a/fs/Makefile
+++ b/fs/Makefile
@@ -124,3 +124,4 @@ obj-$(CONFIG_HPPFS) += hppfs/
obj-$(CONFIG_DEBUG_FS) += debugfs/
obj-$(CONFIG_OCFS2_FS) += ocfs2/
obj-$(CONFIG_GFS2_FS) += gfs2/
+obj-$(CONFIG_YAFFS_FS) += yaffs2/

View file

@ -0,0 +1,92 @@
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -181,7 +181,13 @@ static int yaffs_statfs(struct super_blo
#else
static int yaffs_statfs(struct super_block *sb, struct statfs *buf);
#endif
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino);
+#else
static void yaffs_read_inode(struct inode *inode);
+#endif
+
static void yaffs_put_inode(struct inode *inode);
static void yaffs_delete_inode(struct inode *);
@@ -284,7 +290,9 @@ static struct file_operations yaffs_dir_
static struct super_operations yaffs_super_ops = {
.statfs = yaffs_statfs,
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
.read_inode = yaffs_read_inode,
+#endif
.put_inode = yaffs_put_inode,
.put_super = yaffs_put_super,
.delete_inode = yaffs_delete_inode,
@@ -844,11 +852,17 @@ struct inode *yaffs_get_inode(struct sup
T(YAFFS_TRACE_OS,
(KERN_DEBUG "yaffs_get_inode for object %d\n", obj->objectId));
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
+ inode = yaffs_iget(sb, obj->objectId);
+ if (IS_ERR(inode))
+ return NULL;
+#else
inode = iget(sb, obj->objectId);
/* NB Side effect: iget calls back to yaffs_read_inode(). */
/* iget also increments the inode's i_count */
/* NB You can't be holding grossLock or deadlock will happen! */
+#endif
return inode;
}
@@ -1427,6 +1441,39 @@ static int yaffs_sync_fs(struct super_bl
}
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25))
+static struct inode *yaffs_iget(struct super_block *sb, unsigned long ino)
+{
+ yaffs_Object *obj;
+ yaffs_Device *dev = yaffs_SuperToDevice(sb);
+ struct inode *inode;
+
+ T(YAFFS_TRACE_OS,
+ (KERN_DEBUG "yaffs_iget for %lu\n", ino));
+
+ inode = iget_locked(sb, ino);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ if (!(inode->i_state & I_NEW))
+ return inode;
+
+ /* NB This is called as a side effect of other functions, but
+ * we had to release the lock to prevent deadlocks, so
+ * need to lock again.
+ */
+
+ yaffs_GrossLock(dev);
+
+ obj = yaffs_FindObjectByNumber(dev, inode->i_ino);
+
+ yaffs_FillInodeFromObject(inode, obj);
+
+ yaffs_GrossUnlock(dev);
+
+ unlock_new_inode(inode);
+ return inode;
+}
+#else
static void yaffs_read_inode(struct inode *inode)
{
/* NB This is called as a side effect of other functions, but
@@ -1448,6 +1495,7 @@ static void yaffs_read_inode(struct inod
yaffs_GrossUnlock(dev);
}
+#endif /* (LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)) */
static LIST_HEAD(yaffs_dev_list);

View file

@ -0,0 +1,69 @@
--- a/fs/yaffs2/yaffs_fs.c
+++ b/fs/yaffs2/yaffs_fs.c
@@ -76,6 +76,12 @@ extern const char *yaffs_guts_c_version;
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
+#define YPROC_ROOT &proc_root
+#else
+#define YPROC_ROOT NULL
+#endif
+
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,6,17))
#define WRITE_SIZE_STR "writesize"
#define WRITE_SIZE(mtd) (mtd)->writesize
@@ -189,7 +195,9 @@ static void yaffs_read_inode(struct inod
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
static void yaffs_put_inode(struct inode *inode);
+#endif
static void yaffs_delete_inode(struct inode *);
static void yaffs_clear_inode(struct inode *);
@@ -293,7 +301,9 @@ static struct super_operations yaffs_sup
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25))
.read_inode = yaffs_read_inode,
#endif
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
.put_inode = yaffs_put_inode,
+#endif
.put_super = yaffs_put_super,
.delete_inode = yaffs_delete_inode,
.clear_inode = yaffs_clear_inode,
@@ -437,6 +447,7 @@ static struct dentry *yaffs_lookup(struc
}
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26))
/* For now put inode is just for debugging
* Put inode is called when the inode **structure** is put.
*/
@@ -447,6 +458,7 @@ static void yaffs_put_inode(struct inode
atomic_read(&inode->i_count)));
}
+#endif
/* clear is called to tell the fs to release any per-inode data it holds */
static void yaffs_clear_inode(struct inode *inode)
@@ -2279,7 +2291,7 @@ static int __init init_yaffs_fs(void)
/* Install the proc_fs entry */
my_proc_entry = create_proc_entry("yaffs",
S_IRUGO | S_IFREG,
- &proc_root);
+ YPROC_ROOT);
if (my_proc_entry) {
my_proc_entry->write_proc = yaffs_proc_write;
@@ -2325,7 +2337,7 @@ static void __exit exit_yaffs_fs(void)
T(YAFFS_TRACE_ALWAYS, ("yaffs " __DATE__ " " __TIME__
" removing. \n"));
- remove_proc_entry("yaffs", &proc_root);
+ remove_proc_entry("yaffs", YPROC_ROOT);
fsinst = fs_to_install;

View file

@ -0,0 +1,83 @@
--- a/drivers/net/phy/phy.c
+++ b/drivers/net/phy/phy.c
@@ -299,6 +299,50 @@ int phy_ethtool_gset(struct phy_device *
}
EXPORT_SYMBOL(phy_ethtool_gset);
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr)
+{
+ u32 cmd;
+ int tmp;
+ struct ethtool_cmd ecmd = { ETHTOOL_GSET };
+ struct ethtool_value edata = { ETHTOOL_GLINK };
+
+ if (get_user(cmd, (u32 *) useraddr))
+ return -EFAULT;
+
+ switch (cmd) {
+ case ETHTOOL_GSET:
+ phy_ethtool_gset(phydev, &ecmd);
+ if (copy_to_user(useraddr, &ecmd, sizeof(ecmd)))
+ return -EFAULT;
+ return 0;
+
+ case ETHTOOL_SSET:
+ if (copy_from_user(&ecmd, useraddr, sizeof(ecmd)))
+ return -EFAULT;
+ return phy_ethtool_sset(phydev, &ecmd);
+
+ case ETHTOOL_NWAY_RST:
+ /* if autoneg is off, it's an error */
+ tmp = phy_read(phydev, MII_BMCR);
+ if (tmp & BMCR_ANENABLE) {
+ tmp |= (BMCR_ANRESTART);
+ phy_write(phydev, MII_BMCR, tmp);
+ return 0;
+ }
+ return -EINVAL;
+
+ case ETHTOOL_GLINK:
+ edata.data = (phy_read(phydev,
+ MII_BMSR) & BMSR_LSTATUS) ? 1 : 0;
+ if (copy_to_user(useraddr, &edata, sizeof(edata)))
+ return -EFAULT;
+ return 0;
+ }
+
+ return -EOPNOTSUPP;
+}
+EXPORT_SYMBOL(phy_ethtool_ioctl);
+
/**
* phy_mii_ioctl - generic PHY MII ioctl interface
* @phydev: the phy_device struct
@@ -355,8 +399,8 @@ int phy_mii_ioctl(struct phy_device *phy
}
phy_write(phydev, mii_data->reg_num, val);
-
- if (mii_data->reg_num == MII_BMCR
+
+ if (mii_data->reg_num == MII_BMCR
&& val & BMCR_RESET
&& phydev->drv->config_init) {
phy_scan_fixups(phydev);
@@ -476,7 +520,7 @@ static void phy_force_reduction(struct p
int idx;
idx = phy_find_setting(phydev->speed, phydev->duplex);
-
+
idx++;
idx = phy_find_valid(idx, phydev->supported);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -476,6 +476,7 @@ void phy_start_machine(struct phy_device
void phy_stop_machine(struct phy_device *phydev);
int phy_ethtool_sset(struct phy_device *phydev, struct ethtool_cmd *cmd);
int phy_ethtool_gset(struct phy_device *phydev, struct ethtool_cmd *cmd);
+int phy_ethtool_ioctl(struct phy_device *phydev, void *useraddr);
int phy_mii_ioctl(struct phy_device *phydev,
struct mii_ioctl_data *mii_data, int cmd);
int phy_start_interrupts(struct phy_device *phydev);

View file

@ -0,0 +1,26 @@
--- a/drivers/net/phy/mdio_bus.c
+++ b/drivers/net/phy/mdio_bus.c
@@ -273,6 +273,9 @@ static int mdio_bus_match(struct device
struct phy_device *phydev = to_phy_device(dev);
struct phy_driver *phydrv = to_phy_driver(drv);
+ if (phydrv->detect)
+ return (phydrv->detect(phydev->bus, phydev->addr));
+
return ((phydrv->phy_id & phydrv->phy_id_mask) ==
(phydev->phy_id & phydrv->phy_id_mask));
}
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -356,6 +356,11 @@ struct phy_driver {
u32 features;
u32 flags;
+ /* Called during discovery to test if the
+ * device can attach to the bus, even if
+ * phy id and mask do not match */
+ bool (*detect)(struct mii_bus *bus, int addr);
+
/*
* Called to initialize the PHY,
* including after a reset

View file

@ -0,0 +1,24 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -66,6 +66,11 @@ config REALTEK_PHY
---help---
Supports the Realtek 821x PHY.
+config ADM6996_PHY
+ tristate "Driver for ADM6996 switches"
+ ---help---
+ Currently supports the ADM6996F switch
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -12,6 +12,7 @@ obj-$(CONFIG_SMSC_PHY) += smsc.o
obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
+obj-$(CONFIG_ADM6996_PHY) += adm6996.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o

View file

@ -0,0 +1,63 @@
--- a/drivers/net/phy/phy_device.c
+++ b/drivers/net/phy/phy_device.c
@@ -143,6 +143,18 @@ int phy_scan_fixups(struct phy_device *p
}
EXPORT_SYMBOL(phy_scan_fixups);
+static int generic_receive_skb(struct sk_buff *skb)
+{
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ return netif_receive_skb(skb);
+}
+
+static int generic_rx(struct sk_buff *skb)
+{
+ skb->protocol = eth_type_trans(skb, skb->dev);
+ return netif_rx(skb);
+}
+
struct phy_device* phy_device_create(struct mii_bus *bus, int addr, int phy_id)
{
struct phy_device *dev;
@@ -168,6 +180,8 @@ struct phy_device* phy_device_create(str
dev->bus = bus;
dev->state = PHY_DOWN;
+ dev->netif_receive_skb = &generic_receive_skb;
+ dev->netif_rx = &generic_rx;
mutex_init(&dev->lock);
--- a/include/linux/phy.h
+++ b/include/linux/phy.h
@@ -326,6 +326,20 @@ struct phy_device {
void (*adjust_link)(struct net_device *dev);
void (*adjust_state)(struct net_device *dev);
+
+ /*
+ * By default these point to the original functions
+ * with the same name. adding them to the phy_device
+ * allows the phy driver to override them for packet
+ * mangling if the ethernet driver supports it
+ * This is required to support some really horrible
+ * switches such as the Marvell 88E6060
+ */
+ int (*netif_receive_skb)(struct sk_buff *skb);
+ int (*netif_rx)(struct sk_buff *skb);
+
+ /* alignment offset for packets */
+ int pkt_align;
};
#define to_phy_device(d) container_of(d, struct phy_device, dev)
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -627,6 +627,7 @@ struct net_device
void *ax25_ptr; /* AX.25 specific data */
struct wireless_dev *ieee80211_ptr; /* IEEE 802.11 specific data,
assign before registering */
+ void *phy_ptr; /* PHY device specific data */
/*
* Cache line mostly used on receive path (including eth_type_trans())

View file

@ -0,0 +1,25 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -71,6 +71,12 @@ config ADM6996_PHY
---help---
Currently supports the ADM6996F switch
+config MVSWITCH_PHY
+ tristate "Driver for Marvell switches"
+ select VLAN_8021Q
+ ---help---
+ Currently supports the Marvell 88E6060 switch.
+
config FIXED_PHY
bool "Driver for MDIO Bus/PHY emulation with fixed speed/link PHYs"
depends on PHYLIB=y
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -13,6 +13,7 @@ obj-$(CONFIG_VITESSE_PHY) += vitesse.o
obj-$(CONFIG_BROADCOM_PHY) += broadcom.o
obj-$(CONFIG_ICPLUS_PHY) += icplus.o
obj-$(CONFIG_ADM6996_PHY) += adm6996.o
+obj-$(CONFIG_MVSWITCH_PHY) += mvswitch.o
obj-$(CONFIG_REALTEK_PHY) += realtek.o
obj-$(CONFIG_FIXED_PHY) += fixed.o
obj-$(CONFIG_MDIO_BITBANG) += mdio-bitbang.o

View file

@ -0,0 +1,25 @@
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -13,6 +13,12 @@ menuconfig PHYLIB
if PHYLIB
+config SWCONFIG
+ tristate "Switch configuration API"
+ ---help---
+ Switch configuration API using netlink. This allows
+ you to configure the VLAN features of certain switches.
+
comment "MII PHY device drivers"
config MARVELL_PHY
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -3,6 +3,7 @@
libphy-objs := phy.o phy_device.o mdio_bus.o
obj-$(CONFIG_PHYLIB) += libphy.o
+obj-$(CONFIG_SWCONFIG) += swconfig.o
obj-$(CONFIG_MARVELL_PHY) += marvell.o
obj-$(CONFIG_DAVICOM_PHY) += davicom.o
obj-$(CONFIG_CICADA_PHY) += cicada.o

View file

@ -0,0 +1,25 @@
--- a/drivers/usb/serial/usb-serial.c
+++ b/drivers/usb/serial/usb-serial.c
@@ -59,6 +59,7 @@ static struct usb_driver usb_serial_driv
drivers depend on it.
*/
+static ushort maxSize = 0;
static int debug;
/* initially all NULL */
static struct usb_serial *serial_table[SERIAL_TTY_MINORS];
@@ -839,7 +840,7 @@ int usb_serial_probe(struct usb_interfac
dev_err(&interface->dev, "No free urbs available\n");
goto probe_error;
}
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
+ buffer_size = (endpoint->wMaxPacketSize > maxSize) ? endpoint->wMaxPacketSize : maxSize;
port->bulk_in_size = buffer_size;
port->bulk_in_endpointAddress = endpoint->bEndpointAddress;
port->bulk_in_buffer = kmalloc(buffer_size, GFP_KERNEL);
@@ -1268,3 +1269,5 @@ MODULE_LICENSE("GPL");
module_param(debug, bool, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(debug, "Debug enabled or not");
+module_param(maxSize, ushort,0);
+MODULE_PARM_DESC(maxSize,"User specified USB endpoint size");

View file

@ -0,0 +1,11 @@
--- a/init/main.c
+++ b/init/main.c
@@ -801,7 +801,7 @@ static int noinline init_post(void)
numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
- printk(KERN_WARNING "Warning: unable to open an initial console.\n");
+ printk(KERN_WARNING "Please be patient, while OpenWrt loads ...\n");
(void) sys_dup(0);
(void) sys_dup(0);

View file

@ -0,0 +1,46 @@
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -1,6 +1,10 @@
#ifndef _LINUX_TIME_H
#define _LINUX_TIME_H
+#ifndef __KERNEL__
+#include <time.h>
+#else
+
#include <linux/types.h>
#ifdef __KERNEL__
@@ -239,4 +243,6 @@ struct itimerval {
*/
#define TIMER_ABSTIME 0x01
+#endif /* __KERNEL__ DEBIAN */
+
#endif
--- a/include/linux/types.h
+++ b/include/linux/types.h
@@ -1,6 +1,14 @@
#ifndef _LINUX_TYPES_H
#define _LINUX_TYPES_H
+/* Debian: Use userland types instead. */
+#ifndef __KERNEL__
+# include <sys/types.h>
+/* For other kernel headers. */
+# include <linux/posix_types.h>
+# include <asm/types.h>
+#else
+
#ifdef __KERNEL__
#define DECLARE_BITMAP(name,bits) \
@@ -161,6 +169,8 @@ typedef unsigned long blkcnt_t;
#endif /* __KERNEL_STRICT_NAMES */
+#endif /* __KERNEL__ DEBIAN */
+
/*
* Below are truly Linux-specific types that should never collide with
* any application/library that wants linux/types.h.

View file

@ -0,0 +1,102 @@
--- a/scripts/genksyms/parse.c_shipped
+++ b/scripts/genksyms/parse.c_shipped
@@ -160,7 +160,9 @@
#include <assert.h>
+#ifndef __APPLE__
#include <malloc.h>
+#endif
#include "genksyms.h"
static int is_typedef;
--- a/scripts/genksyms/parse.y
+++ b/scripts/genksyms/parse.y
@@ -24,7 +24,9 @@
%{
#include <assert.h>
+#ifndef __APPLE__
#include <malloc.h>
+#endif
#include "genksyms.h"
static int is_typedef;
--- a/scripts/kallsyms.c
+++ b/scripts/kallsyms.c
@@ -22,6 +22,35 @@
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
+#ifdef __APPLE__
+/* Darwin has no memmem implementation, this one is ripped of the uClibc-0.9.28 source */
+void *memmem (const void *haystack, size_t haystack_len,
+ const void *needle, size_t needle_len)
+{
+ const char *begin;
+ const char *const last_possible
+ = (const char *) haystack + haystack_len - needle_len;
+
+ if (needle_len == 0)
+ /* The first occurrence of the empty string is deemed to occur at
+ the beginning of the string. */
+ return (void *) haystack;
+
+ /* Sanity check, otherwise the loop might search through the whole
+ memory. */
+ if (__builtin_expect (haystack_len < needle_len, 0))
+ return NULL;
+
+ for (begin = (const char *) haystack; begin <= last_possible; ++begin)
+ if (begin[0] == ((const char *) needle)[0] &&
+ !memcmp ((const void *) &begin[1],
+ (const void *) ((const char *) needle + 1),
+ needle_len - 1))
+ return (void *) begin;
+
+ return NULL;
+}
+#endif
#define KSYM_NAME_LEN 128
--- a/scripts/kconfig/Makefile
+++ b/scripts/kconfig/Makefile
@@ -97,6 +97,9 @@ check-lxdialog := $(srctree)/$(src)/lxd
# we really need to do so. (Do not call gcc as part of make mrproper)
HOST_EXTRACFLAGS = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ccflags)
HOST_LOADLIBES = $(shell $(CONFIG_SHELL) $(check-lxdialog) -ldflags $(HOSTCC))
+ifeq ($(shell uname -s),Darwin)
+HOST_LOADLIBES += -lncurses
+endif
HOST_EXTRACFLAGS += -DLOCALE
--- a/scripts/mod/mk_elfconfig.c
+++ b/scripts/mod/mk_elfconfig.c
@@ -1,7 +1,11 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#ifndef __APPLE__
#include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
int
main(int argc, char **argv)
--- a/scripts/mod/modpost.h
+++ b/scripts/mod/modpost.h
@@ -7,7 +7,11 @@
#include <sys/mman.h>
#include <fcntl.h>
#include <unistd.h>
+#ifndef __APPLE__
#include <elf.h>
+#else
+#include "../../../../../tools/sstrip/include/elf.h"
+#endif
#include "elfconfig.h"

View file

@ -0,0 +1,154 @@
--- a/drivers/net/wireless/hostap/hostap_ap.c
+++ b/drivers/net/wireless/hostap/hostap_ap.c
@@ -2397,13 +2397,13 @@ int prism2_ap_get_sta_qual(local_info_t
addr[count].sa_family = ARPHRD_ETHER;
memcpy(addr[count].sa_data, sta->addr, ETH_ALEN);
if (sta->last_rx_silence == 0)
- qual[count].qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ qual[count].qual = (sta->last_rx_signal - 156) == 0 ?
+ 0 : (sta->last_rx_signal - 156) * 92 / 64;
else
- qual[count].qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- qual[count].level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- qual[count].noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ qual[count].qual = (sta->last_rx_signal -
+ sta->last_rx_silence) * 92 / 64;
+ qual[count].level = sta->last_rx_signal;
+ qual[count].noise = sta->last_rx_silence;
qual[count].updated = sta->last_rx_updated;
sta->last_rx_updated = IW_QUAL_DBM;
@@ -2469,13 +2469,13 @@ int prism2_ap_translate_scan(struct net_
memset(&iwe, 0, sizeof(iwe));
iwe.cmd = IWEVQUAL;
if (sta->last_rx_silence == 0)
- iwe.u.qual.qual = sta->last_rx_signal < 27 ?
- 0 : (sta->last_rx_signal - 27) * 92 / 127;
+ iwe.u.qual.qual = (sta->last_rx_signal -156) == 0 ?
+ 0 : (sta->last_rx_signal - 156) * 92 / 64;
else
- iwe.u.qual.qual = sta->last_rx_signal -
- sta->last_rx_silence - 35;
- iwe.u.qual.level = HFA384X_LEVEL_TO_dBm(sta->last_rx_signal);
- iwe.u.qual.noise = HFA384X_LEVEL_TO_dBm(sta->last_rx_silence);
+ iwe.u.qual.qual = (sta->last_rx_signal -
+ sta->last_rx_silence) * 92 / 64;
+ iwe.u.qual.level = sta->last_rx_signal;
+ iwe.u.qual.noise = sta->last_rx_silence;
iwe.u.qual.updated = sta->last_rx_updated;
iwe.len = IW_EV_QUAL_LEN;
current_ev = iwe_stream_add_event(info, current_ev, end_buf,
--- a/drivers/net/wireless/hostap/hostap_config.h
+++ b/drivers/net/wireless/hostap/hostap_config.h
@@ -45,4 +45,9 @@
*/
/* #define PRISM2_NO_STATION_MODES */
+/* Enable TX power Setting functions
+ * (min att = -128 , max att = 127)
+ */
+#define RAW_TXPOWER_SETTING
+
#endif /* HOSTAP_CONFIG_H */
--- a/drivers/net/wireless/hostap/hostap.h
+++ b/drivers/net/wireless/hostap/hostap.h
@@ -90,6 +90,7 @@ extern const struct iw_handler_def hosta
extern const struct ethtool_ops prism2_ethtool_ops;
int hostap_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
+int hostap_restore_power(struct net_device *dev);
#endif /* HOSTAP_H */
--- a/drivers/net/wireless/hostap/hostap_hw.c
+++ b/drivers/net/wireless/hostap/hostap_hw.c
@@ -933,6 +933,7 @@ static int hfa384x_set_rid(struct net_de
prism2_hw_reset(dev);
}
+ hostap_restore_power(dev);
return res;
}
--- a/drivers/net/wireless/hostap/hostap_info.c
+++ b/drivers/net/wireless/hostap/hostap_info.c
@@ -434,6 +434,11 @@ static void handle_info_queue_linkstatus
}
/* Get BSSID if we have a valid AP address */
+
+ if ( val == HFA384X_LINKSTATUS_CONNECTED ||
+ val == HFA384X_LINKSTATUS_DISCONNECTED )
+ hostap_restore_power(local->dev);
+
if (connected) {
netif_carrier_on(local->dev);
netif_carrier_on(local->ddev);
--- a/drivers/net/wireless/hostap/hostap_ioctl.c
+++ b/drivers/net/wireless/hostap/hostap_ioctl.c
@@ -1502,23 +1502,20 @@ static int prism2_txpower_hfa386x_to_dBm
val = 255;
tmp = val;
- tmp >>= 2;
- return -12 - tmp;
+ return tmp;
}
static u16 prism2_txpower_dBm_to_hfa386x(int val)
{
signed char tmp;
- if (val > 20)
- return 128;
- else if (val < -43)
+ if (val > 127)
return 127;
+ else if (val < -128)
+ return 128;
tmp = val;
- tmp = -12 - tmp;
- tmp <<= 2;
return (unsigned char) tmp;
}
@@ -4083,3 +4080,35 @@ int hostap_ioctl(struct net_device *dev,
return ret;
}
+
+/* BUG FIX: Restore power setting value when lost due to F/W bug */
+
+int hostap_restore_power(struct net_device *dev)
+{
+ struct hostap_interface *iface = dev->priv;
+ local_info_t *local = iface->local;
+
+ u16 val;
+ int ret = 0;
+
+ if (local->txpower_type == PRISM2_TXPOWER_OFF) {
+ val = 0xff; /* use all standby and sleep modes */
+ ret = local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_A_D_TEST_MODES2,
+ &val, NULL);
+ }
+
+#ifdef RAW_TXPOWER_SETTING
+ if (local->txpower_type == PRISM2_TXPOWER_FIXED) {
+ val = HFA384X_TEST_CFG_BIT_ALC;
+ local->func->cmd(dev, HFA384X_CMDCODE_TEST |
+ (HFA384X_TEST_CFG_BITS << 8), 0, &val, NULL);
+ val = prism2_txpower_dBm_to_hfa386x(local->txpower);
+ ret = (local->func->cmd(dev, HFA384X_CMDCODE_WRITEMIF,
+ HFA386X_CR_MANUAL_TX_POWER, &val, NULL));
+ }
+#endif /* RAW_TXPOWER_SETTING */
+ return (ret ? -EOPNOTSUPP : 0);
+}
+
+EXPORT_SYMBOL(hostap_restore_power);

View file

@ -0,0 +1,17 @@
--- a/include/linux/stddef.h
+++ b/include/linux/stddef.h
@@ -16,6 +16,7 @@ enum {
false = 0,
true = 1
};
+#endif /* __KERNEL__ */
#undef offsetof
#ifdef __compiler_offsetof
@@ -23,6 +24,5 @@ enum {
#else
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#endif
-#endif /* __KERNEL__ */
#endif

View file

@ -0,0 +1,10 @@
--- a/arch/x86/boot/tools/build.c
+++ b/arch/x86/boot/tools/build.c
@@ -29,7 +29,6 @@
#include <stdarg.h>
#include <sys/types.h>
#include <sys/stat.h>
-#include <sys/sysmacros.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/mman.h>

View file

@ -0,0 +1,376 @@
--- /dev/null
+++ b/include/linux/spi/spi_gpio.h
@@ -0,0 +1,73 @@
+/*
+ * spi_gpio interface to platform code
+ *
+ * Copyright (c) 2008 Piotr Skamruk
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _LINUX_SPI_SPI_GPIO
+#define _LINUX_SPI_SPI_GPIO
+
+#include <linux/types.h>
+#include <linux/spi/spi.h>
+
+
+/**
+ * struct spi_gpio_platform_data - Data definitions for a SPI-GPIO device.
+ *
+ * This structure holds information about a GPIO-based SPI device.
+ *
+ * @pin_clk: The GPIO pin number of the CLOCK pin.
+ *
+ * @pin_miso: The GPIO pin number of the MISO pin.
+ *
+ * @pin_mosi: The GPIO pin number of the MOSI pin.
+ *
+ * @pin_cs: The GPIO pin number of the CHIPSELECT pin.
+ *
+ * @cs_activelow: If true, the chip is selected when the CS line is low.
+ *
+ * @no_spi_delay: If true, no delay is done in the lowlevel bitbanging.
+ * Note that doing no delay is not standards compliant,
+ * but it might be needed to speed up transfers on some
+ * slow embedded machines.
+ *
+ * @boardinfo_setup: This callback is called after the
+ * SPI master device was registered, but before the
+ * device is registered.
+ * @boardinfo_setup_data: Data argument passed to boardinfo_setup().
+ */
+struct spi_gpio_platform_data {
+ unsigned int pin_clk;
+ unsigned int pin_miso;
+ unsigned int pin_mosi;
+ unsigned int pin_cs;
+ bool cs_activelow;
+ bool no_spi_delay;
+ int (*boardinfo_setup)(struct spi_board_info *bi,
+ struct spi_master *master,
+ void *data);
+ void *boardinfo_setup_data;
+};
+
+/**
+ * SPI_GPIO_PLATDEV_NAME - The platform device name string.
+ *
+ * The name string that has to be used for platform_device_alloc
+ * when allocating a spi-gpio device.
+ */
+#define SPI_GPIO_PLATDEV_NAME "spi-gpio"
+
+/**
+ * spi_gpio_next_id - Get another platform device ID number.
+ *
+ * This returns the next platform device ID number that has to be used
+ * for platform_device_alloc. The ID is opaque and should not be used for
+ * anything else.
+ */
+int spi_gpio_next_id(void);
+
+#endif /* _LINUX_SPI_SPI_GPIO */
--- /dev/null
+++ b/drivers/spi/spi_gpio.c
@@ -0,0 +1,251 @@
+/*
+ * Bitbanging SPI bus driver using GPIO API
+ *
+ * Copyright (c) 2008 Piotr Skamruk
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * based on spi_s3c2410_gpio.c
+ * Copyright (c) 2006 Ben Dooks
+ * Copyright (c) 2006 Simtec Electronics
+ * and on i2c-gpio.c
+ * Copyright (C) 2007 Atmel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/spinlock.h>
+#include <linux/workqueue.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/spi/spi.h>
+#include <linux/spi/spi_bitbang.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+
+
+struct spi_gpio {
+ struct spi_bitbang bitbang;
+ struct spi_gpio_platform_data *info;
+ struct platform_device *pdev;
+ struct spi_board_info bi;
+};
+
+
+static inline struct spi_gpio *spidev_to_sg(struct spi_device *dev)
+{
+ return dev->controller_data;
+}
+
+static inline void setsck(struct spi_device *dev, int val)
+{
+ struct spi_gpio *sp = spidev_to_sg(dev);
+ gpio_set_value(sp->info->pin_clk, val ? 1 : 0);
+}
+
+static inline void setmosi(struct spi_device *dev, int val)
+{
+ struct spi_gpio *sp = spidev_to_sg(dev);
+ gpio_set_value(sp->info->pin_mosi, val ? 1 : 0);
+}
+
+static inline u32 getmiso(struct spi_device *dev)
+{
+ struct spi_gpio *sp = spidev_to_sg(dev);
+ return gpio_get_value(sp->info->pin_miso) ? 1 : 0;
+}
+
+static inline void do_spidelay(struct spi_device *dev, unsigned nsecs)
+{
+ struct spi_gpio *sp = spidev_to_sg(dev);
+
+ if (!sp->info->no_spi_delay)
+ ndelay(nsecs);
+}
+
+#define spidelay(nsecs) do { \
+ /* Steal the spi_device pointer from our caller. \
+ * The bitbang-API should probably get fixed here... */ \
+ do_spidelay(spi, nsecs); \
+ } while (0)
+
+#define EXPAND_BITBANG_TXRX
+#include <linux/spi/spi_bitbang.h>
+
+static u32 spi_gpio_txrx_mode0(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 0, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode1(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 0, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode2(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha0(spi, nsecs, 1, word, bits);
+}
+
+static u32 spi_gpio_txrx_mode3(struct spi_device *spi,
+ unsigned nsecs, u32 word, u8 bits)
+{
+ return bitbang_txrx_be_cpha1(spi, nsecs, 1, word, bits);
+}
+
+static void spi_gpio_chipselect(struct spi_device *dev, int on)
+{
+ struct spi_gpio *sp = spidev_to_sg(dev);
+
+ if (sp->info->cs_activelow)
+ on = !on;
+ gpio_set_value(sp->info->pin_cs, on ? 1 : 0);
+}
+
+static int spi_gpio_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct spi_gpio_platform_data *pdata;
+ struct spi_gpio *sp;
+ struct spi_device *spidev;
+ int err;
+
+ pdata = pdev->dev.platform_data;
+ if (!pdata)
+ return -ENXIO;
+
+ err = -ENOMEM;
+ master = spi_alloc_master(&pdev->dev, sizeof(struct spi_gpio));
+ if (!master)
+ goto err_alloc_master;
+
+ sp = spi_master_get_devdata(master);
+ platform_set_drvdata(pdev, sp);
+ sp->info = pdata;
+
+ err = gpio_request(pdata->pin_clk, "spi_clock");
+ if (err)
+ goto err_request_clk;
+ err = gpio_request(pdata->pin_mosi, "spi_mosi");
+ if (err)
+ goto err_request_mosi;
+ err = gpio_request(pdata->pin_miso, "spi_miso");
+ if (err)
+ goto err_request_miso;
+ err = gpio_request(pdata->pin_cs, "spi_cs");
+ if (err)
+ goto err_request_cs;
+
+ sp->bitbang.master = spi_master_get(master);
+ sp->bitbang.master->bus_num = -1;
+ sp->bitbang.master->num_chipselect = 1;
+ sp->bitbang.chipselect = spi_gpio_chipselect;
+ sp->bitbang.txrx_word[SPI_MODE_0] = spi_gpio_txrx_mode0;
+ sp->bitbang.txrx_word[SPI_MODE_1] = spi_gpio_txrx_mode1;
+ sp->bitbang.txrx_word[SPI_MODE_2] = spi_gpio_txrx_mode2;
+ sp->bitbang.txrx_word[SPI_MODE_3] = spi_gpio_txrx_mode3;
+
+ gpio_direction_output(pdata->pin_clk, 0);
+ gpio_direction_output(pdata->pin_mosi, 0);
+ gpio_direction_output(pdata->pin_cs,
+ pdata->cs_activelow ? 1 : 0);
+ gpio_direction_input(pdata->pin_miso);
+
+ err = spi_bitbang_start(&sp->bitbang);
+ if (err)
+ goto err_no_bitbang;
+ err = pdata->boardinfo_setup(&sp->bi, master,
+ pdata->boardinfo_setup_data);
+ if (err)
+ goto err_bi_setup;
+ sp->bi.controller_data = sp;
+ spidev = spi_new_device(master, &sp->bi);
+ if (!spidev)
+ goto err_new_dev;
+
+ return 0;
+
+err_new_dev:
+err_bi_setup:
+ spi_bitbang_stop(&sp->bitbang);
+err_no_bitbang:
+ spi_master_put(sp->bitbang.master);
+ gpio_free(pdata->pin_cs);
+err_request_cs:
+ gpio_free(pdata->pin_miso);
+err_request_miso:
+ gpio_free(pdata->pin_mosi);
+err_request_mosi:
+ gpio_free(pdata->pin_clk);
+err_request_clk:
+ kfree(master);
+
+err_alloc_master:
+ return err;
+}
+
+static int __devexit spi_gpio_remove(struct platform_device *pdev)
+{
+ struct spi_gpio *sp;
+ struct spi_gpio_platform_data *pdata;
+
+ pdata = pdev->dev.platform_data;
+ sp = platform_get_drvdata(pdev);
+
+ gpio_free(pdata->pin_clk);
+ gpio_free(pdata->pin_mosi);
+ gpio_free(pdata->pin_miso);
+ gpio_free(pdata->pin_cs);
+ spi_bitbang_stop(&sp->bitbang);
+ spi_master_put(sp->bitbang.master);
+
+ return 0;
+}
+
+static struct platform_driver spi_gpio_driver = {
+ .driver = {
+ .name = SPI_GPIO_PLATDEV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = spi_gpio_probe,
+ .remove = __devexit_p(spi_gpio_remove),
+};
+
+int spi_gpio_next_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(-1);
+
+ return atomic_inc_return(&counter);
+}
+EXPORT_SYMBOL(spi_gpio_next_id);
+
+static int __init spi_gpio_init(void)
+{
+ int err;
+
+ err = platform_driver_register(&spi_gpio_driver);
+ if (err)
+ printk(KERN_ERR "spi-gpio: register failed: %d\n", err);
+
+ return err;
+}
+module_init(spi_gpio_init);
+
+static void __exit spi_gpio_exit(void)
+{
+ platform_driver_unregister(&spi_gpio_driver);
+}
+module_exit(spi_gpio_exit);
+
+MODULE_AUTHOR("Piot Skamruk <piotr.skamruk at gmail.com>");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_DESCRIPTION("Platform independent GPIO bitbanging SPI driver");
+MODULE_LICENSE("GPL v2");
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -100,6 +100,19 @@ config SPI_BUTTERFLY
inexpensive battery powered microcontroller evaluation board.
This same cable can be used to flash new firmware.
+config SPI_GPIO
+ tristate "GPIO API based bitbanging SPI controller"
+ depends on SPI_MASTER && GENERIC_GPIO
+ select SPI_BITBANG
+ help
+ This is a platform driver that can be used for bitbanging
+ an SPI bus over GPIO pins.
+ Select this if you have any SPI device that is connected via
+ GPIO pins.
+ The module will be called spi_gpio.
+
+ If unsure, say N.
+
config SPI_IMX
tristate "Freescale iMX SPI controller"
depends on ARCH_IMX && EXPERIMENTAL
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -16,6 +16,7 @@ obj-$(CONFIG_SPI_BFIN) += spi_bfin5xx.
obj-$(CONFIG_SPI_BITBANG) += spi_bitbang.o
obj-$(CONFIG_SPI_AU1550) += au1550_spi.o
obj-$(CONFIG_SPI_BUTTERFLY) += spi_butterfly.o
+obj-$(CONFIG_SPI_GPIO) += spi_gpio.o
obj-$(CONFIG_SPI_IMX) += spi_imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi_lm70llp.o
obj-$(CONFIG_SPI_PXA2XX) += pxa2xx_spi.o
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -4017,6 +4017,11 @@ M: jbglaw@lug-owl.de
L: linux-kernel@vger.kernel.org
S: Maintained
+SPI GPIO MASTER DRIVER
+P: Michael Buesch
+M: mb@bu3sch.de
+S: Maintained
+
STABLE BRANCH
P: Greg Kroah-Hartman
M: greg@kroah.com

View file

@ -0,0 +1,838 @@
--- /dev/null
+++ b/drivers/mmc/host/gpiommc.c
@@ -0,0 +1,608 @@
+/*
+ * Driver an MMC/SD card on a bitbanging GPIO SPI bus.
+ * This module hooks up the mmc_spi and spi_gpio modules and also
+ * provides a configfs interface.
+ *
+ * Copyright 2008 Michael Buesch <mb@bu3sch.de>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include <linux/mmc/gpiommc.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spi/spi_gpio.h>
+#include <linux/configfs.h>
+#include <linux/gpio.h>
+#include <asm/atomic.h>
+
+
+#define PFX "gpio-mmc: "
+
+
+struct gpiommc_device {
+ struct platform_device *pdev;
+ struct platform_device *spi_pdev;
+ struct spi_board_info boardinfo;
+};
+
+
+MODULE_DESCRIPTION("GPIO based MMC driver");
+MODULE_AUTHOR("Michael Buesch");
+MODULE_LICENSE("GPL");
+
+
+static int gpiommc_boardinfo_setup(struct spi_board_info *bi,
+ struct spi_master *master,
+ void *data)
+{
+ struct gpiommc_device *d = data;
+ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
+
+ /* Bind the SPI master to the MMC-SPI host driver. */
+ strlcpy(bi->modalias, "mmc_spi", sizeof(bi->modalias));
+
+ bi->max_speed_hz = pdata->max_bus_speed;
+ bi->bus_num = master->bus_num;
+ bi->mode = pdata->mode;
+
+ return 0;
+}
+
+static int gpiommc_probe(struct platform_device *pdev)
+{
+ struct gpiommc_platform_data *mmc_pdata = pdev->dev.platform_data;
+ struct spi_gpio_platform_data spi_pdata;
+ struct gpiommc_device *d;
+ int err;
+
+ err = -ENXIO;
+ if (!mmc_pdata)
+ goto error;
+
+#ifdef CONFIG_MMC_SPI_MODULE
+ err = request_module("mmc_spi");
+ if (err) {
+ printk(KERN_WARNING PFX
+ "Failed to request mmc_spi module.\n");
+ }
+#endif /* CONFIG_MMC_SPI_MODULE */
+
+ /* Allocate the GPIO-MMC device */
+ err = -ENOMEM;
+ d = kzalloc(sizeof(*d), GFP_KERNEL);
+ if (!d)
+ goto error;
+ d->pdev = pdev;
+
+ /* Create the SPI-GPIO device */
+ d->spi_pdev = platform_device_alloc(SPI_GPIO_PLATDEV_NAME,
+ spi_gpio_next_id());
+ if (!d->spi_pdev)
+ goto err_free_d;
+
+ memset(&spi_pdata, 0, sizeof(spi_pdata));
+ spi_pdata.pin_clk = mmc_pdata->pins.gpio_clk;
+ spi_pdata.pin_miso = mmc_pdata->pins.gpio_do;
+ spi_pdata.pin_mosi = mmc_pdata->pins.gpio_di;
+ spi_pdata.pin_cs = mmc_pdata->pins.gpio_cs;
+ spi_pdata.cs_activelow = mmc_pdata->pins.cs_activelow;
+ spi_pdata.no_spi_delay = mmc_pdata->no_spi_delay;
+ spi_pdata.boardinfo_setup = gpiommc_boardinfo_setup;
+ spi_pdata.boardinfo_setup_data = d;
+
+ err = platform_device_add_data(d->spi_pdev, &spi_pdata,
+ sizeof(spi_pdata));
+ if (err)
+ goto err_free_pdev;
+ err = platform_device_add(d->spi_pdev);
+ if (err)
+ goto err_free_pdata;
+ platform_set_drvdata(pdev, d);
+
+ printk(KERN_INFO PFX "MMC-Card \"%s\" "
+ "attached to GPIO pins di=%u, do=%u, clk=%u, cs=%u\n",
+ mmc_pdata->name, mmc_pdata->pins.gpio_di,
+ mmc_pdata->pins.gpio_do,
+ mmc_pdata->pins.gpio_clk,
+ mmc_pdata->pins.gpio_cs);
+
+ return 0;
+
+err_free_pdata:
+ kfree(d->spi_pdev->dev.platform_data);
+ d->spi_pdev->dev.platform_data = NULL;
+err_free_pdev:
+ platform_device_put(d->spi_pdev);
+err_free_d:
+ kfree(d);
+error:
+ return err;
+}
+
+static int gpiommc_remove(struct platform_device *pdev)
+{
+ struct gpiommc_device *d = platform_get_drvdata(pdev);
+ struct gpiommc_platform_data *pdata = d->pdev->dev.platform_data;
+
+ platform_device_unregister(d->spi_pdev);
+ printk(KERN_INFO PFX "GPIO based MMC-Card \"%s\" removed\n",
+ pdata->name);
+ platform_device_put(d->spi_pdev);
+
+ return 0;
+}
+
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+
+/* A device that was created through configfs */
+struct gpiommc_configfs_device {
+ struct config_item item;
+ /* The platform device, after registration. */
+ struct platform_device *pdev;
+ /* The configuration */
+ struct gpiommc_platform_data pdata;
+};
+
+#define GPIO_INVALID -1
+
+static inline bool gpiommc_is_registered(struct gpiommc_configfs_device *dev)
+{
+ return (dev->pdev != NULL);
+}
+
+static inline struct gpiommc_configfs_device *ci_to_gpiommc(struct config_item *item)
+{
+ return item ? container_of(item, struct gpiommc_configfs_device, item) : NULL;
+}
+
+static struct configfs_attribute gpiommc_attr_DI = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_data_in",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_DO = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_data_out",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CLK = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_clock",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CS = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_chipselect",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_CS_activelow = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "gpio_chipselect_activelow",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_spimode = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "spi_mode",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_spidelay = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "spi_delay",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_max_bus_speed = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "max_bus_speed",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute gpiommc_attr_register = {
+ .ca_owner = THIS_MODULE,
+ .ca_name = "register",
+ .ca_mode = S_IRUGO | S_IWUSR,
+};
+
+static struct configfs_attribute *gpiommc_config_attrs[] = {
+ &gpiommc_attr_DI,
+ &gpiommc_attr_DO,
+ &gpiommc_attr_CLK,
+ &gpiommc_attr_CS,
+ &gpiommc_attr_CS_activelow,
+ &gpiommc_attr_spimode,
+ &gpiommc_attr_spidelay,
+ &gpiommc_attr_max_bus_speed,
+ &gpiommc_attr_register,
+ NULL,
+};
+
+static ssize_t gpiommc_config_attr_show(struct config_item *item,
+ struct configfs_attribute *attr,
+ char *page)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+ ssize_t count = 0;
+ unsigned int gpio;
+ int err = 0;
+
+ if (attr == &gpiommc_attr_DI) {
+ gpio = dev->pdata.pins.gpio_di;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_DO) {
+ gpio = dev->pdata.pins.gpio_do;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CLK) {
+ gpio = dev->pdata.pins.gpio_clk;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS) {
+ gpio = dev->pdata.pins.gpio_cs;
+ if (gpio == GPIO_INVALID)
+ count = snprintf(page, PAGE_SIZE, "not configured\n");
+ else
+ count = snprintf(page, PAGE_SIZE, "%u\n", gpio);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS_activelow) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.pins.cs_activelow);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spimode) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.mode);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spidelay) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ !dev->pdata.no_spi_delay);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_max_bus_speed) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ dev->pdata.max_bus_speed);
+ goto out;
+ }
+ if (attr == &gpiommc_attr_register) {
+ count = snprintf(page, PAGE_SIZE, "%u\n",
+ gpiommc_is_registered(dev));
+ goto out;
+ }
+ WARN_ON(1);
+ err = -ENOSYS;
+out:
+ return err ? err : count;
+}
+
+static int gpiommc_do_register(struct gpiommc_configfs_device *dev,
+ const char *name)
+{
+ int err;
+
+ if (gpiommc_is_registered(dev))
+ return 0;
+
+ if (!gpio_is_valid(dev->pdata.pins.gpio_di) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_do) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_clk) ||
+ !gpio_is_valid(dev->pdata.pins.gpio_cs)) {
+ printk(KERN_ERR PFX
+ "configfs: Invalid GPIO pin number(s)\n");
+ return -EINVAL;
+ }
+
+ strlcpy(dev->pdata.name, name,
+ sizeof(dev->pdata.name));
+
+ dev->pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME,
+ gpiommc_next_id());
+ if (!dev->pdev)
+ return -ENOMEM;
+ err = platform_device_add_data(dev->pdev, &dev->pdata,
+ sizeof(dev->pdata));
+ if (err) {
+ platform_device_put(dev->pdev);
+ return err;
+ }
+ err = platform_device_add(dev->pdev);
+ if (err) {
+ platform_device_put(dev->pdev);
+ return err;
+ }
+
+ return 0;
+}
+
+static void gpiommc_do_unregister(struct gpiommc_configfs_device *dev)
+{
+ if (!gpiommc_is_registered(dev))
+ return;
+
+ platform_device_unregister(dev->pdev);
+ dev->pdev = NULL;
+}
+
+static ssize_t gpiommc_config_attr_store(struct config_item *item,
+ struct configfs_attribute *attr,
+ const char *page, size_t count)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+ int err = -EINVAL;
+ unsigned long data;
+
+ if (attr == &gpiommc_attr_register) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data == 1)
+ err = gpiommc_do_register(dev, item->ci_name);
+ if (data == 0) {
+ gpiommc_do_unregister(dev);
+ err = 0;
+ }
+ goto out;
+ }
+
+ if (gpiommc_is_registered(dev)) {
+ /* The rest of the config parameters can only be set
+ * as long as the device is not registered, yet. */
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (attr == &gpiommc_attr_DI) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_di = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_DO) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_do = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CLK) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_clk = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (!gpio_is_valid(data))
+ goto out;
+ dev->pdata.pins.gpio_cs = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_CS_activelow) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data != 0 && data != 1)
+ goto out;
+ dev->pdata.pins.cs_activelow = data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spimode) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ switch (data) {
+ case 0:
+ dev->pdata.mode = SPI_MODE_0;
+ break;
+ case 1:
+ dev->pdata.mode = SPI_MODE_1;
+ break;
+ case 2:
+ dev->pdata.mode = SPI_MODE_2;
+ break;
+ case 3:
+ dev->pdata.mode = SPI_MODE_3;
+ break;
+ default:
+ goto out;
+ }
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_spidelay) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data != 0 && data != 1)
+ goto out;
+ dev->pdata.no_spi_delay = !data;
+ err = 0;
+ goto out;
+ }
+ if (attr == &gpiommc_attr_max_bus_speed) {
+ err = strict_strtoul(page, 10, &data);
+ if (err)
+ goto out;
+ err = -EINVAL;
+ if (data > UINT_MAX)
+ goto out;
+ dev->pdata.max_bus_speed = data;
+ err = 0;
+ goto out;
+ }
+ WARN_ON(1);
+ err = -ENOSYS;
+out:
+ return err ? err : count;
+}
+
+static void gpiommc_config_item_release(struct config_item *item)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+
+ kfree(dev);
+}
+
+static struct configfs_item_operations gpiommc_config_item_ops = {
+ .release = gpiommc_config_item_release,
+ .show_attribute = gpiommc_config_attr_show,
+ .store_attribute = gpiommc_config_attr_store,
+};
+
+static struct config_item_type gpiommc_dev_ci_type = {
+ .ct_item_ops = &gpiommc_config_item_ops,
+ .ct_attrs = gpiommc_config_attrs,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct config_item *gpiommc_make_item(struct config_group *group,
+ const char *name)
+{
+ struct gpiommc_configfs_device *dev;
+
+ if (strlen(name) > GPIOMMC_MAX_NAMELEN) {
+ printk(KERN_ERR PFX "configfs: device name too long\n");
+ return NULL;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ config_item_init_type_name(&dev->item, name,
+ &gpiommc_dev_ci_type);
+
+ /* Assign default configuration */
+ dev->pdata.pins.gpio_di = GPIO_INVALID;
+ dev->pdata.pins.gpio_do = GPIO_INVALID;
+ dev->pdata.pins.gpio_clk = GPIO_INVALID;
+ dev->pdata.pins.gpio_cs = GPIO_INVALID;
+ dev->pdata.pins.cs_activelow = 1;
+ dev->pdata.mode = SPI_MODE_0;
+ dev->pdata.no_spi_delay = 0;
+ dev->pdata.max_bus_speed = 5000000; /* 5 MHz */
+
+ return &(dev->item);
+}
+
+static void gpiommc_drop_item(struct config_group *group,
+ struct config_item *item)
+{
+ struct gpiommc_configfs_device *dev = ci_to_gpiommc(item);
+
+ gpiommc_do_unregister(dev);
+ kfree(dev);
+}
+
+static struct configfs_group_operations gpiommc_ct_group_ops = {
+ .make_item = gpiommc_make_item,
+ .drop_item = gpiommc_drop_item,
+};
+
+static struct config_item_type gpiommc_ci_type = {
+ .ct_group_ops = &gpiommc_ct_group_ops,
+ .ct_owner = THIS_MODULE,
+};
+
+static struct configfs_subsystem gpiommc_subsys = {
+ .su_group = {
+ .cg_item = {
+ .ci_namebuf = GPIOMMC_PLATDEV_NAME,
+ .ci_type = &gpiommc_ci_type,
+ },
+ },
+ .su_mutex = __MUTEX_INITIALIZER(gpiommc_subsys.su_mutex),
+};
+
+#endif /* CONFIG_GPIOMMC_CONFIGFS */
+
+static struct platform_driver gpiommc_plat_driver = {
+ .probe = gpiommc_probe,
+ .remove = gpiommc_remove,
+ .driver = {
+ .name = GPIOMMC_PLATDEV_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+int gpiommc_next_id(void)
+{
+ static atomic_t counter = ATOMIC_INIT(-1);
+
+ return atomic_inc_return(&counter);
+}
+EXPORT_SYMBOL(gpiommc_next_id);
+
+static int __init gpiommc_modinit(void)
+{
+ int err;
+
+ err = platform_driver_register(&gpiommc_plat_driver);
+ if (err)
+ return err;
+
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+ config_group_init(&gpiommc_subsys.su_group);
+ err = configfs_register_subsystem(&gpiommc_subsys);
+ if (err) {
+ platform_driver_unregister(&gpiommc_plat_driver);
+ return err;
+ }
+#endif /* CONFIG_GPIOMMC_CONFIGFS */
+
+ return 0;
+}
+module_init(gpiommc_modinit);
+
+static void __exit gpiommc_modexit(void)
+{
+#ifdef CONFIG_GPIOMMC_CONFIGFS
+ configfs_unregister_subsystem(&gpiommc_subsys);
+#endif
+ platform_driver_unregister(&gpiommc_plat_driver);
+}
+module_exit(gpiommc_modexit);
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -192,3 +192,28 @@ config MMC_TMIO
help
This provides support for the SD/MMC cell found in TC6393XB,
T7L66XB and also ipaq ASIC3
+
+config GPIOMMC
+ tristate "MMC/SD over GPIO-based SPI"
+ depends on MMC && MMC_SPI && SPI_GPIO
+ help
+ This driver hooks up the mmc_spi and spi_gpio modules so that
+ MMC/SD cards can be used on a GPIO based bus by bitbanging
+ the SPI protocol in software.
+
+ This driver provides a configfs interface to dynamically create
+ and destroy GPIO-based MMC/SD card devices. It also provides
+ a platform device interface API.
+ See Documentation/gpiommc.txt for details.
+
+ The module will be called gpiommc.
+
+ If unsure, say N.
+
+config GPIOMMC_CONFIGFS
+ bool
+ depends on GPIOMMC && CONFIGFS_FS
+ default y
+ help
+ This option automatically enables configfs support for gpiommc
+ if configfs is available.
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -22,4 +22,5 @@ obj-$(CONFIG_MMC_SPI) += mmc_spi.o
obj-$(CONFIG_MMC_S3C) += s3cmci.o
obj-$(CONFIG_MMC_SDRICOH_CS) += sdricoh_cs.o
obj-$(CONFIG_MMC_TMIO) += tmio_mmc.o
+obj-$(CONFIG_GPIOMMC) += gpiommc.o
--- /dev/null
+++ b/include/linux/mmc/gpiommc.h
@@ -0,0 +1,71 @@
+/*
+ * Device driver for MMC/SD cards driven over a GPIO bus.
+ *
+ * Copyright (c) 2008 Michael Buesch
+ *
+ * Licensed under the GNU/GPL version 2.
+ */
+#ifndef LINUX_GPIOMMC_H_
+#define LINUX_GPIOMMC_H_
+
+#include <linux/types.h>
+
+
+#define GPIOMMC_MAX_NAMELEN 15
+#define GPIOMMC_MAX_NAMELEN_STR __stringify(GPIOMMC_MAX_NAMELEN)
+
+/**
+ * struct gpiommc_pins - Hardware pin assignments
+ *
+ * @gpio_di: The GPIO number of the DATA IN pin
+ * @gpio_do: The GPIO number of the DATA OUT pin
+ * @gpio_clk: The GPIO number of the CLOCK pin
+ * @gpio_cs: The GPIO number of the CHIPSELECT pin
+ * @cs_activelow: If true, the chip is considered selected if @gpio_cs is low.
+ */
+struct gpiommc_pins {
+ unsigned int gpio_di;
+ unsigned int gpio_do;
+ unsigned int gpio_clk;
+ unsigned int gpio_cs;
+ bool cs_activelow;
+};
+
+/**
+ * struct gpiommc_platform_data - Platform data for a MMC-over-SPI-GPIO device.
+ *
+ * @name: The unique name string of the device.
+ * @pins: The hardware pin assignments.
+ * @mode: The hardware mode. This is either SPI_MODE_0,
+ * SPI_MODE_1, SPI_MODE_2 or SPI_MODE_3. See the SPI documentation.
+ * @no_spi_delay: Do not use delays in the lowlevel SPI bitbanging code.
+ * This is not standards compliant, but may be required for some
+ * embedded machines to gain reasonable speed.
+ * @max_bus_speed: The maximum speed of the SPI bus, in Hertz.
+ */
+struct gpiommc_platform_data {
+ char name[GPIOMMC_MAX_NAMELEN + 1];
+ struct gpiommc_pins pins;
+ u8 mode;
+ bool no_spi_delay;
+ unsigned int max_bus_speed;
+};
+
+/**
+ * GPIOMMC_PLATDEV_NAME - The platform device name string.
+ *
+ * The name string that has to be used for platform_device_alloc
+ * when allocating a gpiommc device.
+ */
+#define GPIOMMC_PLATDEV_NAME "gpiommc"
+
+/**
+ * gpiommc_next_id - Get another platform device ID number.
+ *
+ * This returns the next platform device ID number that has to be used
+ * for platform_device_alloc. The ID is opaque and should not be used for
+ * anything else.
+ */
+int gpiommc_next_id(void);
+
+#endif /* LINUX_GPIOMMC_H_ */
--- /dev/null
+++ b/Documentation/gpiommc.txt
@@ -0,0 +1,97 @@
+GPIOMMC - Driver for an MMC/SD card on a bitbanging GPIO SPI bus
+================================================================
+
+The gpiommc module hooks up the mmc_spi and spi_gpio modules for running an
+MMC or SD card on GPIO pins.
+
+Two interfaces for registering a new MMC/SD card device are provided:
+A static platform-device based mechanism and a dynamic configfs based interface.
+
+
+Registering devices via platform-device
+=======================================
+
+The platform-device interface is used for registering MMC/SD devices that are
+part of the hardware platform. This is most useful only for embedded machines
+with MMC/SD devices statically connected to the platform GPIO bus.
+
+The data structures are declared in <linux/mmc/gpiommc.h>.
+
+To register a new device, define an instance of struct gpiommc_platform_data.
+This structure holds any information about how the device is hooked up to the
+GPIO pins and what hardware modes the device supports. See the docbook-style
+documentation in the header file for more information on the struct fields.
+
+Then allocate a new instance of a platform device by doing:
+
+ pdev = platform_device_alloc(GPIOMMC_PLATDEV_NAME, gpiommc_next_id());
+
+This will allocate the platform device data structures and hook it up to the
+gpiommc driver.
+Then add the gpiommc_platform_data to the platform device.
+
+ err = platform_device_add_data(pdev, pdata, sizeof(struct gpiommc_platform_data));
+
+You may free the local instance of struct gpiommc_platform_data now. (So the
+struct may be allocated on the stack, too).
+Now simply register the platform device.
+
+ err = platform_device_add(pdev);
+
+Done. The gpiommc probe routine will be invoked now and you should see a kernel
+log message for the added device.
+
+
+Registering devices via configfs
+================================
+
+MMC/SD cards connected via GPIO often are a pretty dynamic thing, as for example
+selfmade hacks for soldering an MMC/SD card to standard GPIO pins on embedded
+hardware are a common situation.
+So we provide a dynamic interface to conveniently handle adding and removing
+devices from userspace, without the need to recompile the kernel.
+
+The "gpiommc" subdirectory at the configfs mountpoint is used for handling
+the dynamic configuration.
+
+To create a new device, it must first be allocated with mkdir.
+The following command will allocate a device named "my_mmc":
+ mkdir /config/gpiommc/my_mmc
+
+There are several configuration files available in the new
+/config/gpiommc/my_mmc/ directory:
+
+gpio_data_in = The SPI data-IN GPIO pin number.
+gpio_data_out = The SPI data-OUT GPIO pin number.
+gpio_clock = The SPI Clock GPIO pin number.
+gpio_chipselect = The SPI Chipselect GPIO pin number.
+gpio_chipselect_activelow = Boolean. If 0, Chipselect is active-HIGH.
+ If 1, Chipselect is active-LOW.
+spi_mode = The SPI data mode. Can be 0-3.
+spi_delay = Enable all delays in the lowlevel bitbanging.
+max_bus_speed = The maximum SPI bus speed. In Hertz.
+
+register = Not a configuration parameter.
+ Used to register the configured card
+ with the kernel.
+
+The device must first get configured and then registered by writing "1" to
+the "register" file.
+The configuration parameters "gpio_data_in", "gpio_data_out", "gpio_clock"
+and "gpio_chipselect" are essential and _must_ be configured before writing
+"1" to the "register" file. The registration will fail, otherwise.
+
+The default values for the other parameters are:
+gpio_chipselect_activelow = 1 (CS active-LOW)
+spi_mode = 0 (SPI_MODE_0)
+spi_delay = 1 (enabled)
+max_bus_speed = 5000000 (5 Mhz)
+
+Configuration values can not be changed after registration. To unregister
+the device, write a "0" to the "register" file. The configuration can be
+changed again after unregistering.
+
+To completely remove the device, simply rmdir the directory
+(/config/gpiommc/my_mmc in this example).
+There's no need to first unregister the device before removing it. That will
+be done automatically.
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1910,6 +1910,11 @@ W: http://moinejf.free.fr
L: video4linux-list@redhat.com
S: Maintained
+GPIOMMC DRIVER
+P: Michael Buesch
+M: mb@bu3sch.de
+S: Maintained
+
HARDWARE MONITORING
L: lm-sensors@lm-sensors.org
W: http://www.lm-sensors.org/

View file

@ -0,0 +1,58 @@
The gpiommc configfs context structure needs locking, as configfs
does not lock access between files.
--- a/drivers/mmc/host/gpiommc.c
+++ b/drivers/mmc/host/gpiommc.c
@@ -143,6 +143,8 @@ struct gpiommc_configfs_device {
struct platform_device *pdev;
/* The configuration */
struct gpiommc_platform_data pdata;
+ /* Mutex to protect this structure */
+ struct mutex mutex;
};
#define GPIO_INVALID -1
@@ -233,6 +235,8 @@ static ssize_t gpiommc_config_attr_show(
unsigned int gpio;
int err = 0;
+ mutex_lock(&dev->mutex);
+
if (attr == &gpiommc_attr_DI) {
gpio = dev->pdata.pins.gpio_di;
if (gpio == GPIO_INVALID)
@@ -293,6 +297,8 @@ static ssize_t gpiommc_config_attr_show(
WARN_ON(1);
err = -ENOSYS;
out:
+ mutex_unlock(&dev->mutex);
+
return err ? err : count;
}
@@ -352,6 +358,8 @@ static ssize_t gpiommc_config_attr_store
int err = -EINVAL;
unsigned long data;
+ mutex_lock(&dev->mutex);
+
if (attr == &gpiommc_attr_register) {
err = strict_strtoul(page, 10, &data);
if (err)
@@ -477,6 +485,8 @@ static ssize_t gpiommc_config_attr_store
WARN_ON(1);
err = -ENOSYS;
out:
+ mutex_unlock(&dev->mutex);
+
return err ? err : count;
}
@@ -513,6 +523,7 @@ static struct config_item *gpiommc_make_
if (!dev)
return NULL;
+ mutex_init(&dev->mutex);
config_item_init_type_name(&dev->item, name,
&gpiommc_dev_ci_type);

View file

@ -0,0 +1,103 @@
--- a/include/linux/netfilter/xt_sctp.h
+++ b/include/linux/netfilter/xt_sctp.h
@@ -37,54 +37,68 @@ struct xt_sctp_info {
#define SCTP_CHUNKMAP_SET(chunkmap, type) \
do { \
- (chunkmap)[type / bytes(u_int32_t)] |= \
+ chunkmap[type / bytes(u_int32_t)] |= \
1 << (type % bytes(u_int32_t)); \
} while (0)
#define SCTP_CHUNKMAP_CLEAR(chunkmap, type) \
do { \
- (chunkmap)[type / bytes(u_int32_t)] &= \
+ chunkmap[type / bytes(u_int32_t)] &= \
~(1 << (type % bytes(u_int32_t))); \
} while (0)
#define SCTP_CHUNKMAP_IS_SET(chunkmap, type) \
({ \
- ((chunkmap)[type / bytes (u_int32_t)] & \
+ (chunkmap[type / bytes (u_int32_t)] & \
(1 << (type % bytes (u_int32_t)))) ? 1: 0; \
})
-#define SCTP_CHUNKMAP_RESET(chunkmap) \
- memset((chunkmap), 0, sizeof(chunkmap))
+#define SCTP_CHUNKMAP_RESET(chunkmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \
+ chunkmap[i] = 0; \
+ } while (0)
-#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
- memset((chunkmap), ~0U, sizeof(chunkmap))
+#define SCTP_CHUNKMAP_SET_ALL(chunkmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) \
+ chunkmap[i] = ~0; \
+ } while (0)
-#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
- memcpy((destmap), (srcmap), sizeof(srcmap))
+#define SCTP_CHUNKMAP_COPY(destmap, srcmap) \
+ do { \
+ int i; \
+ for (i = 0; i < ARRAY_SIZE(srcmap); i++) \
+ destmap[i] = srcmap[i]; \
+ } while (0)
+
+#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
+({ \
+ int i; \
+ int flag = 1; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \
+ if (chunkmap[i]) { \
+ flag = 0; \
+ break; \
+ } \
+ } \
+ flag; \
+})
-#define SCTP_CHUNKMAP_IS_CLEAR(chunkmap) \
- __sctp_chunkmap_is_clear((chunkmap), ARRAY_SIZE(chunkmap))
-static inline bool
-__sctp_chunkmap_is_clear(const u_int32_t *chunkmap, unsigned int n)
-{
- unsigned int i;
- for (i = 0; i < n; ++i)
- if (chunkmap[i])
- return false;
- return true;
-}
-
-#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
- __sctp_chunkmap_is_all_set((chunkmap), ARRAY_SIZE(chunkmap))
-static inline bool
-__sctp_chunkmap_is_all_set(const u_int32_t *chunkmap, unsigned int n)
-{
- unsigned int i;
- for (i = 0; i < n; ++i)
- if (chunkmap[i] != ~0U)
- return false;
- return true;
-}
+#define SCTP_CHUNKMAP_IS_ALL_SET(chunkmap) \
+({ \
+ int i; \
+ int flag = 1; \
+ for (i = 0; i < ARRAY_SIZE(chunkmap); i++) { \
+ if (chunkmap[i] != ~0) { \
+ flag = 0; \
+ break; \
+ } \
+ } \
+ flag; \
+})
#endif /* _XT_SCTP_H_ */

View file

@ -0,0 +1,524 @@
--- a/arch/powerpc/boot/crtsavres.S
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Special support for eabi and SVR4
- *
- * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
- * Written By Michael Meissner
- *
- * Based on gcc/config/rs6000/crtsavres.asm from gcc
- *
- * This file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * In addition to the permissions in the GNU General Public License, the
- * Free Software Foundation gives you unlimited permission to link the
- * compiled version of this file with other programs, and to distribute
- * those programs without any restriction coming from the use of this
- * file. (The General Public License restrictions do apply in other
- * respects; for example, they cover modification of the file, and
- * distribution when not linked into another program.)
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * As a special exception, if you link this library with files
- * compiled with GCC to produce an executable, this does not cause
- * the resulting executable to be covered by the GNU General Public License.
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- */
-
- .file "crtsavres.S"
- .section ".text"
-
-/* On PowerPC64 Linux, these functions are provided by the linker. */
-#ifndef __powerpc64__
-
-#define _GLOBAL(name) \
- .type name,@function; \
- .globl name; \
-name:
-
-/* Routines for saving integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer save area. */
-
-_GLOBAL(_savegpr_14)
-_GLOBAL(_save32gpr_14)
- stw 14,-72(11) /* save gp registers */
-_GLOBAL(_savegpr_15)
-_GLOBAL(_save32gpr_15)
- stw 15,-68(11)
-_GLOBAL(_savegpr_16)
-_GLOBAL(_save32gpr_16)
- stw 16,-64(11)
-_GLOBAL(_savegpr_17)
-_GLOBAL(_save32gpr_17)
- stw 17,-60(11)
-_GLOBAL(_savegpr_18)
-_GLOBAL(_save32gpr_18)
- stw 18,-56(11)
-_GLOBAL(_savegpr_19)
-_GLOBAL(_save32gpr_19)
- stw 19,-52(11)
-_GLOBAL(_savegpr_20)
-_GLOBAL(_save32gpr_20)
- stw 20,-48(11)
-_GLOBAL(_savegpr_21)
-_GLOBAL(_save32gpr_21)
- stw 21,-44(11)
-_GLOBAL(_savegpr_22)
-_GLOBAL(_save32gpr_22)
- stw 22,-40(11)
-_GLOBAL(_savegpr_23)
-_GLOBAL(_save32gpr_23)
- stw 23,-36(11)
-_GLOBAL(_savegpr_24)
-_GLOBAL(_save32gpr_24)
- stw 24,-32(11)
-_GLOBAL(_savegpr_25)
-_GLOBAL(_save32gpr_25)
- stw 25,-28(11)
-_GLOBAL(_savegpr_26)
-_GLOBAL(_save32gpr_26)
- stw 26,-24(11)
-_GLOBAL(_savegpr_27)
-_GLOBAL(_save32gpr_27)
- stw 27,-20(11)
-_GLOBAL(_savegpr_28)
-_GLOBAL(_save32gpr_28)
- stw 28,-16(11)
-_GLOBAL(_savegpr_29)
-_GLOBAL(_save32gpr_29)
- stw 29,-12(11)
-_GLOBAL(_savegpr_30)
-_GLOBAL(_save32gpr_30)
- stw 30,-8(11)
-_GLOBAL(_savegpr_31)
-_GLOBAL(_save32gpr_31)
- stw 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14)
-_GLOBAL(_rest32gpr_14)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15)
-_GLOBAL(_rest32gpr_15)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16)
-_GLOBAL(_rest32gpr_16)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17)
-_GLOBAL(_rest32gpr_17)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18)
-_GLOBAL(_rest32gpr_18)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19)
-_GLOBAL(_rest32gpr_19)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20)
-_GLOBAL(_rest32gpr_20)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21)
-_GLOBAL(_rest32gpr_21)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22)
-_GLOBAL(_rest32gpr_22)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23)
-_GLOBAL(_rest32gpr_23)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24)
-_GLOBAL(_rest32gpr_24)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25)
-_GLOBAL(_rest32gpr_25)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26)
-_GLOBAL(_rest32gpr_26)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27)
-_GLOBAL(_rest32gpr_27)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28)
-_GLOBAL(_rest32gpr_28)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29)
-_GLOBAL(_rest32gpr_29)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30)
-_GLOBAL(_rest32gpr_30)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31)
-_GLOBAL(_rest32gpr_31)
- lwz 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14_x)
-_GLOBAL(_rest32gpr_14_x)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15_x)
-_GLOBAL(_rest32gpr_15_x)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16_x)
-_GLOBAL(_rest32gpr_16_x)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17_x)
-_GLOBAL(_rest32gpr_17_x)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18_x)
-_GLOBAL(_rest32gpr_18_x)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19_x)
-_GLOBAL(_rest32gpr_19_x)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20_x)
-_GLOBAL(_rest32gpr_20_x)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21_x)
-_GLOBAL(_rest32gpr_21_x)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22_x)
-_GLOBAL(_rest32gpr_22_x)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23_x)
-_GLOBAL(_rest32gpr_23_x)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24_x)
-_GLOBAL(_rest32gpr_24_x)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25_x)
-_GLOBAL(_rest32gpr_25_x)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26_x)
-_GLOBAL(_rest32gpr_26_x)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27_x)
-_GLOBAL(_rest32gpr_27_x)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28_x)
-_GLOBAL(_rest32gpr_28_x)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29_x)
-_GLOBAL(_rest32gpr_29_x)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30_x)
-_GLOBAL(_rest32gpr_30_x)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31_x)
-_GLOBAL(_rest32gpr_31_x)
- lwz 0,4(11)
- lwz 31,-4(11)
- mtlr 0
- mr 1,11
- blr
-#endif
--- a/arch/powerpc/boot/Makefile
+++ b/arch/powerpc/boot/Makefile
@@ -53,7 +53,7 @@ $(addprefix $(obj)/,$(zlib) cuboot-c2k.o
$(addprefix $(obj)/,$(zliblinuxheader)) $(addprefix $(obj)/,$(zlibheader))
src-libfdt := fdt.c fdt_ro.c fdt_wip.c fdt_sw.c fdt_rw.c fdt_strerror.c
-src-wlib := string.S crt0.S crtsavres.S stdio.c main.c \
+src-wlib := string.S crt0.S stdio.c main.c \
$(addprefix libfdt/,$(src-libfdt)) libfdt-wrapper.c \
ns16550.c serial.c simple_alloc.c div64.S util.S \
gunzip_util.c elf_util.c $(zlib) devtree.c oflib.c ofconsole.c \
--- a/arch/powerpc/kernel/prom_init_check.sh
+++ b/arch/powerpc/kernel/prom_init_check.sh
@@ -48,20 +48,6 @@ do
fi
done
- # ignore register save/restore funcitons
- if [ "${UNDEF:0:9}" = "_restgpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:11}" = "_rest32gpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:9}" = "_savegpr_" ]; then
- OK=1
- fi
- if [ "${UNDEF:0:11}" = "_save32gpr_" ]; then
- OK=1
- fi
-
if [ $OK -eq 0 ]; then
ERROR=1
echo "Error: External symbol '$UNDEF' referenced" \
--- a/arch/powerpc/lib/crtsavres.S
+++ /dev/null
@@ -1,229 +0,0 @@
-/*
- * Special support for eabi and SVR4
- *
- * Copyright (C) 1995, 1996, 1998, 2000, 2001 Free Software Foundation, Inc.
- * Copyright 2008 Freescale Semiconductor, Inc.
- * Written By Michael Meissner
- *
- * Based on gcc/config/rs6000/crtsavres.asm from gcc
- *
- * This file is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2, or (at your option) any
- * later version.
- *
- * In addition to the permissions in the GNU General Public License, the
- * Free Software Foundation gives you unlimited permission to link the
- * compiled version of this file with other programs, and to distribute
- * those programs without any restriction coming from the use of this
- * file. (The General Public License restrictions do apply in other
- * respects; for example, they cover modification of the file, and
- * distribution when not linked into another program.)
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 51 Franklin Street, Fifth Floor,
- * Boston, MA 02110-1301, USA.
- *
- * As a special exception, if you link this library with files
- * compiled with GCC to produce an executable, this does not cause
- * the resulting executable to be covered by the GNU General Public License.
- * This exception does not however invalidate any other reasons why
- * the executable file might be covered by the GNU General Public License.
- */
-
-#include <asm/ppc_asm.h>
-
- .file "crtsavres.S"
- .section ".text"
-
-#ifdef CONFIG_CC_OPTIMIZE_FOR_SIZE
-
-/* Routines for saving integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer save area. */
-
-_GLOBAL(_savegpr_14)
-_GLOBAL(_save32gpr_14)
- stw 14,-72(11) /* save gp registers */
-_GLOBAL(_savegpr_15)
-_GLOBAL(_save32gpr_15)
- stw 15,-68(11)
-_GLOBAL(_savegpr_16)
-_GLOBAL(_save32gpr_16)
- stw 16,-64(11)
-_GLOBAL(_savegpr_17)
-_GLOBAL(_save32gpr_17)
- stw 17,-60(11)
-_GLOBAL(_savegpr_18)
-_GLOBAL(_save32gpr_18)
- stw 18,-56(11)
-_GLOBAL(_savegpr_19)
-_GLOBAL(_save32gpr_19)
- stw 19,-52(11)
-_GLOBAL(_savegpr_20)
-_GLOBAL(_save32gpr_20)
- stw 20,-48(11)
-_GLOBAL(_savegpr_21)
-_GLOBAL(_save32gpr_21)
- stw 21,-44(11)
-_GLOBAL(_savegpr_22)
-_GLOBAL(_save32gpr_22)
- stw 22,-40(11)
-_GLOBAL(_savegpr_23)
-_GLOBAL(_save32gpr_23)
- stw 23,-36(11)
-_GLOBAL(_savegpr_24)
-_GLOBAL(_save32gpr_24)
- stw 24,-32(11)
-_GLOBAL(_savegpr_25)
-_GLOBAL(_save32gpr_25)
- stw 25,-28(11)
-_GLOBAL(_savegpr_26)
-_GLOBAL(_save32gpr_26)
- stw 26,-24(11)
-_GLOBAL(_savegpr_27)
-_GLOBAL(_save32gpr_27)
- stw 27,-20(11)
-_GLOBAL(_savegpr_28)
-_GLOBAL(_save32gpr_28)
- stw 28,-16(11)
-_GLOBAL(_savegpr_29)
-_GLOBAL(_save32gpr_29)
- stw 29,-12(11)
-_GLOBAL(_savegpr_30)
-_GLOBAL(_save32gpr_30)
- stw 30,-8(11)
-_GLOBAL(_savegpr_31)
-_GLOBAL(_save32gpr_31)
- stw 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14)
-_GLOBAL(_rest32gpr_14)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15)
-_GLOBAL(_rest32gpr_15)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16)
-_GLOBAL(_rest32gpr_16)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17)
-_GLOBAL(_rest32gpr_17)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18)
-_GLOBAL(_rest32gpr_18)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19)
-_GLOBAL(_rest32gpr_19)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20)
-_GLOBAL(_rest32gpr_20)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21)
-_GLOBAL(_rest32gpr_21)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22)
-_GLOBAL(_rest32gpr_22)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23)
-_GLOBAL(_rest32gpr_23)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24)
-_GLOBAL(_rest32gpr_24)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25)
-_GLOBAL(_rest32gpr_25)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26)
-_GLOBAL(_rest32gpr_26)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27)
-_GLOBAL(_rest32gpr_27)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28)
-_GLOBAL(_rest32gpr_28)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29)
-_GLOBAL(_rest32gpr_29)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30)
-_GLOBAL(_rest32gpr_30)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31)
-_GLOBAL(_rest32gpr_31)
- lwz 31,-4(11)
- blr
-
-/* Routines for restoring integer registers, called by the compiler. */
-/* Called with r11 pointing to the stack header word of the caller of the */
-/* function, just beyond the end of the integer restore area. */
-
-_GLOBAL(_restgpr_14_x)
-_GLOBAL(_rest32gpr_14_x)
- lwz 14,-72(11) /* restore gp registers */
-_GLOBAL(_restgpr_15_x)
-_GLOBAL(_rest32gpr_15_x)
- lwz 15,-68(11)
-_GLOBAL(_restgpr_16_x)
-_GLOBAL(_rest32gpr_16_x)
- lwz 16,-64(11)
-_GLOBAL(_restgpr_17_x)
-_GLOBAL(_rest32gpr_17_x)
- lwz 17,-60(11)
-_GLOBAL(_restgpr_18_x)
-_GLOBAL(_rest32gpr_18_x)
- lwz 18,-56(11)
-_GLOBAL(_restgpr_19_x)
-_GLOBAL(_rest32gpr_19_x)
- lwz 19,-52(11)
-_GLOBAL(_restgpr_20_x)
-_GLOBAL(_rest32gpr_20_x)
- lwz 20,-48(11)
-_GLOBAL(_restgpr_21_x)
-_GLOBAL(_rest32gpr_21_x)
- lwz 21,-44(11)
-_GLOBAL(_restgpr_22_x)
-_GLOBAL(_rest32gpr_22_x)
- lwz 22,-40(11)
-_GLOBAL(_restgpr_23_x)
-_GLOBAL(_rest32gpr_23_x)
- lwz 23,-36(11)
-_GLOBAL(_restgpr_24_x)
-_GLOBAL(_rest32gpr_24_x)
- lwz 24,-32(11)
-_GLOBAL(_restgpr_25_x)
-_GLOBAL(_rest32gpr_25_x)
- lwz 25,-28(11)
-_GLOBAL(_restgpr_26_x)
-_GLOBAL(_rest32gpr_26_x)
- lwz 26,-24(11)
-_GLOBAL(_restgpr_27_x)
-_GLOBAL(_rest32gpr_27_x)
- lwz 27,-20(11)
-_GLOBAL(_restgpr_28_x)
-_GLOBAL(_rest32gpr_28_x)
- lwz 28,-16(11)
-_GLOBAL(_restgpr_29_x)
-_GLOBAL(_rest32gpr_29_x)
- lwz 29,-12(11)
-_GLOBAL(_restgpr_30_x)
-_GLOBAL(_rest32gpr_30_x)
- lwz 30,-8(11)
-_GLOBAL(_restgpr_31_x)
-_GLOBAL(_rest32gpr_31_x)
- lwz 0,4(11)
- lwz 31,-4(11)
- mtlr 0
- mr 1,11
- blr
-#endif
--- a/arch/powerpc/lib/Makefile
+++ b/arch/powerpc/lib/Makefile
@@ -8,7 +8,7 @@ endif
obj-y := string.o alloc.o \
checksum_$(CONFIG_WORD_SIZE).o
-obj-$(CONFIG_PPC32) += div64.o copy_32.o crtsavres.o
+obj-$(CONFIG_PPC32) += div64.o copy_32.o
obj-$(CONFIG_HAS_IOMEM) += devres.o
obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \
--- a/arch/powerpc/Makefile
+++ b/arch/powerpc/Makefile
@@ -92,8 +92,6 @@ endif
else
KBUILD_CFLAGS += $(call cc-option,-mtune=power4)
endif
-else
-LDFLAGS_MODULE += arch/powerpc/lib/crtsavres.o
endif
ifeq ($(CONFIG_TUNE_CELL),y)

View file

@ -0,0 +1,25 @@
--- a/crypto/Kconfig
+++ b/crypto/Kconfig
@@ -707,6 +707,8 @@ config CRYPTO_ANSI_CPRNG
for cryptographic modules. Uses the Algorithm specified in
ANSI X9.31 A.2.4
+source "crypto/ocf/Kconfig"
+
source "drivers/crypto/Kconfig"
endif # if CRYPTO
--- a/crypto/Makefile
+++ b/crypto/Makefile
@@ -79,6 +79,11 @@ obj-$(CONFIG_CRYPTO_ANSI_CPRNG) += ansi_
obj-$(CONFIG_CRYPTO_TEST) += tcrypt.o
#
+# OCF
+#
+obj-$(CONFIG_OCF_OCF) += ocf/
+
+#
# generic algorithms and the async_tx api
#
obj-$(CONFIG_XOR_BLOCKS) += xor.o

View file

@ -0,0 +1,160 @@
--- a/drivers/char/random.c
+++ b/drivers/char/random.c
@@ -129,6 +129,9 @@
* unsigned int value);
* void add_interrupt_randomness(int irq);
*
+ * void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+ * int random_input_wait(void);
+ *
* add_input_randomness() uses the input layer interrupt timing, as well as
* the event type information from the hardware.
*
@@ -140,6 +143,13 @@
* a better measure, since the timing of the disk interrupts are more
* unpredictable.
*
+ * random_input_words() just provides a raw block of entropy to the input
+ * pool, such as from a hardware entropy generator.
+ *
+ * random_input_wait() suspends the caller until such time as the
+ * entropy pool falls below the write threshold, and returns a count of how
+ * much entropy (in bits) is needed to sustain the pool.
+ *
* All of these routines try to estimate how many bits of randomness a
* particular randomness source. They do this by keeping track of the
* first and second order deltas of the event timings.
@@ -689,6 +699,61 @@ void add_disk_randomness(struct gendisk
}
#endif
+/*
+ * random_input_words - add bulk entropy to pool
+ *
+ * @buf: buffer to add
+ * @wordcount: number of __u32 words to add
+ * @ent_count: total amount of entropy (in bits) to credit
+ *
+ * this provides bulk input of entropy to the input pool
+ *
+ */
+void random_input_words(__u32 *buf, size_t wordcount, int ent_count)
+{
+ mix_pool_bytes(&input_pool, buf, wordcount*4);
+
+ credit_entropy_bits(&input_pool, ent_count);
+
+ DEBUG_ENT("crediting %d bits => %d\n",
+ ent_count, input_pool.entropy_count);
+ /*
+ * Wake up waiting processes if we have enough
+ * entropy.
+ */
+ if (input_pool.entropy_count >= random_read_wakeup_thresh)
+ wake_up_interruptible(&random_read_wait);
+}
+EXPORT_SYMBOL(random_input_words);
+
+/*
+ * random_input_wait - wait until random needs entropy
+ *
+ * this function sleeps until the /dev/random subsystem actually
+ * needs more entropy, and then return the amount of entropy
+ * that it would be nice to have added to the system.
+ */
+int random_input_wait(void)
+{
+ int count;
+
+ wait_event_interruptible(random_write_wait,
+ input_pool.entropy_count < random_write_wakeup_thresh);
+
+ count = random_write_wakeup_thresh - input_pool.entropy_count;
+
+ /* likely we got woken up due to a signal */
+ if (count <= 0) count = random_read_wakeup_thresh;
+
+ DEBUG_ENT("requesting %d bits from input_wait()er %d<%d\n",
+ count,
+ input_pool.entropy_count, random_write_wakeup_thresh);
+
+ return count;
+}
+EXPORT_SYMBOL(random_input_wait);
+
+
#define EXTRACT_SIZE 10
/*********************************************************************
--- a/fs/fcntl.c
+++ b/fs/fcntl.c
@@ -139,6 +139,7 @@ asmlinkage long sys_dup(unsigned int fil
}
return ret;
}
+EXPORT_SYMBOL(sys_dup);
#define SETFL_MASK (O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
--- a/include/linux/miscdevice.h
+++ b/include/linux/miscdevice.h
@@ -12,6 +12,7 @@
#define APOLLO_MOUSE_MINOR 7
#define PC110PAD_MINOR 9
/*#define ADB_MOUSE_MINOR 10 FIXME OBSOLETE */
+#define CRYPTODEV_MINOR 70 /* /dev/crypto */
#define WATCHDOG_MINOR 130 /* Watchdog timer */
#define TEMP_MINOR 131 /* Temperature Sensor */
#define RTC_MINOR 135
--- a/include/linux/random.h
+++ b/include/linux/random.h
@@ -8,6 +8,7 @@
#define _LINUX_RANDOM_H
#include <linux/ioctl.h>
+#include <linux/types.h> /* for __u32 in user space */
/* ioctl()'s for the random number generator */
@@ -32,6 +33,30 @@
/* Clear the entropy pool and associated counters. (Superuser only.) */
#define RNDCLEARPOOL _IO( 'R', 0x06 )
+#ifdef CONFIG_FIPS_RNG
+
+/* Size of seed value - equal to AES blocksize */
+#define AES_BLOCK_SIZE_BYTES 16
+#define SEED_SIZE_BYTES AES_BLOCK_SIZE_BYTES
+/* Size of AES key */
+#define KEY_SIZE_BYTES 16
+
+/* ioctl() structure used by FIPS 140-2 Tests */
+struct rand_fips_test {
+ unsigned char key[KEY_SIZE_BYTES]; /* Input */
+ unsigned char datetime[SEED_SIZE_BYTES]; /* Input */
+ unsigned char seed[SEED_SIZE_BYTES]; /* Input */
+ unsigned char result[SEED_SIZE_BYTES]; /* Output */
+};
+
+/* FIPS 140-2 RNG Variable Seed Test. (Superuser only.) */
+#define RNDFIPSVST _IOWR('R', 0x10, struct rand_fips_test)
+
+/* FIPS 140-2 RNG Monte Carlo Test. (Superuser only.) */
+#define RNDFIPSMCT _IOWR('R', 0x11, struct rand_fips_test)
+
+#endif /* #ifdef CONFIG_FIPS_RNG */
+
struct rand_pool_info {
int entropy_count;
int buf_size;
@@ -48,6 +73,10 @@ extern void add_input_randomness(unsigne
unsigned int value);
extern void add_interrupt_randomness(int irq);
+extern void random_input_words(__u32 *buf, size_t wordcount, int ent_count);
+extern int random_input_wait(void);
+#define HAS_RANDOM_INPUT_WAIT 1
+
extern void get_random_bytes(void *buf, int nbytes);
void generate_random_uuid(unsigned char uuid_out[16]);

View file

@ -0,0 +1,11 @@
--- a/crypto/ocf/cryptosoft.c
+++ b/crypto/ocf/cryptosoft.c
@@ -47,7 +47,7 @@
#include <linux/mm.h>
#include <linux/skbuff.h>
#include <linux/random.h>
-#include <asm/scatterlist.h>
+#include <linux/scatterlist.h>
#include <cryptodev.h>
#include <uio.h>

View file

@ -0,0 +1,197 @@
--- a/crypto/ocf/random.c
+++ b/crypto/ocf/random.c
@@ -49,6 +49,7 @@
#include <linux/unistd.h>
#include <linux/poll.h>
#include <linux/random.h>
+#include <linux/kthread.h>
#include <cryptodev.h>
#ifdef CONFIG_OCF_FIPS
@@ -81,7 +82,7 @@ struct random_op {
static int random_proc(void *arg);
-static pid_t randomproc = (pid_t) -1;
+static struct task_struct *random_task;
static spinlock_t random_lock;
/*
@@ -141,13 +142,18 @@ crypto_rregister(
spin_lock_irqsave(&random_lock, flags);
list_add_tail(&rops->random_list, &random_ops);
if (!started) {
- randomproc = kernel_thread(random_proc, NULL, CLONE_FS|CLONE_FILES);
- if (randomproc < 0) {
- ret = randomproc;
+ struct task_struct *t;
+
+ t = kthread_create(random_proc, NULL, "ocf-random");
+ if (IS_ERR(t)) {
printk("crypto: crypto_rregister cannot start random thread; "
"error %d", ret);
- } else
+ ret = PTR_ERR(t);
+ } else {
+ random_task = t;
+ wake_up_process(t);
started = 1;
+ }
}
spin_unlock_irqrestore(&random_lock, flags);
@@ -172,7 +178,7 @@ crypto_runregister_all(u_int32_t driveri
spin_lock_irqsave(&random_lock, flags);
if (list_empty(&random_ops) && started)
- kill_proc(randomproc, SIGKILL, 1);
+ send_sig(SIGKILL, random_task, 1);
spin_unlock_irqrestore(&random_lock, flags);
return(0);
}
@@ -308,7 +314,7 @@ random_proc(void *arg)
bad_alloc:
spin_lock_irq(&random_lock);
- randomproc = (pid_t) -1;
+ random_task = NULL;
started = 0;
spin_unlock_irq(&random_lock);
--- a/crypto/ocf/crypto.c
+++ b/crypto/ocf/crypto.c
@@ -74,6 +74,7 @@ __FBSDID("$FreeBSD: src/sys/opencrypto/c
#include <linux/sched.h>
#include <linux/spinlock.h>
#include <linux/version.h>
+#include <linux/kthread.h>
#include <cryptodev.h>
/*
@@ -255,10 +256,10 @@ module_param(crypto_devallowsoft, int, 0
MODULE_PARM_DESC(crypto_devallowsoft,
"Enable/disable use of software crypto support");
-static pid_t cryptoproc = (pid_t) -1;
+static struct task_struct *crypto_task;
static struct completion cryptoproc_exited;
static DECLARE_WAIT_QUEUE_HEAD(cryptoproc_wait);
-static pid_t cryptoretproc = (pid_t) -1;
+static struct task_struct *cryptoret_task;
static struct completion cryptoretproc_exited;
static DECLARE_WAIT_QUEUE_HEAD(cryptoretproc_wait);
@@ -1401,7 +1402,7 @@ crypto_proc(void *arg)
wait_event_interruptible(cryptoproc_wait,
!(list_empty(&crp_q) || crypto_all_qblocked) ||
!(list_empty(&crp_kq) || crypto_all_kqblocked) ||
- cryptoproc == (pid_t) -1);
+ crypto_task == NULL);
crp_sleep = 0;
if (signal_pending (current)) {
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,0)
@@ -1414,7 +1415,7 @@ crypto_proc(void *arg)
}
CRYPTO_Q_LOCK();
dprintk("%s - awake\n", __FUNCTION__);
- if (cryptoproc == (pid_t) -1)
+ if (crypto_task == NULL)
break;
cryptostats.cs_intrs++;
}
@@ -1470,7 +1471,7 @@ crypto_ret_proc(void *arg)
dprintk("%s - sleeping\n", __FUNCTION__);
CRYPTO_RETQ_UNLOCK();
wait_event_interruptible(cryptoretproc_wait,
- cryptoretproc == (pid_t) -1 ||
+ cryptoret_task == NULL ||
!list_empty(&crp_ret_q) ||
!list_empty(&crp_ret_kq));
if (signal_pending (current)) {
@@ -1484,7 +1485,7 @@ crypto_ret_proc(void *arg)
}
CRYPTO_RETQ_LOCK();
dprintk("%s - awake\n", __FUNCTION__);
- if (cryptoretproc == (pid_t) -1) {
+ if (cryptoret_task == NULL) {
dprintk("%s - EXITING!\n", __FUNCTION__);
break;
}
@@ -1597,6 +1598,7 @@ DB_SHOW_COMMAND(kcrypto, db_show_kcrypto
static int
crypto_init(void)
{
+ struct task_struct *t;
int error;
dprintk("%s(0x%x)\n", __FUNCTION__, (int) crypto_init);
@@ -1643,23 +1645,27 @@ crypto_init(void)
init_completion(&cryptoproc_exited);
init_completion(&cryptoretproc_exited);
- cryptoproc = 0; /* to avoid race condition where proc runs first */
- cryptoproc = kernel_thread(crypto_proc, NULL, CLONE_FS|CLONE_FILES);
- if (cryptoproc < 0) {
- error = cryptoproc;
+ crypto_task = NULL; /* to avoid race condition where proc runs first */
+ t = kthread_create(crypto_proc, NULL, "ocf-crypto");
+ if (IS_ERR(t)) {
+ error = PTR_ERR(t);
printk("crypto: crypto_init cannot start crypto thread; error %d",
error);
goto bad;
}
+ wake_up_process(t);
+ crypto_task = t;
- cryptoretproc = 0; /* to avoid race condition where proc runs first */
- cryptoretproc = kernel_thread(crypto_ret_proc, NULL, CLONE_FS|CLONE_FILES);
- if (cryptoretproc < 0) {
- error = cryptoretproc;
+ cryptoret_task = NULL; /* to avoid race condition where proc runs first */
+ t = kthread_create(crypto_ret_proc, NULL, "ocf-cryptoret");
+ if (IS_ERR(t)) {
+ error = PTR_ERR(t);
printk("crypto: crypto_init cannot start cryptoret thread; error %d",
error);
goto bad;
}
+ wake_up_process(t);
+ cryptoret_task = t;
return 0;
bad:
@@ -1671,7 +1677,7 @@ bad:
static void
crypto_exit(void)
{
- pid_t p;
+ struct task_struct *t;
unsigned long d_flags;
dprintk("%s()\n", __FUNCTION__);
@@ -1681,18 +1687,18 @@ crypto_exit(void)
*/
CRYPTO_DRIVER_LOCK();
- p = cryptoproc;
- cryptoproc = (pid_t) -1;
- kill_proc(p, SIGTERM, 1);
+ t = crypto_task;
+ crypto_task = NULL;
+ send_sig(SIGTERM, t, 1);
wake_up_interruptible(&cryptoproc_wait);
CRYPTO_DRIVER_UNLOCK();
wait_for_completion(&cryptoproc_exited);
CRYPTO_DRIVER_LOCK();
- p = cryptoretproc;
- cryptoretproc = (pid_t) -1;
- kill_proc(p, SIGTERM, 1);
+ t = cryptoret_task;
+ cryptoret_task = NULL;
+ send_sig(SIGTERM, t, 1);
wake_up_interruptible(&cryptoretproc_wait);
CRYPTO_DRIVER_UNLOCK();

View file

@ -0,0 +1,11 @@
--- a/drivers/ssb/Kconfig
+++ b/drivers/ssb/Kconfig
@@ -49,7 +49,7 @@ config SSB_PCIHOST
config SSB_B43_PCI_BRIDGE
bool
depends on SSB_PCIHOST
- default n
+ default y
config SSB_PCMCIAHOST_POSSIBLE
bool