Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (24 commits) e100: do not go D3 in shutdown unless system is powering off netfilter: revised locking for x_tables Bluetooth: Fix connection establishment with low security requirement Bluetooth: Add different pairing timeout for Legacy Pairing Bluetooth: Ensure that HCI sysfs add/del is preempt safe net: Avoid extra wakeups of threads blocked in wait_for_packet() net: Fix typo in net_device_ops description. ipv4: Limit size of route cache hash table Add reference to CAPI 2.0 standard Documentation/isdn/INTERFACE.CAPI update Documentation/isdn/00-INDEX ixgbe: Fix WoL functionality for 82599 KX4 devices veth: prevent oops caused by netdev destructor xfrm: wrong hash value for temporary SA forcedeth: tx timeout fix net: Fix LL_MAX_HEADER for CONFIG_TR_MODULE mlx4_en: Handle page allocation failure during receive mlx4_en: Fix cleanup flow on cq activation vlan: update vlan carrier state for admin up/down netfilter: xt_recent: fix stack overread in compat code ...
This commit is contained in:
Коммит
3dacbdad24
|
@ -2,8 +2,14 @@
|
||||||
- this file (info on ISDN implementation for Linux)
|
- this file (info on ISDN implementation for Linux)
|
||||||
CREDITS
|
CREDITS
|
||||||
- list of the kind folks that brought you this stuff.
|
- list of the kind folks that brought you this stuff.
|
||||||
|
HiSax.cert
|
||||||
|
- information about the ITU approval certification of the HiSax driver.
|
||||||
INTERFACE
|
INTERFACE
|
||||||
- description of Linklevel and Hardwarelevel ISDN interface.
|
- description of isdn4linux Link Level and Hardware Level interfaces.
|
||||||
|
INTERFACE.fax
|
||||||
|
- description of the fax subinterface of isdn4linux.
|
||||||
|
INTERFACE.CAPI
|
||||||
|
- description of kernel CAPI Link Level to Hardware Level interface.
|
||||||
README
|
README
|
||||||
- general info on what you need and what to do for Linux ISDN.
|
- general info on what you need and what to do for Linux ISDN.
|
||||||
README.FAQ
|
README.FAQ
|
||||||
|
@ -12,6 +18,8 @@ README.audio
|
||||||
- info for running audio over ISDN.
|
- info for running audio over ISDN.
|
||||||
README.fax
|
README.fax
|
||||||
- info for using Fax over ISDN.
|
- info for using Fax over ISDN.
|
||||||
|
README.gigaset
|
||||||
|
- info on the drivers for Siemens Gigaset ISDN adapters.
|
||||||
README.icn
|
README.icn
|
||||||
- info on the ICN-ISDN-card and its driver.
|
- info on the ICN-ISDN-card and its driver.
|
||||||
README.HiSax
|
README.HiSax
|
||||||
|
@ -37,7 +45,8 @@ README.diversion
|
||||||
README.sc
|
README.sc
|
||||||
- info on driver for Spellcaster cards.
|
- info on driver for Spellcaster cards.
|
||||||
README.x25
|
README.x25
|
||||||
_ info for running X.25 over ISDN.
|
- info for running X.25 over ISDN.
|
||||||
README.hysdn
|
README.hysdn
|
||||||
- info on driver for Hypercope active HYSDN cards
|
- info on driver for Hypercope active HYSDN cards
|
||||||
|
README.mISDN
|
||||||
|
- info on the Modular ISDN subsystem (mISDN).
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
Kernel CAPI Interface to Hardware Drivers
|
||||||
|
-----------------------------------------
|
||||||
|
|
||||||
|
1. Overview
|
||||||
|
|
||||||
|
From the CAPI 2.0 specification:
|
||||||
|
COMMON-ISDN-API (CAPI) is an application programming interface standard used
|
||||||
|
to access ISDN equipment connected to basic rate interfaces (BRI) and primary
|
||||||
|
rate interfaces (PRI).
|
||||||
|
|
||||||
|
Kernel CAPI operates as a dispatching layer between CAPI applications and CAPI
|
||||||
|
hardware drivers. Hardware drivers register ISDN devices (controllers, in CAPI
|
||||||
|
lingo) with Kernel CAPI to indicate their readiness to provide their service
|
||||||
|
to CAPI applications. CAPI applications also register with Kernel CAPI,
|
||||||
|
requesting association with a CAPI device. Kernel CAPI then dispatches the
|
||||||
|
application registration to an available device, forwarding it to the
|
||||||
|
corresponding hardware driver. Kernel CAPI then forwards CAPI messages in both
|
||||||
|
directions between the application and the hardware driver.
|
||||||
|
|
||||||
|
Format and semantics of CAPI messages are specified in the CAPI 2.0 standard.
|
||||||
|
This standard is freely available from http://www.capi.org.
|
||||||
|
|
||||||
|
|
||||||
|
2. Driver and Device Registration
|
||||||
|
|
||||||
|
CAPI drivers optionally register themselves with Kernel CAPI by calling the
|
||||||
|
Kernel CAPI function register_capi_driver() with a pointer to a struct
|
||||||
|
capi_driver. This structure must be filled with the name and revision of the
|
||||||
|
driver, and optionally a pointer to a callback function, add_card(). The
|
||||||
|
registration can be revoked by calling the function unregister_capi_driver()
|
||||||
|
with a pointer to the same struct capi_driver.
|
||||||
|
|
||||||
|
CAPI drivers must register each of the ISDN devices they control with Kernel
|
||||||
|
CAPI by calling the Kernel CAPI function attach_capi_ctr() with a pointer to a
|
||||||
|
struct capi_ctr before they can be used. This structure must be filled with
|
||||||
|
the names of the driver and controller, and a number of callback function
|
||||||
|
pointers which are subsequently used by Kernel CAPI for communicating with the
|
||||||
|
driver. The registration can be revoked by calling the function
|
||||||
|
detach_capi_ctr() with a pointer to the same struct capi_ctr.
|
||||||
|
|
||||||
|
Before the device can be actually used, the driver must fill in the device
|
||||||
|
information fields 'manu', 'version', 'profile' and 'serial' in the capi_ctr
|
||||||
|
structure of the device, and signal its readiness by calling capi_ctr_ready().
|
||||||
|
From then on, Kernel CAPI may call the registered callback functions for the
|
||||||
|
device.
|
||||||
|
|
||||||
|
If the device becomes unusable for any reason (shutdown, disconnect ...), the
|
||||||
|
driver has to call capi_ctr_reseted(). This will prevent further calls to the
|
||||||
|
callback functions by Kernel CAPI.
|
||||||
|
|
||||||
|
|
||||||
|
3. Application Registration and Communication
|
||||||
|
|
||||||
|
Kernel CAPI forwards registration requests from applications (calls to CAPI
|
||||||
|
operation CAPI_REGISTER) to an appropriate hardware driver by calling its
|
||||||
|
register_appl() callback function. A unique Application ID (ApplID, u16) is
|
||||||
|
allocated by Kernel CAPI and passed to register_appl() along with the
|
||||||
|
parameter structure provided by the application. This is analogous to the
|
||||||
|
open() operation on regular files or character devices.
|
||||||
|
|
||||||
|
After a successful return from register_appl(), CAPI messages from the
|
||||||
|
application may be passed to the driver for the device via calls to the
|
||||||
|
send_message() callback function. The CAPI message to send is stored in the
|
||||||
|
data portion of an skb. Conversely, the driver may call Kernel CAPI's
|
||||||
|
capi_ctr_handle_message() function to pass a received CAPI message to Kernel
|
||||||
|
CAPI for forwarding to an application, specifying its ApplID.
|
||||||
|
|
||||||
|
Deregistration requests (CAPI operation CAPI_RELEASE) from applications are
|
||||||
|
forwarded as calls to the release_appl() callback function, passing the same
|
||||||
|
ApplID as with register_appl(). After return from release_appl(), no CAPI
|
||||||
|
messages for that application may be passed to or from the device anymore.
|
||||||
|
|
||||||
|
|
||||||
|
4. Data Structures
|
||||||
|
|
||||||
|
4.1 struct capi_driver
|
||||||
|
|
||||||
|
This structure describes a Kernel CAPI driver itself. It is used in the
|
||||||
|
register_capi_driver() and unregister_capi_driver() functions, and contains
|
||||||
|
the following non-private fields, all to be set by the driver before calling
|
||||||
|
register_capi_driver():
|
||||||
|
|
||||||
|
char name[32]
|
||||||
|
the name of the driver, as a zero-terminated ASCII string
|
||||||
|
char revision[32]
|
||||||
|
the revision number of the driver, as a zero-terminated ASCII string
|
||||||
|
int (*add_card)(struct capi_driver *driver, capicardparams *data)
|
||||||
|
a callback function pointer (may be NULL)
|
||||||
|
|
||||||
|
|
||||||
|
4.2 struct capi_ctr
|
||||||
|
|
||||||
|
This structure describes an ISDN device (controller) handled by a Kernel CAPI
|
||||||
|
driver. After registration via the attach_capi_ctr() function it is passed to
|
||||||
|
all controller specific lower layer interface and callback functions to
|
||||||
|
identify the controller to operate on.
|
||||||
|
|
||||||
|
It contains the following non-private fields:
|
||||||
|
|
||||||
|
- to be set by the driver before calling attach_capi_ctr():
|
||||||
|
|
||||||
|
struct module *owner
|
||||||
|
pointer to the driver module owning the device
|
||||||
|
|
||||||
|
void *driverdata
|
||||||
|
an opaque pointer to driver specific data, not touched by Kernel CAPI
|
||||||
|
|
||||||
|
char name[32]
|
||||||
|
the name of the controller, as a zero-terminated ASCII string
|
||||||
|
|
||||||
|
char *driver_name
|
||||||
|
the name of the driver, as a zero-terminated ASCII string
|
||||||
|
|
||||||
|
int (*load_firmware)(struct capi_ctr *ctrlr, capiloaddata *ldata)
|
||||||
|
(optional) pointer to a callback function for sending firmware and
|
||||||
|
configuration data to the device
|
||||||
|
|
||||||
|
void (*reset_ctr)(struct capi_ctr *ctrlr)
|
||||||
|
pointer to a callback function for performing a reset on the device,
|
||||||
|
releasing all registered applications
|
||||||
|
|
||||||
|
void (*register_appl)(struct capi_ctr *ctrlr, u16 applid,
|
||||||
|
capi_register_params *rparam)
|
||||||
|
void (*release_appl)(struct capi_ctr *ctrlr, u16 applid)
|
||||||
|
pointers to callback functions for registration and deregistration of
|
||||||
|
applications with the device
|
||||||
|
|
||||||
|
u16 (*send_message)(struct capi_ctr *ctrlr, struct sk_buff *skb)
|
||||||
|
pointer to a callback function for sending a CAPI message to the
|
||||||
|
device
|
||||||
|
|
||||||
|
char *(*procinfo)(struct capi_ctr *ctrlr)
|
||||||
|
pointer to a callback function returning the entry for the device in
|
||||||
|
the CAPI controller info table, /proc/capi/controller
|
||||||
|
|
||||||
|
read_proc_t *ctr_read_proc
|
||||||
|
pointer to the read_proc callback function for the device's proc file
|
||||||
|
system entry, /proc/capi/controllers/<n>; will be called with a
|
||||||
|
pointer to the device's capi_ctr structure as the last (data) argument
|
||||||
|
|
||||||
|
- to be filled in before calling capi_ctr_ready():
|
||||||
|
|
||||||
|
u8 manu[CAPI_MANUFACTURER_LEN]
|
||||||
|
value to return for CAPI_GET_MANUFACTURER
|
||||||
|
|
||||||
|
capi_version version
|
||||||
|
value to return for CAPI_GET_VERSION
|
||||||
|
|
||||||
|
capi_profile profile
|
||||||
|
value to return for CAPI_GET_PROFILE
|
||||||
|
|
||||||
|
u8 serial[CAPI_SERIAL_LEN]
|
||||||
|
value to return for CAPI_GET_SERIAL
|
||||||
|
|
||||||
|
|
||||||
|
5. Lower Layer Interface Functions
|
||||||
|
|
||||||
|
(declared in <linux/isdn/capilli.h>)
|
||||||
|
|
||||||
|
void register_capi_driver(struct capi_driver *drvr)
|
||||||
|
void unregister_capi_driver(struct capi_driver *drvr)
|
||||||
|
register/unregister a driver with Kernel CAPI
|
||||||
|
|
||||||
|
int attach_capi_ctr(struct capi_ctr *ctrlr)
|
||||||
|
int detach_capi_ctr(struct capi_ctr *ctrlr)
|
||||||
|
register/unregister a device (controller) with Kernel CAPI
|
||||||
|
|
||||||
|
void capi_ctr_ready(struct capi_ctr *ctrlr)
|
||||||
|
void capi_ctr_reseted(struct capi_ctr *ctrlr)
|
||||||
|
signal controller ready/not ready
|
||||||
|
|
||||||
|
void capi_ctr_suspend_output(struct capi_ctr *ctrlr)
|
||||||
|
void capi_ctr_resume_output(struct capi_ctr *ctrlr)
|
||||||
|
signal suspend/resume
|
||||||
|
|
||||||
|
void capi_ctr_handle_message(struct capi_ctr * ctrlr, u16 applid,
|
||||||
|
struct sk_buff *skb)
|
||||||
|
pass a received CAPI message to Kernel CAPI
|
||||||
|
for forwarding to the specified application
|
||||||
|
|
||||||
|
|
||||||
|
6. Helper Functions and Macros
|
||||||
|
|
||||||
|
Library functions (from <linux/isdn/capilli.h>):
|
||||||
|
|
||||||
|
void capilib_new_ncci(struct list_head *head, u16 applid,
|
||||||
|
u32 ncci, u32 winsize)
|
||||||
|
void capilib_free_ncci(struct list_head *head, u16 applid, u32 ncci)
|
||||||
|
void capilib_release_appl(struct list_head *head, u16 applid)
|
||||||
|
void capilib_release(struct list_head *head)
|
||||||
|
void capilib_data_b3_conf(struct list_head *head, u16 applid,
|
||||||
|
u32 ncci, u16 msgid)
|
||||||
|
u16 capilib_data_b3_req(struct list_head *head, u16 applid,
|
||||||
|
u32 ncci, u16 msgid)
|
||||||
|
|
||||||
|
|
||||||
|
Macros to extract/set element values from/in a CAPI message header
|
||||||
|
(from <linux/isdn/capiutil.h>):
|
||||||
|
|
||||||
|
Get Macro Set Macro Element (Type)
|
||||||
|
|
||||||
|
CAPIMSG_LEN(m) CAPIMSG_SETLEN(m, len) Total Length (u16)
|
||||||
|
CAPIMSG_APPID(m) CAPIMSG_SETAPPID(m, applid) ApplID (u16)
|
||||||
|
CAPIMSG_COMMAND(m) CAPIMSG_SETCOMMAND(m,cmd) Command (u8)
|
||||||
|
CAPIMSG_SUBCOMMAND(m) CAPIMSG_SETSUBCOMMAND(m, cmd) Subcommand (u8)
|
||||||
|
CAPIMSG_CMD(m) - Command*256
|
||||||
|
+ Subcommand (u16)
|
||||||
|
CAPIMSG_MSGID(m) CAPIMSG_SETMSGID(m, msgid) Message Number (u16)
|
||||||
|
|
||||||
|
CAPIMSG_CONTROL(m) CAPIMSG_SETCONTROL(m, contr) Controller/PLCI/NCCI
|
||||||
|
(u32)
|
||||||
|
CAPIMSG_DATALEN(m) CAPIMSG_SETDATALEN(m, len) Data Length (u16)
|
||||||
|
|
|
@ -270,6 +270,15 @@ static void recv_handler(struct work_struct *work)
|
||||||
mutex_unlock(&ap->recv_mtx);
|
mutex_unlock(&ap->recv_mtx);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi_ctr_handle_message() - handle incoming CAPI message
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
* @appl: application ID.
|
||||||
|
* @skb: message.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to pass a CAPI message to the application.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
|
void capi_ctr_handle_message(struct capi_ctr * card, u16 appl, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct capi20_appl *ap;
|
struct capi20_appl *ap;
|
||||||
|
@ -348,6 +357,13 @@ error:
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi_ctr_handle_message);
|
EXPORT_SYMBOL(capi_ctr_handle_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi_ctr_ready() - signal CAPI controller ready
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to signal that the controller is up and running.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi_ctr_ready(struct capi_ctr * card)
|
void capi_ctr_ready(struct capi_ctr * card)
|
||||||
{
|
{
|
||||||
card->cardstate = CARD_RUNNING;
|
card->cardstate = CARD_RUNNING;
|
||||||
|
@ -360,6 +376,14 @@ void capi_ctr_ready(struct capi_ctr * card)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi_ctr_ready);
|
EXPORT_SYMBOL(capi_ctr_ready);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi_ctr_reseted() - signal CAPI controller reset
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to signal that the controller is down and
|
||||||
|
* unavailable for use.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi_ctr_reseted(struct capi_ctr * card)
|
void capi_ctr_reseted(struct capi_ctr * card)
|
||||||
{
|
{
|
||||||
u16 appl;
|
u16 appl;
|
||||||
|
@ -391,6 +415,13 @@ void capi_ctr_reseted(struct capi_ctr * card)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi_ctr_reseted);
|
EXPORT_SYMBOL(capi_ctr_reseted);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi_ctr_suspend_output() - suspend controller
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to stop data flow.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi_ctr_suspend_output(struct capi_ctr *card)
|
void capi_ctr_suspend_output(struct capi_ctr *card)
|
||||||
{
|
{
|
||||||
if (!card->blocked) {
|
if (!card->blocked) {
|
||||||
|
@ -401,6 +432,13 @@ void capi_ctr_suspend_output(struct capi_ctr *card)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi_ctr_suspend_output);
|
EXPORT_SYMBOL(capi_ctr_suspend_output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi_ctr_resume_output() - resume controller
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to resume data flow.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi_ctr_resume_output(struct capi_ctr *card)
|
void capi_ctr_resume_output(struct capi_ctr *card)
|
||||||
{
|
{
|
||||||
if (card->blocked) {
|
if (card->blocked) {
|
||||||
|
@ -413,6 +451,14 @@ EXPORT_SYMBOL(capi_ctr_resume_output);
|
||||||
|
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* attach_capi_ctr() - register CAPI controller
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to register a controller with the CAPI subsystem.
|
||||||
|
* Return value: 0 on success, error code < 0 on error
|
||||||
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
attach_capi_ctr(struct capi_ctr *card)
|
attach_capi_ctr(struct capi_ctr *card)
|
||||||
{
|
{
|
||||||
|
@ -459,6 +505,15 @@ attach_capi_ctr(struct capi_ctr *card)
|
||||||
|
|
||||||
EXPORT_SYMBOL(attach_capi_ctr);
|
EXPORT_SYMBOL(attach_capi_ctr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* detach_capi_ctr() - unregister CAPI controller
|
||||||
|
* @card: controller descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to remove the registration of a controller
|
||||||
|
* with the CAPI subsystem.
|
||||||
|
* Return value: 0 on success, error code < 0 on error
|
||||||
|
*/
|
||||||
|
|
||||||
int detach_capi_ctr(struct capi_ctr *card)
|
int detach_capi_ctr(struct capi_ctr *card)
|
||||||
{
|
{
|
||||||
if (card->cardstate != CARD_DETECTED)
|
if (card->cardstate != CARD_DETECTED)
|
||||||
|
@ -479,6 +534,13 @@ int detach_capi_ctr(struct capi_ctr *card)
|
||||||
|
|
||||||
EXPORT_SYMBOL(detach_capi_ctr);
|
EXPORT_SYMBOL(detach_capi_ctr);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* register_capi_driver() - register CAPI driver
|
||||||
|
* @driver: driver descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to register itself with the CAPI subsystem.
|
||||||
|
*/
|
||||||
|
|
||||||
void register_capi_driver(struct capi_driver *driver)
|
void register_capi_driver(struct capi_driver *driver)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -490,6 +552,13 @@ void register_capi_driver(struct capi_driver *driver)
|
||||||
|
|
||||||
EXPORT_SYMBOL(register_capi_driver);
|
EXPORT_SYMBOL(register_capi_driver);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* unregister_capi_driver() - unregister CAPI driver
|
||||||
|
* @driver: driver descriptor structure.
|
||||||
|
*
|
||||||
|
* Called by hardware driver to unregister itself from the CAPI subsystem.
|
||||||
|
*/
|
||||||
|
|
||||||
void unregister_capi_driver(struct capi_driver *driver)
|
void unregister_capi_driver(struct capi_driver *driver)
|
||||||
{
|
{
|
||||||
unsigned long flags;
|
unsigned long flags;
|
||||||
|
@ -505,6 +574,13 @@ EXPORT_SYMBOL(unregister_capi_driver);
|
||||||
/* -------- CAPI2.0 Interface ---------------------------------- */
|
/* -------- CAPI2.0 Interface ---------------------------------- */
|
||||||
/* ------------------------------------------------------------- */
|
/* ------------------------------------------------------------- */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_isinstalled() - CAPI 2.0 operation CAPI_INSTALLED
|
||||||
|
*
|
||||||
|
* Return value: CAPI result code (CAPI_NOERROR if at least one ISDN controller
|
||||||
|
* is ready for use, CAPI_REGNOTINSTALLED otherwise)
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_isinstalled(void)
|
u16 capi20_isinstalled(void)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -517,6 +593,18 @@ u16 capi20_isinstalled(void)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_isinstalled);
|
EXPORT_SYMBOL(capi20_isinstalled);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_register() - CAPI 2.0 operation CAPI_REGISTER
|
||||||
|
* @ap: CAPI application descriptor structure.
|
||||||
|
*
|
||||||
|
* Register an application's presence with CAPI.
|
||||||
|
* A unique application ID is assigned and stored in @ap->applid.
|
||||||
|
* After this function returns successfully, the message receive
|
||||||
|
* callback function @ap->recv_message() may be called at any time
|
||||||
|
* until capi20_release() has been called for the same @ap.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_register(struct capi20_appl *ap)
|
u16 capi20_register(struct capi20_appl *ap)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -571,6 +659,16 @@ u16 capi20_register(struct capi20_appl *ap)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_register);
|
EXPORT_SYMBOL(capi20_register);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_release() - CAPI 2.0 operation CAPI_RELEASE
|
||||||
|
* @ap: CAPI application descriptor structure.
|
||||||
|
*
|
||||||
|
* Terminate an application's registration with CAPI.
|
||||||
|
* After this function returns successfully, the message receive
|
||||||
|
* callback function @ap->recv_message() will no longer be called.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_release(struct capi20_appl *ap)
|
u16 capi20_release(struct capi20_appl *ap)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -603,6 +701,15 @@ u16 capi20_release(struct capi20_appl *ap)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_release);
|
EXPORT_SYMBOL(capi20_release);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_put_message() - CAPI 2.0 operation CAPI_PUT_MESSAGE
|
||||||
|
* @ap: CAPI application descriptor structure.
|
||||||
|
* @skb: CAPI message.
|
||||||
|
*
|
||||||
|
* Transfer a single message to CAPI.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
|
u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -668,6 +775,16 @@ u16 capi20_put_message(struct capi20_appl *ap, struct sk_buff *skb)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_put_message);
|
EXPORT_SYMBOL(capi20_put_message);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_get_manufacturer() - CAPI 2.0 operation CAPI_GET_MANUFACTURER
|
||||||
|
* @contr: controller number.
|
||||||
|
* @buf: result buffer (64 bytes).
|
||||||
|
*
|
||||||
|
* Retrieve information about the manufacturer of the specified ISDN controller
|
||||||
|
* or (for @contr == 0) the driver itself.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
|
u16 capi20_get_manufacturer(u32 contr, u8 *buf)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -685,6 +802,16 @@ u16 capi20_get_manufacturer(u32 contr, u8 *buf)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_get_manufacturer);
|
EXPORT_SYMBOL(capi20_get_manufacturer);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_get_version() - CAPI 2.0 operation CAPI_GET_VERSION
|
||||||
|
* @contr: controller number.
|
||||||
|
* @verp: result structure.
|
||||||
|
*
|
||||||
|
* Retrieve version information for the specified ISDN controller
|
||||||
|
* or (for @contr == 0) the driver itself.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_get_version(u32 contr, struct capi_version *verp)
|
u16 capi20_get_version(u32 contr, struct capi_version *verp)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -703,6 +830,16 @@ u16 capi20_get_version(u32 contr, struct capi_version *verp)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_get_version);
|
EXPORT_SYMBOL(capi20_get_version);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_get_serial() - CAPI 2.0 operation CAPI_GET_SERIAL_NUMBER
|
||||||
|
* @contr: controller number.
|
||||||
|
* @serial: result buffer (8 bytes).
|
||||||
|
*
|
||||||
|
* Retrieve the serial number of the specified ISDN controller
|
||||||
|
* or (for @contr == 0) the driver itself.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_get_serial(u32 contr, u8 *serial)
|
u16 capi20_get_serial(u32 contr, u8 *serial)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -721,6 +858,16 @@ u16 capi20_get_serial(u32 contr, u8 *serial)
|
||||||
|
|
||||||
EXPORT_SYMBOL(capi20_get_serial);
|
EXPORT_SYMBOL(capi20_get_serial);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_get_profile() - CAPI 2.0 operation CAPI_GET_PROFILE
|
||||||
|
* @contr: controller number.
|
||||||
|
* @profp: result structure.
|
||||||
|
*
|
||||||
|
* Retrieve capability information for the specified ISDN controller
|
||||||
|
* or (for @contr == 0) the number of installed controllers.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
|
u16 capi20_get_profile(u32 contr, struct capi_profile *profp)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -903,6 +1050,15 @@ static int old_capi_manufacturer(unsigned int cmd, void __user *data)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_manufacturer() - CAPI 2.0 operation CAPI_MANUFACTURER
|
||||||
|
* @cmd: command.
|
||||||
|
* @data: parameter.
|
||||||
|
*
|
||||||
|
* Perform manufacturer specific command.
|
||||||
|
* Return value: CAPI result code
|
||||||
|
*/
|
||||||
|
|
||||||
int capi20_manufacturer(unsigned int cmd, void __user *data)
|
int capi20_manufacturer(unsigned int cmd, void __user *data)
|
||||||
{
|
{
|
||||||
struct capi_ctr *card;
|
struct capi_ctr *card;
|
||||||
|
@ -981,6 +1137,21 @@ int capi20_manufacturer(unsigned int cmd, void __user *data)
|
||||||
EXPORT_SYMBOL(capi20_manufacturer);
|
EXPORT_SYMBOL(capi20_manufacturer);
|
||||||
|
|
||||||
/* temporary hack */
|
/* temporary hack */
|
||||||
|
|
||||||
|
/**
|
||||||
|
* capi20_set_callback() - set CAPI application notification callback function
|
||||||
|
* @ap: CAPI application descriptor structure.
|
||||||
|
* @callback: callback function (NULL to remove).
|
||||||
|
*
|
||||||
|
* If not NULL, the callback function will be called to notify the
|
||||||
|
* application of the addition or removal of a controller.
|
||||||
|
* The first argument (cmd) will tell whether the controller was added
|
||||||
|
* (KCI_CONTRUP) or removed (KCI_CONTRDOWN).
|
||||||
|
* The second argument (contr) will be the controller number.
|
||||||
|
* For cmd==KCI_CONTRUP the third argument (data) will be a pointer to the
|
||||||
|
* new controller's capability profile structure.
|
||||||
|
*/
|
||||||
|
|
||||||
void capi20_set_callback(struct capi20_appl *ap,
|
void capi20_set_callback(struct capi20_appl *ap,
|
||||||
void (*callback) (unsigned int cmd, __u32 contr, void *data))
|
void (*callback) (unsigned int cmd, __u32 contr, void *data))
|
||||||
{
|
{
|
||||||
|
|
|
@ -2728,7 +2728,7 @@ static void __devexit e100_remove(struct pci_dev *pdev)
|
||||||
#define E100_82552_SMARTSPEED 0x14 /* SmartSpeed Ctrl register */
|
#define E100_82552_SMARTSPEED 0x14 /* SmartSpeed Ctrl register */
|
||||||
#define E100_82552_REV_ANEG 0x0200 /* Reverse auto-negotiation */
|
#define E100_82552_REV_ANEG 0x0200 /* Reverse auto-negotiation */
|
||||||
#define E100_82552_ANEG_NOW 0x0400 /* Auto-negotiate now */
|
#define E100_82552_ANEG_NOW 0x0400 /* Auto-negotiate now */
|
||||||
static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
|
static void __e100_shutdown(struct pci_dev *pdev, bool *enable_wake)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||||
struct nic *nic = netdev_priv(netdev);
|
struct nic *nic = netdev_priv(netdev);
|
||||||
|
@ -2749,19 +2749,32 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||||
E100_82552_SMARTSPEED, smartspeed |
|
E100_82552_SMARTSPEED, smartspeed |
|
||||||
E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
|
E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
|
||||||
}
|
}
|
||||||
if (pci_enable_wake(pdev, PCI_D3cold, true))
|
*enable_wake = true;
|
||||||
pci_enable_wake(pdev, PCI_D3hot, true);
|
|
||||||
} else {
|
} else {
|
||||||
pci_enable_wake(pdev, PCI_D3hot, false);
|
*enable_wake = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
pci_disable_device(pdev);
|
pci_disable_device(pdev);
|
||||||
pci_set_power_state(pdev, PCI_D3hot);
|
}
|
||||||
|
|
||||||
return 0;
|
static int __e100_power_off(struct pci_dev *pdev, bool wake)
|
||||||
|
{
|
||||||
|
if (wake) {
|
||||||
|
return pci_prepare_to_sleep(pdev);
|
||||||
|
} else {
|
||||||
|
pci_wake_from_d3(pdev, false);
|
||||||
|
return pci_set_power_state(pdev, PCI_D3hot);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PM
|
#ifdef CONFIG_PM
|
||||||
|
static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
|
||||||
|
{
|
||||||
|
bool wake;
|
||||||
|
__e100_shutdown(pdev, &wake);
|
||||||
|
return __e100_power_off(pdev, wake);
|
||||||
|
}
|
||||||
|
|
||||||
static int e100_resume(struct pci_dev *pdev)
|
static int e100_resume(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
struct net_device *netdev = pci_get_drvdata(pdev);
|
struct net_device *netdev = pci_get_drvdata(pdev);
|
||||||
|
@ -2792,7 +2805,10 @@ static int e100_resume(struct pci_dev *pdev)
|
||||||
|
|
||||||
static void e100_shutdown(struct pci_dev *pdev)
|
static void e100_shutdown(struct pci_dev *pdev)
|
||||||
{
|
{
|
||||||
e100_suspend(pdev, PMSG_SUSPEND);
|
bool wake;
|
||||||
|
__e100_shutdown(pdev, &wake);
|
||||||
|
if (system_state == SYSTEM_POWER_OFF)
|
||||||
|
__e100_power_off(pdev, wake);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ------------------ PCI Error Recovery infrastructure -------------- */
|
/* ------------------ PCI Error Recovery infrastructure -------------- */
|
||||||
|
|
|
@ -1880,6 +1880,7 @@ static void nv_init_tx(struct net_device *dev)
|
||||||
np->tx_pkts_in_progress = 0;
|
np->tx_pkts_in_progress = 0;
|
||||||
np->tx_change_owner = NULL;
|
np->tx_change_owner = NULL;
|
||||||
np->tx_end_flip = NULL;
|
np->tx_end_flip = NULL;
|
||||||
|
np->tx_stop = 0;
|
||||||
|
|
||||||
for (i = 0; i < np->tx_ring_size; i++) {
|
for (i = 0; i < np->tx_ring_size; i++) {
|
||||||
if (!nv_optimized(np)) {
|
if (!nv_optimized(np)) {
|
||||||
|
@ -2530,6 +2531,8 @@ static void nv_tx_timeout(struct net_device *dev)
|
||||||
struct fe_priv *np = netdev_priv(dev);
|
struct fe_priv *np = netdev_priv(dev);
|
||||||
u8 __iomem *base = get_hwbase(dev);
|
u8 __iomem *base = get_hwbase(dev);
|
||||||
u32 status;
|
u32 status;
|
||||||
|
union ring_type put_tx;
|
||||||
|
int saved_tx_limit;
|
||||||
|
|
||||||
if (np->msi_flags & NV_MSI_X_ENABLED)
|
if (np->msi_flags & NV_MSI_X_ENABLED)
|
||||||
status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
|
status = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
|
||||||
|
@ -2589,24 +2592,32 @@ static void nv_tx_timeout(struct net_device *dev)
|
||||||
/* 1) stop tx engine */
|
/* 1) stop tx engine */
|
||||||
nv_stop_tx(dev);
|
nv_stop_tx(dev);
|
||||||
|
|
||||||
/* 2) check that the packets were not sent already: */
|
/* 2) complete any outstanding tx and do not give HW any limited tx pkts */
|
||||||
|
saved_tx_limit = np->tx_limit;
|
||||||
|
np->tx_limit = 0; /* prevent giving HW any limited pkts */
|
||||||
|
np->tx_stop = 0; /* prevent waking tx queue */
|
||||||
if (!nv_optimized(np))
|
if (!nv_optimized(np))
|
||||||
nv_tx_done(dev, np->tx_ring_size);
|
nv_tx_done(dev, np->tx_ring_size);
|
||||||
else
|
else
|
||||||
nv_tx_done_optimized(dev, np->tx_ring_size);
|
nv_tx_done_optimized(dev, np->tx_ring_size);
|
||||||
|
|
||||||
/* 3) if there are dead entries: clear everything */
|
/* save current HW postion */
|
||||||
if (np->get_tx_ctx != np->put_tx_ctx) {
|
if (np->tx_change_owner)
|
||||||
printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name);
|
put_tx.ex = np->tx_change_owner->first_tx_desc;
|
||||||
|
else
|
||||||
|
put_tx = np->put_tx;
|
||||||
|
|
||||||
|
/* 3) clear all tx state */
|
||||||
nv_drain_tx(dev);
|
nv_drain_tx(dev);
|
||||||
nv_init_tx(dev);
|
nv_init_tx(dev);
|
||||||
setup_hw_rings(dev, NV_SETUP_TX_RING);
|
|
||||||
}
|
|
||||||
|
|
||||||
netif_wake_queue(dev);
|
/* 4) restore state to current HW position */
|
||||||
|
np->get_tx = np->put_tx = put_tx;
|
||||||
|
np->tx_limit = saved_tx_limit;
|
||||||
|
|
||||||
/* 4) restart tx engine */
|
/* 5) restart tx engine */
|
||||||
nv_start_tx(dev);
|
nv_start_tx(dev);
|
||||||
|
netif_wake_queue(dev);
|
||||||
spin_unlock_irq(&np->lock);
|
spin_unlock_irq(&np->lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -50,7 +50,6 @@ static u16 ixgbe_calc_eeprom_checksum(struct ixgbe_hw *hw);
|
||||||
static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index);
|
static void ixgbe_enable_rar(struct ixgbe_hw *hw, u32 index);
|
||||||
static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
|
static void ixgbe_disable_rar(struct ixgbe_hw *hw, u32 index);
|
||||||
static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
|
static s32 ixgbe_mta_vector(struct ixgbe_hw *hw, u8 *mc_addr);
|
||||||
static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr);
|
|
||||||
static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
|
static void ixgbe_add_uc_addr(struct ixgbe_hw *hw, u8 *addr, u32 vmdq);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -1377,8 +1376,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
|
||||||
* Clear accounting of old secondary address list,
|
* Clear accounting of old secondary address list,
|
||||||
* don't count RAR[0]
|
* don't count RAR[0]
|
||||||
*/
|
*/
|
||||||
uc_addr_in_use = hw->addr_ctrl.rar_used_count -
|
uc_addr_in_use = hw->addr_ctrl.rar_used_count - 1;
|
||||||
hw->addr_ctrl.mc_addr_in_rar_count - 1;
|
|
||||||
hw->addr_ctrl.rar_used_count -= uc_addr_in_use;
|
hw->addr_ctrl.rar_used_count -= uc_addr_in_use;
|
||||||
hw->addr_ctrl.overflow_promisc = 0;
|
hw->addr_ctrl.overflow_promisc = 0;
|
||||||
|
|
||||||
|
@ -1492,40 +1490,6 @@ static void ixgbe_set_mta(struct ixgbe_hw *hw, u8 *mc_addr)
|
||||||
IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
|
IXGBE_WRITE_REG(hw, IXGBE_MTA(vector_reg), mta_reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* ixgbe_add_mc_addr - Adds a multicast address.
|
|
||||||
* @hw: pointer to hardware structure
|
|
||||||
* @mc_addr: new multicast address
|
|
||||||
*
|
|
||||||
* Adds it to unused receive address register or to the multicast table.
|
|
||||||
**/
|
|
||||||
static void ixgbe_add_mc_addr(struct ixgbe_hw *hw, u8 *mc_addr)
|
|
||||||
{
|
|
||||||
u32 rar_entries = hw->mac.num_rar_entries;
|
|
||||||
u32 rar;
|
|
||||||
|
|
||||||
hw_dbg(hw, " MC Addr =%.2X %.2X %.2X %.2X %.2X %.2X\n",
|
|
||||||
mc_addr[0], mc_addr[1], mc_addr[2],
|
|
||||||
mc_addr[3], mc_addr[4], mc_addr[5]);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Place this multicast address in the RAR if there is room,
|
|
||||||
* else put it in the MTA
|
|
||||||
*/
|
|
||||||
if (hw->addr_ctrl.rar_used_count < rar_entries) {
|
|
||||||
/* use RAR from the end up for multicast */
|
|
||||||
rar = rar_entries - hw->addr_ctrl.mc_addr_in_rar_count - 1;
|
|
||||||
hw->mac.ops.set_rar(hw, rar, mc_addr, 0, IXGBE_RAH_AV);
|
|
||||||
hw_dbg(hw, "Added a multicast address to RAR[%d]\n", rar);
|
|
||||||
hw->addr_ctrl.rar_used_count++;
|
|
||||||
hw->addr_ctrl.mc_addr_in_rar_count++;
|
|
||||||
} else {
|
|
||||||
ixgbe_set_mta(hw, mc_addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
hw_dbg(hw, "ixgbe_add_mc_addr Complete\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses
|
* ixgbe_update_mc_addr_list_generic - Updates MAC list of multicast addresses
|
||||||
* @hw: pointer to hardware structure
|
* @hw: pointer to hardware structure
|
||||||
|
@ -1542,7 +1506,6 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
|
||||||
u32 mc_addr_count, ixgbe_mc_addr_itr next)
|
u32 mc_addr_count, ixgbe_mc_addr_itr next)
|
||||||
{
|
{
|
||||||
u32 i;
|
u32 i;
|
||||||
u32 rar_entries = hw->mac.num_rar_entries;
|
|
||||||
u32 vmdq;
|
u32 vmdq;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1550,18 +1513,8 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
|
||||||
* use.
|
* use.
|
||||||
*/
|
*/
|
||||||
hw->addr_ctrl.num_mc_addrs = mc_addr_count;
|
hw->addr_ctrl.num_mc_addrs = mc_addr_count;
|
||||||
hw->addr_ctrl.rar_used_count -= hw->addr_ctrl.mc_addr_in_rar_count;
|
|
||||||
hw->addr_ctrl.mc_addr_in_rar_count = 0;
|
|
||||||
hw->addr_ctrl.mta_in_use = 0;
|
hw->addr_ctrl.mta_in_use = 0;
|
||||||
|
|
||||||
/* Zero out the other receive addresses. */
|
|
||||||
hw_dbg(hw, "Clearing RAR[%d-%d]\n", hw->addr_ctrl.rar_used_count,
|
|
||||||
rar_entries - 1);
|
|
||||||
for (i = hw->addr_ctrl.rar_used_count; i < rar_entries; i++) {
|
|
||||||
IXGBE_WRITE_REG(hw, IXGBE_RAL(i), 0);
|
|
||||||
IXGBE_WRITE_REG(hw, IXGBE_RAH(i), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Clear the MTA */
|
/* Clear the MTA */
|
||||||
hw_dbg(hw, " Clearing MTA\n");
|
hw_dbg(hw, " Clearing MTA\n");
|
||||||
for (i = 0; i < hw->mac.mcft_size; i++)
|
for (i = 0; i < hw->mac.mcft_size; i++)
|
||||||
|
@ -1570,7 +1523,7 @@ s32 ixgbe_update_mc_addr_list_generic(struct ixgbe_hw *hw, u8 *mc_addr_list,
|
||||||
/* Add the new addresses */
|
/* Add the new addresses */
|
||||||
for (i = 0; i < mc_addr_count; i++) {
|
for (i = 0; i < mc_addr_count; i++) {
|
||||||
hw_dbg(hw, " Adding the multicast addresses:\n");
|
hw_dbg(hw, " Adding the multicast addresses:\n");
|
||||||
ixgbe_add_mc_addr(hw, next(hw, &mc_addr_list, &vmdq));
|
ixgbe_set_mta(hw, next(hw, &mc_addr_list, &vmdq));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Enable mta */
|
/* Enable mta */
|
||||||
|
|
|
@ -3646,6 +3646,8 @@ static int ixgbe_resume(struct pci_dev *pdev)
|
||||||
|
|
||||||
ixgbe_reset(adapter);
|
ixgbe_reset(adapter);
|
||||||
|
|
||||||
|
IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
|
||||||
|
|
||||||
if (netif_running(netdev)) {
|
if (netif_running(netdev)) {
|
||||||
err = ixgbe_open(adapter->netdev);
|
err = ixgbe_open(adapter->netdev);
|
||||||
if (err)
|
if (err)
|
||||||
|
@ -4575,7 +4577,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
|
||||||
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
|
const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
|
||||||
static int cards_found;
|
static int cards_found;
|
||||||
int i, err, pci_using_dac;
|
int i, err, pci_using_dac;
|
||||||
u16 pm_value = 0;
|
|
||||||
u32 part_num, eec;
|
u32 part_num, eec;
|
||||||
|
|
||||||
err = pci_enable_device(pdev);
|
err = pci_enable_device(pdev);
|
||||||
|
@ -4763,11 +4764,8 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
|
||||||
|
|
||||||
switch (pdev->device) {
|
switch (pdev->device) {
|
||||||
case IXGBE_DEV_ID_82599_KX4:
|
case IXGBE_DEV_ID_82599_KX4:
|
||||||
#define IXGBE_PCIE_PMCSR 0x44
|
adapter->wol = (IXGBE_WUFC_MAG | IXGBE_WUFC_EX |
|
||||||
adapter->wol = IXGBE_WUFC_MAG;
|
IXGBE_WUFC_MC | IXGBE_WUFC_BC);
|
||||||
pci_read_config_word(pdev, IXGBE_PCIE_PMCSR, &pm_value);
|
|
||||||
pci_write_config_word(pdev, IXGBE_PCIE_PMCSR,
|
|
||||||
(pm_value | (1 << 8)));
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
adapter->wol = 0;
|
adapter->wol = 0;
|
||||||
|
|
|
@ -583,7 +583,7 @@ int mlx4_en_start_port(struct net_device *dev)
|
||||||
err = mlx4_en_activate_cq(priv, cq);
|
err = mlx4_en_activate_cq(priv, cq);
|
||||||
if (err) {
|
if (err) {
|
||||||
mlx4_err(mdev, "Failed activating Rx CQ\n");
|
mlx4_err(mdev, "Failed activating Rx CQ\n");
|
||||||
goto rx_err;
|
goto cq_err;
|
||||||
}
|
}
|
||||||
for (j = 0; j < cq->size; j++)
|
for (j = 0; j < cq->size; j++)
|
||||||
cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK;
|
cq->buf[j].owner_sr_opcode = MLX4_CQE_OWNER_MASK;
|
||||||
|
|
|
@ -610,6 +610,10 @@ static struct sk_buff *mlx4_en_rx_skb(struct mlx4_en_priv *priv,
|
||||||
used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, skb_frags,
|
used_frags = mlx4_en_complete_rx_desc(priv, rx_desc, skb_frags,
|
||||||
skb_shinfo(skb)->frags,
|
skb_shinfo(skb)->frags,
|
||||||
page_alloc, length);
|
page_alloc, length);
|
||||||
|
if (unlikely(!used_frags)) {
|
||||||
|
kfree_skb(skb);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
skb_shinfo(skb)->nr_frags = used_frags;
|
skb_shinfo(skb)->nr_frags = used_frags;
|
||||||
|
|
||||||
/* Copy headers into the skb linear buffer */
|
/* Copy headers into the skb linear buffer */
|
||||||
|
|
|
@ -210,14 +210,11 @@ rx_drop:
|
||||||
|
|
||||||
static struct net_device_stats *veth_get_stats(struct net_device *dev)
|
static struct net_device_stats *veth_get_stats(struct net_device *dev)
|
||||||
{
|
{
|
||||||
struct veth_priv *priv;
|
struct veth_priv *priv = netdev_priv(dev);
|
||||||
struct net_device_stats *dev_stats;
|
struct net_device_stats *dev_stats = &dev->stats;
|
||||||
int cpu;
|
unsigned int cpu;
|
||||||
struct veth_net_stats *stats;
|
struct veth_net_stats *stats;
|
||||||
|
|
||||||
priv = netdev_priv(dev);
|
|
||||||
dev_stats = &dev->stats;
|
|
||||||
|
|
||||||
dev_stats->rx_packets = 0;
|
dev_stats->rx_packets = 0;
|
||||||
dev_stats->tx_packets = 0;
|
dev_stats->tx_packets = 0;
|
||||||
dev_stats->rx_bytes = 0;
|
dev_stats->rx_bytes = 0;
|
||||||
|
@ -225,6 +222,7 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev)
|
||||||
dev_stats->tx_dropped = 0;
|
dev_stats->tx_dropped = 0;
|
||||||
dev_stats->rx_dropped = 0;
|
dev_stats->rx_dropped = 0;
|
||||||
|
|
||||||
|
if (priv->stats)
|
||||||
for_each_online_cpu(cpu) {
|
for_each_online_cpu(cpu) {
|
||||||
stats = per_cpu_ptr(priv->stats, cpu);
|
stats = per_cpu_ptr(priv->stats, cpu);
|
||||||
|
|
||||||
|
@ -261,6 +259,8 @@ static int veth_close(struct net_device *dev)
|
||||||
netif_carrier_off(dev);
|
netif_carrier_off(dev);
|
||||||
netif_carrier_off(priv->peer);
|
netif_carrier_off(priv->peer);
|
||||||
|
|
||||||
|
free_percpu(priv->stats);
|
||||||
|
priv->stats = NULL;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -291,15 +291,6 @@ static int veth_dev_init(struct net_device *dev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void veth_dev_free(struct net_device *dev)
|
|
||||||
{
|
|
||||||
struct veth_priv *priv;
|
|
||||||
|
|
||||||
priv = netdev_priv(dev);
|
|
||||||
free_percpu(priv->stats);
|
|
||||||
free_netdev(dev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static const struct net_device_ops veth_netdev_ops = {
|
static const struct net_device_ops veth_netdev_ops = {
|
||||||
.ndo_init = veth_dev_init,
|
.ndo_init = veth_dev_init,
|
||||||
.ndo_open = veth_open,
|
.ndo_open = veth_open,
|
||||||
|
@ -317,7 +308,7 @@ static void veth_setup(struct net_device *dev)
|
||||||
dev->netdev_ops = &veth_netdev_ops;
|
dev->netdev_ops = &veth_netdev_ops;
|
||||||
dev->ethtool_ops = &veth_ethtool_ops;
|
dev->ethtool_ops = &veth_ethtool_ops;
|
||||||
dev->features |= NETIF_F_LLTX;
|
dev->features |= NETIF_F_LLTX;
|
||||||
dev->destructor = veth_dev_free;
|
dev->destructor = free_netdev;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -104,7 +104,7 @@ struct wireless_dev;
|
||||||
# else
|
# else
|
||||||
# define LL_MAX_HEADER 96
|
# define LL_MAX_HEADER 96
|
||||||
# endif
|
# endif
|
||||||
#elif defined(CONFIG_TR)
|
#elif defined(CONFIG_TR) || defined(CONFIG_TR_MODULE)
|
||||||
# define LL_MAX_HEADER 48
|
# define LL_MAX_HEADER 48
|
||||||
#else
|
#else
|
||||||
# define LL_MAX_HEADER 32
|
# define LL_MAX_HEADER 32
|
||||||
|
@ -500,7 +500,7 @@ struct netdev_queue {
|
||||||
*
|
*
|
||||||
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
|
* int (*ndo_set_mac_address)(struct net_device *dev, void *addr);
|
||||||
* This function is called when the Media Access Control address
|
* This function is called when the Media Access Control address
|
||||||
* needs to be changed. If not this interface is not defined, the
|
* needs to be changed. If this interface is not defined, the
|
||||||
* mac address can not be changed.
|
* mac address can not be changed.
|
||||||
*
|
*
|
||||||
* int (*ndo_validate_addr)(struct net_device *dev);
|
* int (*ndo_validate_addr)(struct net_device *dev);
|
||||||
|
|
|
@ -100,6 +100,7 @@ enum ctattr_protoinfo_tcp {
|
||||||
enum ctattr_protoinfo_dccp {
|
enum ctattr_protoinfo_dccp {
|
||||||
CTA_PROTOINFO_DCCP_UNSPEC,
|
CTA_PROTOINFO_DCCP_UNSPEC,
|
||||||
CTA_PROTOINFO_DCCP_STATE,
|
CTA_PROTOINFO_DCCP_STATE,
|
||||||
|
CTA_PROTOINFO_DCCP_ROLE,
|
||||||
__CTA_PROTOINFO_DCCP_MAX,
|
__CTA_PROTOINFO_DCCP_MAX,
|
||||||
};
|
};
|
||||||
#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
|
#define CTA_PROTOINFO_DCCP_MAX (__CTA_PROTOINFO_DCCP_MAX - 1)
|
||||||
|
|
|
@ -354,9 +354,6 @@ struct xt_table
|
||||||
/* What hooks you will enter on */
|
/* What hooks you will enter on */
|
||||||
unsigned int valid_hooks;
|
unsigned int valid_hooks;
|
||||||
|
|
||||||
/* Lock for the curtain */
|
|
||||||
struct mutex lock;
|
|
||||||
|
|
||||||
/* Man behind the curtain... */
|
/* Man behind the curtain... */
|
||||||
struct xt_table_info *private;
|
struct xt_table_info *private;
|
||||||
|
|
||||||
|
@ -434,8 +431,74 @@ extern void xt_proto_fini(struct net *net, u_int8_t af);
|
||||||
|
|
||||||
extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
|
extern struct xt_table_info *xt_alloc_table_info(unsigned int size);
|
||||||
extern void xt_free_table_info(struct xt_table_info *info);
|
extern void xt_free_table_info(struct xt_table_info *info);
|
||||||
extern void xt_table_entry_swap_rcu(struct xt_table_info *old,
|
|
||||||
struct xt_table_info *new);
|
/*
|
||||||
|
* Per-CPU spinlock associated with per-cpu table entries, and
|
||||||
|
* with a counter for the "reading" side that allows a recursive
|
||||||
|
* reader to avoid taking the lock and deadlocking.
|
||||||
|
*
|
||||||
|
* "reading" is used by ip/arp/ip6 tables rule processing which runs per-cpu.
|
||||||
|
* It needs to ensure that the rules are not being changed while the packet
|
||||||
|
* is being processed. In some cases, the read lock will be acquired
|
||||||
|
* twice on the same CPU; this is okay because of the count.
|
||||||
|
*
|
||||||
|
* "writing" is used when reading counters.
|
||||||
|
* During replace any readers that are using the old tables have to complete
|
||||||
|
* before freeing the old table. This is handled by the write locking
|
||||||
|
* necessary for reading the counters.
|
||||||
|
*/
|
||||||
|
struct xt_info_lock {
|
||||||
|
spinlock_t lock;
|
||||||
|
unsigned char readers;
|
||||||
|
};
|
||||||
|
DECLARE_PER_CPU(struct xt_info_lock, xt_info_locks);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Note: we need to ensure that preemption is disabled before acquiring
|
||||||
|
* the per-cpu-variable, so we do it as a two step process rather than
|
||||||
|
* using "spin_lock_bh()".
|
||||||
|
*
|
||||||
|
* We _also_ need to disable bottom half processing before updating our
|
||||||
|
* nesting count, to make sure that the only kind of re-entrancy is this
|
||||||
|
* code being called by itself: since the count+lock is not an atomic
|
||||||
|
* operation, we can allow no races.
|
||||||
|
*
|
||||||
|
* _Only_ that special combination of being per-cpu and never getting
|
||||||
|
* re-entered asynchronously means that the count is safe.
|
||||||
|
*/
|
||||||
|
static inline void xt_info_rdlock_bh(void)
|
||||||
|
{
|
||||||
|
struct xt_info_lock *lock;
|
||||||
|
|
||||||
|
local_bh_disable();
|
||||||
|
lock = &__get_cpu_var(xt_info_locks);
|
||||||
|
if (!lock->readers++)
|
||||||
|
spin_lock(&lock->lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xt_info_rdunlock_bh(void)
|
||||||
|
{
|
||||||
|
struct xt_info_lock *lock = &__get_cpu_var(xt_info_locks);
|
||||||
|
|
||||||
|
if (!--lock->readers)
|
||||||
|
spin_unlock(&lock->lock);
|
||||||
|
local_bh_enable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The "writer" side needs to get exclusive access to the lock,
|
||||||
|
* regardless of readers. This must be called with bottom half
|
||||||
|
* processing (and thus also preemption) disabled.
|
||||||
|
*/
|
||||||
|
static inline void xt_info_wrlock(unsigned int cpu)
|
||||||
|
{
|
||||||
|
spin_lock(&per_cpu(xt_info_locks, cpu).lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void xt_info_wrunlock(unsigned int cpu)
|
||||||
|
{
|
||||||
|
spin_unlock(&per_cpu(xt_info_locks, cpu).lock);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This helper is performance critical and must be inlined
|
* This helper is performance critical and must be inlined
|
||||||
|
|
|
@ -440,13 +440,15 @@ void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait,
|
||||||
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
|
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
|
||||||
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
|
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
|
||||||
|
|
||||||
#define DEFINE_WAIT(name) \
|
#define DEFINE_WAIT_FUNC(name, function) \
|
||||||
wait_queue_t name = { \
|
wait_queue_t name = { \
|
||||||
.private = current, \
|
.private = current, \
|
||||||
.func = autoremove_wake_function, \
|
.func = function, \
|
||||||
.task_list = LIST_HEAD_INIT((name).task_list), \
|
.task_list = LIST_HEAD_INIT((name).task_list), \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define DEFINE_WAIT(name) DEFINE_WAIT_FUNC(name, autoremove_wake_function)
|
||||||
|
|
||||||
#define DEFINE_WAIT_BIT(name, word, bit) \
|
#define DEFINE_WAIT_BIT(name, word, bit) \
|
||||||
struct wait_bit_queue name = { \
|
struct wait_bit_queue name = { \
|
||||||
.key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \
|
.key = __WAIT_BIT_KEY_INITIALIZER(word, bit), \
|
||||||
|
|
|
@ -101,6 +101,7 @@ enum {
|
||||||
/* HCI timeouts */
|
/* HCI timeouts */
|
||||||
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
|
#define HCI_CONNECT_TIMEOUT (40000) /* 40 seconds */
|
||||||
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
|
#define HCI_DISCONN_TIMEOUT (2000) /* 2 seconds */
|
||||||
|
#define HCI_PAIRING_TIMEOUT (60000) /* 60 seconds */
|
||||||
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
|
#define HCI_IDLE_TIMEOUT (6000) /* 6 seconds */
|
||||||
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
|
#define HCI_INIT_TIMEOUT (10000) /* 10 seconds */
|
||||||
|
|
||||||
|
|
|
@ -171,6 +171,7 @@ struct hci_conn {
|
||||||
__u8 auth_type;
|
__u8 auth_type;
|
||||||
__u8 sec_level;
|
__u8 sec_level;
|
||||||
__u8 power_save;
|
__u8 power_save;
|
||||||
|
__u16 disc_timeout;
|
||||||
unsigned long pend;
|
unsigned long pend;
|
||||||
|
|
||||||
unsigned int sent;
|
unsigned int sent;
|
||||||
|
@ -180,7 +181,8 @@ struct hci_conn {
|
||||||
struct timer_list disc_timer;
|
struct timer_list disc_timer;
|
||||||
struct timer_list idle_timer;
|
struct timer_list idle_timer;
|
||||||
|
|
||||||
struct work_struct work;
|
struct work_struct work_add;
|
||||||
|
struct work_struct work_del;
|
||||||
|
|
||||||
struct device dev;
|
struct device dev;
|
||||||
|
|
||||||
|
@ -348,9 +350,9 @@ static inline void hci_conn_put(struct hci_conn *conn)
|
||||||
if (conn->type == ACL_LINK) {
|
if (conn->type == ACL_LINK) {
|
||||||
del_timer(&conn->idle_timer);
|
del_timer(&conn->idle_timer);
|
||||||
if (conn->state == BT_CONNECTED) {
|
if (conn->state == BT_CONNECTED) {
|
||||||
timeo = msecs_to_jiffies(HCI_DISCONN_TIMEOUT);
|
timeo = msecs_to_jiffies(conn->disc_timeout);
|
||||||
if (!conn->out)
|
if (!conn->out)
|
||||||
timeo *= 5;
|
timeo *= 2;
|
||||||
} else
|
} else
|
||||||
timeo = msecs_to_jiffies(10);
|
timeo = msecs_to_jiffies(10);
|
||||||
} else
|
} else
|
||||||
|
|
|
@ -492,6 +492,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dev_change_flags(vlandev, flgs & ~IFF_UP);
|
dev_change_flags(vlandev, flgs & ~IFF_UP);
|
||||||
|
vlan_transfer_operstate(dev, vlandev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -507,6 +508,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dev_change_flags(vlandev, flgs | IFF_UP);
|
dev_change_flags(vlandev, flgs | IFF_UP);
|
||||||
|
vlan_transfer_operstate(dev, vlandev);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -462,6 +462,7 @@ static int vlan_dev_open(struct net_device *dev)
|
||||||
if (vlan->flags & VLAN_FLAG_GVRP)
|
if (vlan->flags & VLAN_FLAG_GVRP)
|
||||||
vlan_gvrp_request_join(dev);
|
vlan_gvrp_request_join(dev);
|
||||||
|
|
||||||
|
netif_carrier_on(dev);
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
clear_allmulti:
|
clear_allmulti:
|
||||||
|
@ -471,6 +472,7 @@ del_unicast:
|
||||||
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
|
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
|
||||||
dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
|
dev_unicast_delete(real_dev, dev->dev_addr, ETH_ALEN);
|
||||||
out:
|
out:
|
||||||
|
netif_carrier_off(dev);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -492,6 +494,7 @@ static int vlan_dev_stop(struct net_device *dev)
|
||||||
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
|
if (compare_ether_addr(dev->dev_addr, real_dev->dev_addr))
|
||||||
dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
|
dev_unicast_delete(real_dev, dev->dev_addr, dev->addr_len);
|
||||||
|
|
||||||
|
netif_carrier_off(dev);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,6 +615,8 @@ static int vlan_dev_init(struct net_device *dev)
|
||||||
struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
|
struct net_device *real_dev = vlan_dev_info(dev)->real_dev;
|
||||||
int subclass = 0;
|
int subclass = 0;
|
||||||
|
|
||||||
|
netif_carrier_off(dev);
|
||||||
|
|
||||||
/* IFF_BROADCAST|IFF_MULTICAST; ??? */
|
/* IFF_BROADCAST|IFF_MULTICAST; ??? */
|
||||||
dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI);
|
dev->flags = real_dev->flags & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI);
|
||||||
dev->iflink = real_dev->ifindex;
|
dev->iflink = real_dev->ifindex;
|
||||||
|
|
|
@ -215,6 +215,7 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
|
||||||
conn->state = BT_OPEN;
|
conn->state = BT_OPEN;
|
||||||
|
|
||||||
conn->power_save = 1;
|
conn->power_save = 1;
|
||||||
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case ACL_LINK:
|
case ACL_LINK:
|
||||||
|
@ -424,12 +425,9 @@ int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
|
||||||
if (sec_level == BT_SECURITY_SDP)
|
if (sec_level == BT_SECURITY_SDP)
|
||||||
return 1;
|
return 1;
|
||||||
|
|
||||||
if (sec_level == BT_SECURITY_LOW) {
|
if (sec_level == BT_SECURITY_LOW &&
|
||||||
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
|
(!conn->ssp_mode || !conn->hdev->ssp_mode))
|
||||||
return hci_conn_auth(conn, sec_level, auth_type);
|
|
||||||
else
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
|
||||||
|
|
||||||
if (conn->link_mode & HCI_LM_ENCRYPT)
|
if (conn->link_mode & HCI_LM_ENCRYPT)
|
||||||
return hci_conn_auth(conn, sec_level, auth_type);
|
return hci_conn_auth(conn, sec_level, auth_type);
|
||||||
|
|
|
@ -883,6 +883,7 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||||
if (conn->type == ACL_LINK) {
|
if (conn->type == ACL_LINK) {
|
||||||
conn->state = BT_CONFIG;
|
conn->state = BT_CONFIG;
|
||||||
hci_conn_hold(conn);
|
hci_conn_hold(conn);
|
||||||
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
} else
|
} else
|
||||||
conn->state = BT_CONNECTED;
|
conn->state = BT_CONNECTED;
|
||||||
|
|
||||||
|
@ -1063,9 +1064,14 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
|
||||||
hci_proto_connect_cfm(conn, ev->status);
|
hci_proto_connect_cfm(conn, ev->status);
|
||||||
hci_conn_put(conn);
|
hci_conn_put(conn);
|
||||||
}
|
}
|
||||||
} else
|
} else {
|
||||||
hci_auth_cfm(conn, ev->status);
|
hci_auth_cfm(conn, ev->status);
|
||||||
|
|
||||||
|
hci_conn_hold(conn);
|
||||||
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
|
hci_conn_put(conn);
|
||||||
|
}
|
||||||
|
|
||||||
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
|
if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend)) {
|
||||||
if (!ev->status) {
|
if (!ev->status) {
|
||||||
struct hci_cp_set_conn_encrypt cp;
|
struct hci_cp_set_conn_encrypt cp;
|
||||||
|
@ -1479,7 +1485,21 @@ static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb
|
||||||
|
|
||||||
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
static inline void hci_pin_code_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
struct hci_ev_pin_code_req *ev = (void *) skb->data;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||||
|
if (conn) {
|
||||||
|
hci_conn_hold(conn);
|
||||||
|
conn->disc_timeout = HCI_PAIRING_TIMEOUT;
|
||||||
|
hci_conn_put(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
@ -1489,7 +1509,21 @@ static inline void hci_link_key_request_evt(struct hci_dev *hdev, struct sk_buff
|
||||||
|
|
||||||
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
static inline void hci_link_key_notify_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
|
struct hci_ev_link_key_notify *ev = (void *) skb->data;
|
||||||
|
struct hci_conn *conn;
|
||||||
|
|
||||||
BT_DBG("%s", hdev->name);
|
BT_DBG("%s", hdev->name);
|
||||||
|
|
||||||
|
hci_dev_lock(hdev);
|
||||||
|
|
||||||
|
conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
|
||||||
|
if (conn) {
|
||||||
|
hci_conn_hold(conn);
|
||||||
|
conn->disc_timeout = HCI_DISCONN_TIMEOUT;
|
||||||
|
hci_conn_put(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
hci_dev_unlock(hdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *skb)
|
||||||
|
|
|
@ -9,8 +9,7 @@
|
||||||
struct class *bt_class = NULL;
|
struct class *bt_class = NULL;
|
||||||
EXPORT_SYMBOL_GPL(bt_class);
|
EXPORT_SYMBOL_GPL(bt_class);
|
||||||
|
|
||||||
static struct workqueue_struct *btaddconn;
|
static struct workqueue_struct *bluetooth;
|
||||||
static struct workqueue_struct *btdelconn;
|
|
||||||
|
|
||||||
static inline char *link_typetostr(int type)
|
static inline char *link_typetostr(int type)
|
||||||
{
|
{
|
||||||
|
@ -88,9 +87,10 @@ static struct device_type bt_link = {
|
||||||
|
|
||||||
static void add_conn(struct work_struct *work)
|
static void add_conn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct hci_conn *conn = container_of(work, struct hci_conn, work);
|
struct hci_conn *conn = container_of(work, struct hci_conn, work_add);
|
||||||
|
|
||||||
flush_workqueue(btdelconn);
|
/* ensure previous add/del is complete */
|
||||||
|
flush_workqueue(bluetooth);
|
||||||
|
|
||||||
if (device_add(&conn->dev) < 0) {
|
if (device_add(&conn->dev) < 0) {
|
||||||
BT_ERR("Failed to register connection device");
|
BT_ERR("Failed to register connection device");
|
||||||
|
@ -114,9 +114,9 @@ void hci_conn_add_sysfs(struct hci_conn *conn)
|
||||||
|
|
||||||
device_initialize(&conn->dev);
|
device_initialize(&conn->dev);
|
||||||
|
|
||||||
INIT_WORK(&conn->work, add_conn);
|
INIT_WORK(&conn->work_add, add_conn);
|
||||||
|
|
||||||
queue_work(btaddconn, &conn->work);
|
queue_work(bluetooth, &conn->work_add);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -131,9 +131,12 @@ static int __match_tty(struct device *dev, void *data)
|
||||||
|
|
||||||
static void del_conn(struct work_struct *work)
|
static void del_conn(struct work_struct *work)
|
||||||
{
|
{
|
||||||
struct hci_conn *conn = container_of(work, struct hci_conn, work);
|
struct hci_conn *conn = container_of(work, struct hci_conn, work_del);
|
||||||
struct hci_dev *hdev = conn->hdev;
|
struct hci_dev *hdev = conn->hdev;
|
||||||
|
|
||||||
|
/* ensure previous add/del is complete */
|
||||||
|
flush_workqueue(bluetooth);
|
||||||
|
|
||||||
while (1) {
|
while (1) {
|
||||||
struct device *dev;
|
struct device *dev;
|
||||||
|
|
||||||
|
@ -156,9 +159,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
|
||||||
if (!device_is_registered(&conn->dev))
|
if (!device_is_registered(&conn->dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
INIT_WORK(&conn->work, del_conn);
|
INIT_WORK(&conn->work_del, del_conn);
|
||||||
|
|
||||||
queue_work(btdelconn, &conn->work);
|
queue_work(bluetooth, &conn->work_del);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline char *host_typetostr(int type)
|
static inline char *host_typetostr(int type)
|
||||||
|
@ -435,20 +438,13 @@ void hci_unregister_sysfs(struct hci_dev *hdev)
|
||||||
|
|
||||||
int __init bt_sysfs_init(void)
|
int __init bt_sysfs_init(void)
|
||||||
{
|
{
|
||||||
btaddconn = create_singlethread_workqueue("btaddconn");
|
bluetooth = create_singlethread_workqueue("bluetooth");
|
||||||
if (!btaddconn)
|
if (!bluetooth)
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
|
||||||
btdelconn = create_singlethread_workqueue("btdelconn");
|
|
||||||
if (!btdelconn) {
|
|
||||||
destroy_workqueue(btaddconn);
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
bt_class = class_create(THIS_MODULE, "bluetooth");
|
bt_class = class_create(THIS_MODULE, "bluetooth");
|
||||||
if (IS_ERR(bt_class)) {
|
if (IS_ERR(bt_class)) {
|
||||||
destroy_workqueue(btdelconn);
|
destroy_workqueue(bluetooth);
|
||||||
destroy_workqueue(btaddconn);
|
|
||||||
return PTR_ERR(bt_class);
|
return PTR_ERR(bt_class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -457,8 +453,7 @@ int __init bt_sysfs_init(void)
|
||||||
|
|
||||||
void bt_sysfs_cleanup(void)
|
void bt_sysfs_cleanup(void)
|
||||||
{
|
{
|
||||||
destroy_workqueue(btaddconn);
|
destroy_workqueue(bluetooth);
|
||||||
destroy_workqueue(btdelconn);
|
|
||||||
|
|
||||||
class_destroy(bt_class);
|
class_destroy(bt_class);
|
||||||
}
|
}
|
||||||
|
|
|
@ -788,15 +788,23 @@ static unsigned int br_nf_local_out(unsigned int hook, struct sk_buff *skb,
|
||||||
return NF_STOLEN;
|
return NF_STOLEN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if defined(CONFIG_NF_CONNTRACK_IPV4) || defined(CONFIG_NF_CONNTRACK_IPV4_MODULE)
|
||||||
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
|
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
if (skb->protocol == htons(ETH_P_IP) &&
|
if (skb->nfct != NULL &&
|
||||||
|
(skb->protocol == htons(ETH_P_IP) || IS_VLAN_IP(skb)) &&
|
||||||
skb->len > skb->dev->mtu &&
|
skb->len > skb->dev->mtu &&
|
||||||
!skb_is_gso(skb))
|
!skb_is_gso(skb))
|
||||||
return ip_fragment(skb, br_dev_queue_push_xmit);
|
return ip_fragment(skb, br_dev_queue_push_xmit);
|
||||||
else
|
else
|
||||||
return br_dev_queue_push_xmit(skb);
|
return br_dev_queue_push_xmit(skb);
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
static int br_nf_dev_queue_xmit(struct sk_buff *skb)
|
||||||
|
{
|
||||||
|
return br_dev_queue_push_xmit(skb);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
/* PF_BRIDGE/POST_ROUTING ********************************************/
|
/* PF_BRIDGE/POST_ROUTING ********************************************/
|
||||||
static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
|
static unsigned int br_nf_post_routing(unsigned int hook, struct sk_buff *skb,
|
||||||
|
|
|
@ -64,13 +64,25 @@ static inline int connection_based(struct sock *sk)
|
||||||
return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
|
return sk->sk_type == SOCK_SEQPACKET || sk->sk_type == SOCK_STREAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int receiver_wake_function(wait_queue_t *wait, unsigned mode, int sync,
|
||||||
|
void *key)
|
||||||
|
{
|
||||||
|
unsigned long bits = (unsigned long)key;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Avoid a wakeup if event not interesting for us
|
||||||
|
*/
|
||||||
|
if (bits && !(bits & (POLLIN | POLLERR)))
|
||||||
|
return 0;
|
||||||
|
return autoremove_wake_function(wait, mode, sync, key);
|
||||||
|
}
|
||||||
/*
|
/*
|
||||||
* Wait for a packet..
|
* Wait for a packet..
|
||||||
*/
|
*/
|
||||||
static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
|
static int wait_for_packet(struct sock *sk, int *err, long *timeo_p)
|
||||||
{
|
{
|
||||||
int error;
|
int error;
|
||||||
DEFINE_WAIT(wait);
|
DEFINE_WAIT_FUNC(wait, receiver_wake_function);
|
||||||
|
|
||||||
prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
prepare_to_wait_exclusive(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||||
|
|
||||||
|
|
|
@ -253,9 +253,9 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||||
indev = in ? in->name : nulldevname;
|
indev = in ? in->name : nulldevname;
|
||||||
outdev = out ? out->name : nulldevname;
|
outdev = out ? out->name : nulldevname;
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
xt_info_rdlock_bh();
|
||||||
private = rcu_dereference(table->private);
|
private = table->private;
|
||||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
table_base = private->entries[smp_processor_id()];
|
||||||
|
|
||||||
e = get_entry(table_base, private->hook_entry[hook]);
|
e = get_entry(table_base, private->hook_entry[hook]);
|
||||||
back = get_entry(table_base, private->underflow[hook]);
|
back = get_entry(table_base, private->underflow[hook]);
|
||||||
|
@ -273,6 +273,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||||
|
|
||||||
hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
|
hdr_len = sizeof(*arp) + (2 * sizeof(struct in_addr)) +
|
||||||
(2 * skb->dev->addr_len);
|
(2 * skb->dev->addr_len);
|
||||||
|
|
||||||
ADD_COUNTER(e->counters, hdr_len, 1);
|
ADD_COUNTER(e->counters, hdr_len, 1);
|
||||||
|
|
||||||
t = arpt_get_target(e);
|
t = arpt_get_target(e);
|
||||||
|
@ -328,8 +329,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
|
||||||
e = (void *)e + e->next_offset;
|
e = (void *)e + e->next_offset;
|
||||||
}
|
}
|
||||||
} while (!hotdrop);
|
} while (!hotdrop);
|
||||||
|
xt_info_rdunlock_bh();
|
||||||
rcu_read_unlock_bh();
|
|
||||||
|
|
||||||
if (hotdrop)
|
if (hotdrop)
|
||||||
return NF_DROP;
|
return NF_DROP;
|
||||||
|
@ -711,9 +711,12 @@ static void get_counters(const struct xt_table_info *t,
|
||||||
/* Instead of clearing (by a previous call to memset())
|
/* Instead of clearing (by a previous call to memset())
|
||||||
* the counters and using adds, we set the counters
|
* the counters and using adds, we set the counters
|
||||||
* with data used by 'current' CPU
|
* with data used by 'current' CPU
|
||||||
* We dont care about preemption here.
|
*
|
||||||
|
* Bottom half has to be disabled to prevent deadlock
|
||||||
|
* if new softirq were to run and call ipt_do_table
|
||||||
*/
|
*/
|
||||||
curcpu = raw_smp_processor_id();
|
local_bh_disable();
|
||||||
|
curcpu = smp_processor_id();
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
ARPT_ENTRY_ITERATE(t->entries[curcpu],
|
ARPT_ENTRY_ITERATE(t->entries[curcpu],
|
||||||
|
@ -726,73 +729,22 @@ static void get_counters(const struct xt_table_info *t,
|
||||||
if (cpu == curcpu)
|
if (cpu == curcpu)
|
||||||
continue;
|
continue;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
xt_info_wrlock(cpu);
|
||||||
ARPT_ENTRY_ITERATE(t->entries[cpu],
|
ARPT_ENTRY_ITERATE(t->entries[cpu],
|
||||||
t->size,
|
t->size,
|
||||||
add_entry_to_counter,
|
add_entry_to_counter,
|
||||||
counters,
|
counters,
|
||||||
&i);
|
&i);
|
||||||
|
xt_info_wrunlock(cpu);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
|
||||||
* and everything is OK. */
|
|
||||||
static int
|
|
||||||
add_counter_to_entry(struct arpt_entry *e,
|
|
||||||
const struct xt_counters addme[],
|
|
||||||
unsigned int *i)
|
|
||||||
{
|
|
||||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
|
||||||
|
|
||||||
(*i)++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take values from counters and add them back onto the current cpu */
|
|
||||||
static void put_counters(struct xt_table_info *t,
|
|
||||||
const struct xt_counters counters[])
|
|
||||||
{
|
|
||||||
unsigned int i, cpu;
|
|
||||||
|
|
||||||
local_bh_disable();
|
|
||||||
cpu = smp_processor_id();
|
|
||||||
i = 0;
|
|
||||||
ARPT_ENTRY_ITERATE(t->entries[cpu],
|
|
||||||
t->size,
|
|
||||||
add_counter_to_entry,
|
|
||||||
counters,
|
|
||||||
&i);
|
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
zero_entry_counter(struct arpt_entry *e, void *arg)
|
|
||||||
{
|
|
||||||
e->counters.bcnt = 0;
|
|
||||||
e->counters.pcnt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
|
||||||
{
|
|
||||||
unsigned int cpu;
|
|
||||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
|
||||||
|
|
||||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
|
||||||
ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
|
||||||
zero_entry_counter, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct xt_counters *alloc_counters(struct xt_table *table)
|
static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||||
{
|
{
|
||||||
unsigned int countersize;
|
unsigned int countersize;
|
||||||
struct xt_counters *counters;
|
struct xt_counters *counters;
|
||||||
struct xt_table_info *private = table->private;
|
struct xt_table_info *private = table->private;
|
||||||
struct xt_table_info *info;
|
|
||||||
|
|
||||||
/* We need atomic snapshot of counters: rest doesn't change
|
/* We need atomic snapshot of counters: rest doesn't change
|
||||||
* (other than comefrom, which userspace doesn't care
|
* (other than comefrom, which userspace doesn't care
|
||||||
|
@ -802,30 +754,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||||
counters = vmalloc_node(countersize, numa_node_id());
|
counters = vmalloc_node(countersize, numa_node_id());
|
||||||
|
|
||||||
if (counters == NULL)
|
if (counters == NULL)
|
||||||
goto nomem;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
info = xt_alloc_table_info(private->size);
|
get_counters(private, counters);
|
||||||
if (!info)
|
|
||||||
goto free_counters;
|
|
||||||
|
|
||||||
clone_counters(info, private);
|
|
||||||
|
|
||||||
mutex_lock(&table->lock);
|
|
||||||
xt_table_entry_swap_rcu(private, info);
|
|
||||||
synchronize_net(); /* Wait until smoke has cleared */
|
|
||||||
|
|
||||||
get_counters(info, counters);
|
|
||||||
put_counters(private, counters);
|
|
||||||
mutex_unlock(&table->lock);
|
|
||||||
|
|
||||||
xt_free_table_info(info);
|
|
||||||
|
|
||||||
return counters;
|
return counters;
|
||||||
|
|
||||||
free_counters:
|
|
||||||
vfree(counters);
|
|
||||||
nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int copy_entries_to_user(unsigned int total_size,
|
static int copy_entries_to_user(unsigned int total_size,
|
||||||
|
@ -1094,8 +1027,9 @@ static int __do_replace(struct net *net, const char *name,
|
||||||
(newinfo->number <= oldinfo->initial_entries))
|
(newinfo->number <= oldinfo->initial_entries))
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
|
|
||||||
/* Get the old counters. */
|
/* Get the old counters, and synchronize with replace */
|
||||||
get_counters(oldinfo, counters);
|
get_counters(oldinfo, counters);
|
||||||
|
|
||||||
/* Decrease module usage counts and free resource */
|
/* Decrease module usage counts and free resource */
|
||||||
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
||||||
ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
ARPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
||||||
|
@ -1165,10 +1099,23 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||||
|
* and everything is OK. */
|
||||||
|
static int
|
||||||
|
add_counter_to_entry(struct arpt_entry *e,
|
||||||
|
const struct xt_counters addme[],
|
||||||
|
unsigned int *i)
|
||||||
|
{
|
||||||
|
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||||
|
|
||||||
|
(*i)++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||||
int compat)
|
int compat)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i, curcpu;
|
||||||
struct xt_counters_info tmp;
|
struct xt_counters_info tmp;
|
||||||
struct xt_counters *paddc;
|
struct xt_counters *paddc;
|
||||||
unsigned int num_counters;
|
unsigned int num_counters;
|
||||||
|
@ -1224,26 +1171,26 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&t->lock);
|
local_bh_disable();
|
||||||
private = t->private;
|
private = t->private;
|
||||||
if (private->number != num_counters) {
|
if (private->number != num_counters) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlock_up_free;
|
goto unlock_up_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
i = 0;
|
i = 0;
|
||||||
/* Choose the copy that is on our node */
|
/* Choose the copy that is on our node */
|
||||||
loc_cpu_entry = private->entries[smp_processor_id()];
|
curcpu = smp_processor_id();
|
||||||
|
loc_cpu_entry = private->entries[curcpu];
|
||||||
|
xt_info_wrlock(curcpu);
|
||||||
ARPT_ENTRY_ITERATE(loc_cpu_entry,
|
ARPT_ENTRY_ITERATE(loc_cpu_entry,
|
||||||
private->size,
|
private->size,
|
||||||
add_counter_to_entry,
|
add_counter_to_entry,
|
||||||
paddc,
|
paddc,
|
||||||
&i);
|
&i);
|
||||||
preempt_enable();
|
xt_info_wrunlock(curcpu);
|
||||||
unlock_up_free:
|
unlock_up_free:
|
||||||
mutex_unlock(&t->lock);
|
local_bh_enable();
|
||||||
|
|
||||||
xt_table_unlock(t);
|
xt_table_unlock(t);
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
free:
|
free:
|
||||||
|
|
|
@ -338,10 +338,9 @@ ipt_do_table(struct sk_buff *skb,
|
||||||
tgpar.hooknum = hook;
|
tgpar.hooknum = hook;
|
||||||
|
|
||||||
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
||||||
|
xt_info_rdlock_bh();
|
||||||
rcu_read_lock_bh();
|
private = table->private;
|
||||||
private = rcu_dereference(table->private);
|
table_base = private->entries[smp_processor_id()];
|
||||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
|
||||||
|
|
||||||
e = get_entry(table_base, private->hook_entry[hook]);
|
e = get_entry(table_base, private->hook_entry[hook]);
|
||||||
|
|
||||||
|
@ -436,8 +435,7 @@ ipt_do_table(struct sk_buff *skb,
|
||||||
e = (void *)e + e->next_offset;
|
e = (void *)e + e->next_offset;
|
||||||
}
|
}
|
||||||
} while (!hotdrop);
|
} while (!hotdrop);
|
||||||
|
xt_info_rdunlock_bh();
|
||||||
rcu_read_unlock_bh();
|
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOW_ALL
|
#ifdef DEBUG_ALLOW_ALL
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
@ -896,10 +894,13 @@ get_counters(const struct xt_table_info *t,
|
||||||
|
|
||||||
/* Instead of clearing (by a previous call to memset())
|
/* Instead of clearing (by a previous call to memset())
|
||||||
* the counters and using adds, we set the counters
|
* the counters and using adds, we set the counters
|
||||||
* with data used by 'current' CPU
|
* with data used by 'current' CPU.
|
||||||
* We dont care about preemption here.
|
*
|
||||||
|
* Bottom half has to be disabled to prevent deadlock
|
||||||
|
* if new softirq were to run and call ipt_do_table
|
||||||
*/
|
*/
|
||||||
curcpu = raw_smp_processor_id();
|
local_bh_disable();
|
||||||
|
curcpu = smp_processor_id();
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
IPT_ENTRY_ITERATE(t->entries[curcpu],
|
IPT_ENTRY_ITERATE(t->entries[curcpu],
|
||||||
|
@ -912,74 +913,22 @@ get_counters(const struct xt_table_info *t,
|
||||||
if (cpu == curcpu)
|
if (cpu == curcpu)
|
||||||
continue;
|
continue;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
xt_info_wrlock(cpu);
|
||||||
IPT_ENTRY_ITERATE(t->entries[cpu],
|
IPT_ENTRY_ITERATE(t->entries[cpu],
|
||||||
t->size,
|
t->size,
|
||||||
add_entry_to_counter,
|
add_entry_to_counter,
|
||||||
counters,
|
counters,
|
||||||
&i);
|
&i);
|
||||||
|
xt_info_wrunlock(cpu);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
|
||||||
* and everything is OK. */
|
|
||||||
static int
|
|
||||||
add_counter_to_entry(struct ipt_entry *e,
|
|
||||||
const struct xt_counters addme[],
|
|
||||||
unsigned int *i)
|
|
||||||
{
|
|
||||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
|
||||||
|
|
||||||
(*i)++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take values from counters and add them back onto the current cpu */
|
|
||||||
static void put_counters(struct xt_table_info *t,
|
|
||||||
const struct xt_counters counters[])
|
|
||||||
{
|
|
||||||
unsigned int i, cpu;
|
|
||||||
|
|
||||||
local_bh_disable();
|
|
||||||
cpu = smp_processor_id();
|
|
||||||
i = 0;
|
|
||||||
IPT_ENTRY_ITERATE(t->entries[cpu],
|
|
||||||
t->size,
|
|
||||||
add_counter_to_entry,
|
|
||||||
counters,
|
|
||||||
&i);
|
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static inline int
|
|
||||||
zero_entry_counter(struct ipt_entry *e, void *arg)
|
|
||||||
{
|
|
||||||
e->counters.bcnt = 0;
|
|
||||||
e->counters.pcnt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
|
||||||
{
|
|
||||||
unsigned int cpu;
|
|
||||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
|
||||||
|
|
||||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
|
||||||
IPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
|
||||||
zero_entry_counter, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct xt_counters * alloc_counters(struct xt_table *table)
|
static struct xt_counters * alloc_counters(struct xt_table *table)
|
||||||
{
|
{
|
||||||
unsigned int countersize;
|
unsigned int countersize;
|
||||||
struct xt_counters *counters;
|
struct xt_counters *counters;
|
||||||
struct xt_table_info *private = table->private;
|
struct xt_table_info *private = table->private;
|
||||||
struct xt_table_info *info;
|
|
||||||
|
|
||||||
/* We need atomic snapshot of counters: rest doesn't change
|
/* We need atomic snapshot of counters: rest doesn't change
|
||||||
(other than comefrom, which userspace doesn't care
|
(other than comefrom, which userspace doesn't care
|
||||||
|
@ -988,30 +937,11 @@ static struct xt_counters * alloc_counters(struct xt_table *table)
|
||||||
counters = vmalloc_node(countersize, numa_node_id());
|
counters = vmalloc_node(countersize, numa_node_id());
|
||||||
|
|
||||||
if (counters == NULL)
|
if (counters == NULL)
|
||||||
goto nomem;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
info = xt_alloc_table_info(private->size);
|
get_counters(private, counters);
|
||||||
if (!info)
|
|
||||||
goto free_counters;
|
|
||||||
|
|
||||||
clone_counters(info, private);
|
|
||||||
|
|
||||||
mutex_lock(&table->lock);
|
|
||||||
xt_table_entry_swap_rcu(private, info);
|
|
||||||
synchronize_net(); /* Wait until smoke has cleared */
|
|
||||||
|
|
||||||
get_counters(info, counters);
|
|
||||||
put_counters(private, counters);
|
|
||||||
mutex_unlock(&table->lock);
|
|
||||||
|
|
||||||
xt_free_table_info(info);
|
|
||||||
|
|
||||||
return counters;
|
return counters;
|
||||||
|
|
||||||
free_counters:
|
|
||||||
vfree(counters);
|
|
||||||
nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1306,8 +1236,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
|
||||||
(newinfo->number <= oldinfo->initial_entries))
|
(newinfo->number <= oldinfo->initial_entries))
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
|
|
||||||
/* Get the old counters. */
|
/* Get the old counters, and synchronize with replace */
|
||||||
get_counters(oldinfo, counters);
|
get_counters(oldinfo, counters);
|
||||||
|
|
||||||
/* Decrease module usage counts and free resource */
|
/* Decrease module usage counts and free resource */
|
||||||
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
||||||
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
IPT_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
||||||
|
@ -1377,11 +1308,23 @@ do_replace(struct net *net, void __user *user, unsigned int len)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||||
|
* and everything is OK. */
|
||||||
|
static int
|
||||||
|
add_counter_to_entry(struct ipt_entry *e,
|
||||||
|
const struct xt_counters addme[],
|
||||||
|
unsigned int *i)
|
||||||
|
{
|
||||||
|
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||||
|
|
||||||
|
(*i)++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
|
do_add_counters(struct net *net, void __user *user, unsigned int len, int compat)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i, curcpu;
|
||||||
struct xt_counters_info tmp;
|
struct xt_counters_info tmp;
|
||||||
struct xt_counters *paddc;
|
struct xt_counters *paddc;
|
||||||
unsigned int num_counters;
|
unsigned int num_counters;
|
||||||
|
@ -1437,25 +1380,26 @@ do_add_counters(struct net *net, void __user *user, unsigned int len, int compat
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&t->lock);
|
local_bh_disable();
|
||||||
private = t->private;
|
private = t->private;
|
||||||
if (private->number != num_counters) {
|
if (private->number != num_counters) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlock_up_free;
|
goto unlock_up_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
i = 0;
|
i = 0;
|
||||||
/* Choose the copy that is on our node */
|
/* Choose the copy that is on our node */
|
||||||
loc_cpu_entry = private->entries[raw_smp_processor_id()];
|
curcpu = smp_processor_id();
|
||||||
|
loc_cpu_entry = private->entries[curcpu];
|
||||||
|
xt_info_wrlock(curcpu);
|
||||||
IPT_ENTRY_ITERATE(loc_cpu_entry,
|
IPT_ENTRY_ITERATE(loc_cpu_entry,
|
||||||
private->size,
|
private->size,
|
||||||
add_counter_to_entry,
|
add_counter_to_entry,
|
||||||
paddc,
|
paddc,
|
||||||
&i);
|
&i);
|
||||||
preempt_enable();
|
xt_info_wrunlock(curcpu);
|
||||||
unlock_up_free:
|
unlock_up_free:
|
||||||
mutex_unlock(&t->lock);
|
local_bh_enable();
|
||||||
xt_table_unlock(t);
|
xt_table_unlock(t);
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
free:
|
free:
|
||||||
|
|
|
@ -3397,7 +3397,7 @@ int __init ip_rt_init(void)
|
||||||
0,
|
0,
|
||||||
&rt_hash_log,
|
&rt_hash_log,
|
||||||
&rt_hash_mask,
|
&rt_hash_mask,
|
||||||
0);
|
rhash_entries ? 0 : 512 * 1024);
|
||||||
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
|
memset(rt_hash_table, 0, (rt_hash_mask + 1) * sizeof(struct rt_hash_bucket));
|
||||||
rt_hash_lock_init();
|
rt_hash_lock_init();
|
||||||
|
|
||||||
|
|
|
@ -365,9 +365,9 @@ ip6t_do_table(struct sk_buff *skb,
|
||||||
|
|
||||||
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
IP_NF_ASSERT(table->valid_hooks & (1 << hook));
|
||||||
|
|
||||||
rcu_read_lock_bh();
|
xt_info_rdlock_bh();
|
||||||
private = rcu_dereference(table->private);
|
private = table->private;
|
||||||
table_base = rcu_dereference(private->entries[smp_processor_id()]);
|
table_base = private->entries[smp_processor_id()];
|
||||||
|
|
||||||
e = get_entry(table_base, private->hook_entry[hook]);
|
e = get_entry(table_base, private->hook_entry[hook]);
|
||||||
|
|
||||||
|
@ -466,7 +466,7 @@ ip6t_do_table(struct sk_buff *skb,
|
||||||
#ifdef CONFIG_NETFILTER_DEBUG
|
#ifdef CONFIG_NETFILTER_DEBUG
|
||||||
((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
|
((struct ip6t_entry *)table_base)->comefrom = NETFILTER_LINK_POISON;
|
||||||
#endif
|
#endif
|
||||||
rcu_read_unlock_bh();
|
xt_info_rdunlock_bh();
|
||||||
|
|
||||||
#ifdef DEBUG_ALLOW_ALL
|
#ifdef DEBUG_ALLOW_ALL
|
||||||
return NF_ACCEPT;
|
return NF_ACCEPT;
|
||||||
|
@ -926,9 +926,12 @@ get_counters(const struct xt_table_info *t,
|
||||||
/* Instead of clearing (by a previous call to memset())
|
/* Instead of clearing (by a previous call to memset())
|
||||||
* the counters and using adds, we set the counters
|
* the counters and using adds, we set the counters
|
||||||
* with data used by 'current' CPU
|
* with data used by 'current' CPU
|
||||||
* We dont care about preemption here.
|
*
|
||||||
|
* Bottom half has to be disabled to prevent deadlock
|
||||||
|
* if new softirq were to run and call ipt_do_table
|
||||||
*/
|
*/
|
||||||
curcpu = raw_smp_processor_id();
|
local_bh_disable();
|
||||||
|
curcpu = smp_processor_id();
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
IP6T_ENTRY_ITERATE(t->entries[curcpu],
|
IP6T_ENTRY_ITERATE(t->entries[curcpu],
|
||||||
|
@ -941,72 +944,22 @@ get_counters(const struct xt_table_info *t,
|
||||||
if (cpu == curcpu)
|
if (cpu == curcpu)
|
||||||
continue;
|
continue;
|
||||||
i = 0;
|
i = 0;
|
||||||
|
xt_info_wrlock(cpu);
|
||||||
IP6T_ENTRY_ITERATE(t->entries[cpu],
|
IP6T_ENTRY_ITERATE(t->entries[cpu],
|
||||||
t->size,
|
t->size,
|
||||||
add_entry_to_counter,
|
add_entry_to_counter,
|
||||||
counters,
|
counters,
|
||||||
&i);
|
&i);
|
||||||
|
xt_info_wrunlock(cpu);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
|
||||||
* and everything is OK. */
|
|
||||||
static int
|
|
||||||
add_counter_to_entry(struct ip6t_entry *e,
|
|
||||||
const struct xt_counters addme[],
|
|
||||||
unsigned int *i)
|
|
||||||
{
|
|
||||||
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
|
||||||
|
|
||||||
(*i)++;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Take values from counters and add them back onto the current cpu */
|
|
||||||
static void put_counters(struct xt_table_info *t,
|
|
||||||
const struct xt_counters counters[])
|
|
||||||
{
|
|
||||||
unsigned int i, cpu;
|
|
||||||
|
|
||||||
local_bh_disable();
|
|
||||||
cpu = smp_processor_id();
|
|
||||||
i = 0;
|
|
||||||
IP6T_ENTRY_ITERATE(t->entries[cpu],
|
|
||||||
t->size,
|
|
||||||
add_counter_to_entry,
|
|
||||||
counters,
|
|
||||||
&i);
|
|
||||||
local_bh_enable();
|
local_bh_enable();
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline int
|
|
||||||
zero_entry_counter(struct ip6t_entry *e, void *arg)
|
|
||||||
{
|
|
||||||
e->counters.bcnt = 0;
|
|
||||||
e->counters.pcnt = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
|
|
||||||
{
|
|
||||||
unsigned int cpu;
|
|
||||||
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
|
|
||||||
|
|
||||||
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
|
|
||||||
IP6T_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
|
|
||||||
zero_entry_counter, NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static struct xt_counters *alloc_counters(struct xt_table *table)
|
static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||||
{
|
{
|
||||||
unsigned int countersize;
|
unsigned int countersize;
|
||||||
struct xt_counters *counters;
|
struct xt_counters *counters;
|
||||||
struct xt_table_info *private = table->private;
|
struct xt_table_info *private = table->private;
|
||||||
struct xt_table_info *info;
|
|
||||||
|
|
||||||
/* We need atomic snapshot of counters: rest doesn't change
|
/* We need atomic snapshot of counters: rest doesn't change
|
||||||
(other than comefrom, which userspace doesn't care
|
(other than comefrom, which userspace doesn't care
|
||||||
|
@ -1015,30 +968,11 @@ static struct xt_counters *alloc_counters(struct xt_table *table)
|
||||||
counters = vmalloc_node(countersize, numa_node_id());
|
counters = vmalloc_node(countersize, numa_node_id());
|
||||||
|
|
||||||
if (counters == NULL)
|
if (counters == NULL)
|
||||||
goto nomem;
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
info = xt_alloc_table_info(private->size);
|
get_counters(private, counters);
|
||||||
if (!info)
|
|
||||||
goto free_counters;
|
|
||||||
|
|
||||||
clone_counters(info, private);
|
|
||||||
|
|
||||||
mutex_lock(&table->lock);
|
|
||||||
xt_table_entry_swap_rcu(private, info);
|
|
||||||
synchronize_net(); /* Wait until smoke has cleared */
|
|
||||||
|
|
||||||
get_counters(info, counters);
|
|
||||||
put_counters(private, counters);
|
|
||||||
mutex_unlock(&table->lock);
|
|
||||||
|
|
||||||
xt_free_table_info(info);
|
|
||||||
|
|
||||||
return counters;
|
return counters;
|
||||||
|
|
||||||
free_counters:
|
|
||||||
vfree(counters);
|
|
||||||
nomem:
|
|
||||||
return ERR_PTR(-ENOMEM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
|
@ -1334,8 +1268,9 @@ __do_replace(struct net *net, const char *name, unsigned int valid_hooks,
|
||||||
(newinfo->number <= oldinfo->initial_entries))
|
(newinfo->number <= oldinfo->initial_entries))
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
|
|
||||||
/* Get the old counters. */
|
/* Get the old counters, and synchronize with replace */
|
||||||
get_counters(oldinfo, counters);
|
get_counters(oldinfo, counters);
|
||||||
|
|
||||||
/* Decrease module usage counts and free resource */
|
/* Decrease module usage counts and free resource */
|
||||||
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
loc_cpu_old_entry = oldinfo->entries[raw_smp_processor_id()];
|
||||||
IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
IP6T_ENTRY_ITERATE(loc_cpu_old_entry, oldinfo->size, cleanup_entry,
|
||||||
|
@ -1405,11 +1340,24 @@ do_replace(struct net *net, void __user *user, unsigned int len)
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* We're lazy, and add to the first CPU; overflow works its fey magic
|
||||||
|
* and everything is OK. */
|
||||||
|
static int
|
||||||
|
add_counter_to_entry(struct ip6t_entry *e,
|
||||||
|
const struct xt_counters addme[],
|
||||||
|
unsigned int *i)
|
||||||
|
{
|
||||||
|
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
|
||||||
|
|
||||||
|
(*i)++;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
do_add_counters(struct net *net, void __user *user, unsigned int len,
|
do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||||
int compat)
|
int compat)
|
||||||
{
|
{
|
||||||
unsigned int i;
|
unsigned int i, curcpu;
|
||||||
struct xt_counters_info tmp;
|
struct xt_counters_info tmp;
|
||||||
struct xt_counters *paddc;
|
struct xt_counters *paddc;
|
||||||
unsigned int num_counters;
|
unsigned int num_counters;
|
||||||
|
@ -1465,25 +1413,28 @@ do_add_counters(struct net *net, void __user *user, unsigned int len,
|
||||||
goto free;
|
goto free;
|
||||||
}
|
}
|
||||||
|
|
||||||
mutex_lock(&t->lock);
|
|
||||||
|
local_bh_disable();
|
||||||
private = t->private;
|
private = t->private;
|
||||||
if (private->number != num_counters) {
|
if (private->number != num_counters) {
|
||||||
ret = -EINVAL;
|
ret = -EINVAL;
|
||||||
goto unlock_up_free;
|
goto unlock_up_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
preempt_disable();
|
|
||||||
i = 0;
|
i = 0;
|
||||||
/* Choose the copy that is on our node */
|
/* Choose the copy that is on our node */
|
||||||
loc_cpu_entry = private->entries[raw_smp_processor_id()];
|
curcpu = smp_processor_id();
|
||||||
|
xt_info_wrlock(curcpu);
|
||||||
|
loc_cpu_entry = private->entries[curcpu];
|
||||||
IP6T_ENTRY_ITERATE(loc_cpu_entry,
|
IP6T_ENTRY_ITERATE(loc_cpu_entry,
|
||||||
private->size,
|
private->size,
|
||||||
add_counter_to_entry,
|
add_counter_to_entry,
|
||||||
paddc,
|
paddc,
|
||||||
&i);
|
&i);
|
||||||
preempt_enable();
|
xt_info_wrunlock(curcpu);
|
||||||
|
|
||||||
unlock_up_free:
|
unlock_up_free:
|
||||||
mutex_unlock(&t->lock);
|
local_bh_enable();
|
||||||
xt_table_unlock(t);
|
xt_table_unlock(t);
|
||||||
module_put(t->me);
|
module_put(t->me);
|
||||||
free:
|
free:
|
||||||
|
|
|
@ -275,6 +275,8 @@ config NF_CT_NETLINK
|
||||||
help
|
help
|
||||||
This option enables support for a netlink-based userspace interface
|
This option enables support for a netlink-based userspace interface
|
||||||
|
|
||||||
|
endif # NF_CONNTRACK
|
||||||
|
|
||||||
# transparent proxy support
|
# transparent proxy support
|
||||||
config NETFILTER_TPROXY
|
config NETFILTER_TPROXY
|
||||||
tristate "Transparent proxying support (EXPERIMENTAL)"
|
tristate "Transparent proxying support (EXPERIMENTAL)"
|
||||||
|
@ -290,8 +292,6 @@ config NETFILTER_TPROXY
|
||||||
|
|
||||||
To compile it as a module, choose M here. If unsure, say N.
|
To compile it as a module, choose M here. If unsure, say N.
|
||||||
|
|
||||||
endif # NF_CONNTRACK
|
|
||||||
|
|
||||||
config NETFILTER_XTABLES
|
config NETFILTER_XTABLES
|
||||||
tristate "Netfilter Xtables support (required for ip_tables)"
|
tristate "Netfilter Xtables support (required for ip_tables)"
|
||||||
default m if NETFILTER_ADVANCED=n
|
default m if NETFILTER_ADVANCED=n
|
||||||
|
|
|
@ -633,6 +633,8 @@ static int dccp_to_nlattr(struct sk_buff *skb, struct nlattr *nla,
|
||||||
if (!nest_parms)
|
if (!nest_parms)
|
||||||
goto nla_put_failure;
|
goto nla_put_failure;
|
||||||
NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state);
|
NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_STATE, ct->proto.dccp.state);
|
||||||
|
NLA_PUT_U8(skb, CTA_PROTOINFO_DCCP_ROLE,
|
||||||
|
ct->proto.dccp.role[IP_CT_DIR_ORIGINAL]);
|
||||||
nla_nest_end(skb, nest_parms);
|
nla_nest_end(skb, nest_parms);
|
||||||
read_unlock_bh(&dccp_lock);
|
read_unlock_bh(&dccp_lock);
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -644,6 +646,7 @@ nla_put_failure:
|
||||||
|
|
||||||
static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
|
static const struct nla_policy dccp_nla_policy[CTA_PROTOINFO_DCCP_MAX + 1] = {
|
||||||
[CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 },
|
[CTA_PROTOINFO_DCCP_STATE] = { .type = NLA_U8 },
|
||||||
|
[CTA_PROTOINFO_DCCP_ROLE] = { .type = NLA_U8 },
|
||||||
};
|
};
|
||||||
|
|
||||||
static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
|
static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
|
||||||
|
@ -661,11 +664,21 @@ static int nlattr_to_dccp(struct nlattr *cda[], struct nf_conn *ct)
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
|
if (!tb[CTA_PROTOINFO_DCCP_STATE] ||
|
||||||
nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE)
|
!tb[CTA_PROTOINFO_DCCP_ROLE] ||
|
||||||
|
nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) > CT_DCCP_ROLE_MAX ||
|
||||||
|
nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]) >= CT_DCCP_IGNORE) {
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
write_lock_bh(&dccp_lock);
|
write_lock_bh(&dccp_lock);
|
||||||
ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
|
ct->proto.dccp.state = nla_get_u8(tb[CTA_PROTOINFO_DCCP_STATE]);
|
||||||
|
if (nla_get_u8(tb[CTA_PROTOINFO_DCCP_ROLE]) == CT_DCCP_ROLE_CLIENT) {
|
||||||
|
ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_CLIENT;
|
||||||
|
ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_SERVER;
|
||||||
|
} else {
|
||||||
|
ct->proto.dccp.role[IP_CT_DIR_ORIGINAL] = CT_DCCP_ROLE_SERVER;
|
||||||
|
ct->proto.dccp.role[IP_CT_DIR_REPLY] = CT_DCCP_ROLE_CLIENT;
|
||||||
|
}
|
||||||
write_unlock_bh(&dccp_lock);
|
write_unlock_bh(&dccp_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -777,6 +790,7 @@ static struct nf_conntrack_l4proto dccp_proto6 __read_mostly = {
|
||||||
.print_conntrack = dccp_print_conntrack,
|
.print_conntrack = dccp_print_conntrack,
|
||||||
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
|
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
|
||||||
.to_nlattr = dccp_to_nlattr,
|
.to_nlattr = dccp_to_nlattr,
|
||||||
|
.nlattr_size = dccp_nlattr_size,
|
||||||
.from_nlattr = nlattr_to_dccp,
|
.from_nlattr = nlattr_to_dccp,
|
||||||
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
|
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
|
||||||
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
|
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
|
||||||
|
|
|
@ -204,6 +204,7 @@ static struct nf_conntrack_l4proto nf_conntrack_l4proto_udplite6 __read_mostly =
|
||||||
.error = udplite_error,
|
.error = udplite_error,
|
||||||
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
|
#if defined(CONFIG_NF_CT_NETLINK) || defined(CONFIG_NF_CT_NETLINK_MODULE)
|
||||||
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
|
.tuple_to_nlattr = nf_ct_port_tuple_to_nlattr,
|
||||||
|
.nlattr_tuple_size = nf_ct_port_nlattr_tuple_size,
|
||||||
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
|
.nlattr_to_tuple = nf_ct_port_nlattr_to_tuple,
|
||||||
.nla_policy = nf_ct_port_nla_policy,
|
.nla_policy = nf_ct_port_nla_policy,
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -625,20 +625,6 @@ void xt_free_table_info(struct xt_table_info *info)
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL(xt_free_table_info);
|
EXPORT_SYMBOL(xt_free_table_info);
|
||||||
|
|
||||||
void xt_table_entry_swap_rcu(struct xt_table_info *oldinfo,
|
|
||||||
struct xt_table_info *newinfo)
|
|
||||||
{
|
|
||||||
unsigned int cpu;
|
|
||||||
|
|
||||||
for_each_possible_cpu(cpu) {
|
|
||||||
void *p = oldinfo->entries[cpu];
|
|
||||||
rcu_assign_pointer(oldinfo->entries[cpu], newinfo->entries[cpu]);
|
|
||||||
newinfo->entries[cpu] = p;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
EXPORT_SYMBOL_GPL(xt_table_entry_swap_rcu);
|
|
||||||
|
|
||||||
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
|
/* Find table by name, grabs mutex & ref. Returns ERR_PTR() on error. */
|
||||||
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
|
struct xt_table *xt_find_table_lock(struct net *net, u_int8_t af,
|
||||||
const char *name)
|
const char *name)
|
||||||
|
@ -676,32 +662,43 @@ void xt_compat_unlock(u_int8_t af)
|
||||||
EXPORT_SYMBOL_GPL(xt_compat_unlock);
|
EXPORT_SYMBOL_GPL(xt_compat_unlock);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
DEFINE_PER_CPU(struct xt_info_lock, xt_info_locks);
|
||||||
|
EXPORT_PER_CPU_SYMBOL_GPL(xt_info_locks);
|
||||||
|
|
||||||
|
|
||||||
struct xt_table_info *
|
struct xt_table_info *
|
||||||
xt_replace_table(struct xt_table *table,
|
xt_replace_table(struct xt_table *table,
|
||||||
unsigned int num_counters,
|
unsigned int num_counters,
|
||||||
struct xt_table_info *newinfo,
|
struct xt_table_info *newinfo,
|
||||||
int *error)
|
int *error)
|
||||||
{
|
{
|
||||||
struct xt_table_info *oldinfo, *private;
|
struct xt_table_info *private;
|
||||||
|
|
||||||
/* Do the substitution. */
|
/* Do the substitution. */
|
||||||
mutex_lock(&table->lock);
|
local_bh_disable();
|
||||||
private = table->private;
|
private = table->private;
|
||||||
|
|
||||||
/* Check inside lock: is the old number correct? */
|
/* Check inside lock: is the old number correct? */
|
||||||
if (num_counters != private->number) {
|
if (num_counters != private->number) {
|
||||||
duprintf("num_counters != table->private->number (%u/%u)\n",
|
duprintf("num_counters != table->private->number (%u/%u)\n",
|
||||||
num_counters, private->number);
|
num_counters, private->number);
|
||||||
mutex_unlock(&table->lock);
|
local_bh_enable();
|
||||||
*error = -EAGAIN;
|
*error = -EAGAIN;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
oldinfo = private;
|
|
||||||
rcu_assign_pointer(table->private, newinfo);
|
|
||||||
newinfo->initial_entries = oldinfo->initial_entries;
|
|
||||||
mutex_unlock(&table->lock);
|
|
||||||
|
|
||||||
synchronize_net();
|
table->private = newinfo;
|
||||||
return oldinfo;
|
newinfo->initial_entries = private->initial_entries;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Even though table entries have now been swapped, other CPU's
|
||||||
|
* may still be using the old entries. This is okay, because
|
||||||
|
* resynchronization happens because of the locking done
|
||||||
|
* during the get_counters() routine.
|
||||||
|
*/
|
||||||
|
local_bh_enable();
|
||||||
|
|
||||||
|
return private;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xt_replace_table);
|
EXPORT_SYMBOL_GPL(xt_replace_table);
|
||||||
|
|
||||||
|
@ -734,7 +731,6 @@ struct xt_table *xt_register_table(struct net *net, struct xt_table *table,
|
||||||
|
|
||||||
/* Simplifies replace_table code. */
|
/* Simplifies replace_table code. */
|
||||||
table->private = bootstrap;
|
table->private = bootstrap;
|
||||||
mutex_init(&table->lock);
|
|
||||||
|
|
||||||
if (!xt_replace_table(table, 0, newinfo, &ret))
|
if (!xt_replace_table(table, 0, newinfo, &ret))
|
||||||
goto unlock;
|
goto unlock;
|
||||||
|
@ -1147,7 +1143,14 @@ static struct pernet_operations xt_net_ops = {
|
||||||
|
|
||||||
static int __init xt_init(void)
|
static int __init xt_init(void)
|
||||||
{
|
{
|
||||||
int i, rv;
|
unsigned int i;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
for_each_possible_cpu(i) {
|
||||||
|
struct xt_info_lock *lock = &per_cpu(xt_info_locks, i);
|
||||||
|
spin_lock_init(&lock->lock);
|
||||||
|
lock->readers = 0;
|
||||||
|
}
|
||||||
|
|
||||||
xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
|
xt = kmalloc(sizeof(struct xt_af) * NFPROTO_NUMPROTO, GFP_KERNEL);
|
||||||
if (!xt)
|
if (!xt)
|
||||||
|
|
|
@ -474,7 +474,7 @@ static ssize_t recent_old_proc_write(struct file *file,
|
||||||
struct recent_table *t = pde->data;
|
struct recent_table *t = pde->data;
|
||||||
struct recent_entry *e;
|
struct recent_entry *e;
|
||||||
char buf[sizeof("+255.255.255.255")], *c = buf;
|
char buf[sizeof("+255.255.255.255")], *c = buf;
|
||||||
__be32 addr;
|
union nf_inet_addr addr = {};
|
||||||
int add;
|
int add;
|
||||||
|
|
||||||
if (size > sizeof(buf))
|
if (size > sizeof(buf))
|
||||||
|
@ -506,14 +506,13 @@ static ssize_t recent_old_proc_write(struct file *file,
|
||||||
add = 1;
|
add = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
addr = in_aton(c);
|
addr.ip = in_aton(c);
|
||||||
|
|
||||||
spin_lock_bh(&recent_lock);
|
spin_lock_bh(&recent_lock);
|
||||||
e = recent_entry_lookup(t, (const void *)&addr, NFPROTO_IPV4, 0);
|
e = recent_entry_lookup(t, &addr, NFPROTO_IPV4, 0);
|
||||||
if (e == NULL) {
|
if (e == NULL) {
|
||||||
if (add)
|
if (add)
|
||||||
recent_entry_init(t, (const void *)&addr,
|
recent_entry_init(t, &addr, NFPROTO_IPV4, 0);
|
||||||
NFPROTO_IPV4, 0);
|
|
||||||
} else {
|
} else {
|
||||||
if (add)
|
if (add)
|
||||||
recent_entry_update(t, e);
|
recent_entry_update(t, e);
|
||||||
|
|
|
@ -794,7 +794,7 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
|
||||||
{
|
{
|
||||||
static xfrm_address_t saddr_wildcard = { };
|
static xfrm_address_t saddr_wildcard = { };
|
||||||
struct net *net = xp_net(pol);
|
struct net *net = xp_net(pol);
|
||||||
unsigned int h;
|
unsigned int h, h_wildcard;
|
||||||
struct hlist_node *entry;
|
struct hlist_node *entry;
|
||||||
struct xfrm_state *x, *x0, *to_put;
|
struct xfrm_state *x, *x0, *to_put;
|
||||||
int acquire_in_progress = 0;
|
int acquire_in_progress = 0;
|
||||||
|
@ -819,8 +819,8 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
|
||||||
if (best)
|
if (best)
|
||||||
goto found;
|
goto found;
|
||||||
|
|
||||||
h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
|
h_wildcard = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
|
||||||
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
|
hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h_wildcard, bydst) {
|
||||||
if (x->props.family == family &&
|
if (x->props.family == family &&
|
||||||
x->props.reqid == tmpl->reqid &&
|
x->props.reqid == tmpl->reqid &&
|
||||||
!(x->props.flags & XFRM_STATE_WILDRECV) &&
|
!(x->props.flags & XFRM_STATE_WILDRECV) &&
|
||||||
|
|
Загрузка…
Ссылка в новой задаче