Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6

* master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6:
  [NETLINK]: Put {IFA,IFLA}_{RTA,PAYLOAD} macros back for userspace.
  [NET_SCHED] sch_htb: turn intermediate classes into leaves
  [NET_SCHED] sch_cbq: deactivating when grafting, purging etc.
  [XFRM]: Fix XFRMGRP_REPORT to use correct multicast group.
  [NET]: Force a cache line split in hh_cache in SMP.
  [NETPOLL]: make arp replies through netpoll use mac address of sender
  [NETLINK]: Restore API compatibility of address and neighbour bits
  [AX.25]: Fix default address and broadcast address initialization.
  [AX.25]: Constify ax25 utility functions
  [BNX2]: Add an error check.
  [NET]: Convert hh_lock to seqlock.
This commit is contained in:
Linus Torvalds 2006-12-09 09:38:59 -08:00
commit 99b48cff40
23 changed files with 183 additions and 125 deletions

View file

@ -2510,7 +2510,7 @@ bnx2_init_cpus(struct bnx2 *bp)
if (CHIP_NUM(bp) == CHIP_NUM_5709) { if (CHIP_NUM(bp) == CHIP_NUM_5709) {
fw = &bnx2_cp_fw_09; fw = &bnx2_cp_fw_09;
load_cpu_fw(bp, &cpu_reg, fw); rc = load_cpu_fw(bp, &cpu_reg, fw);
if (rc) if (rc)
goto init_cpu_err; goto init_cpu_err;
} }

View file

@ -325,11 +325,6 @@ static int sp_rebuild_header(struct sk_buff *skb)
static void sp_setup(struct net_device *dev) static void sp_setup(struct net_device *dev)
{ {
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
static char ax25_test[AX25_ADDR_LEN] =
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
/* Finish setting up the DEVICE info. */ /* Finish setting up the DEVICE info. */
dev->mtu = SIXP_MTU; dev->mtu = SIXP_MTU;
dev->hard_start_xmit = sp_xmit; dev->hard_start_xmit = sp_xmit;
@ -347,8 +342,8 @@ static void sp_setup(struct net_device *dev)
dev->tx_timeout = NULL; dev->tx_timeout = NULL;
/* Only activated in AX.25 mode */ /* Only activated in AX.25 mode */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);

View file

@ -1141,12 +1141,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
*/ */
static void baycom_probe(struct net_device *dev) static void baycom_probe(struct net_device *dev)
{ {
static char ax25_bcast[AX25_ADDR_LEN] = {
'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1
};
static char ax25_nocall[AX25_ADDR_LEN] = {
'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1
};
const struct hdlcdrv_channel_params dflt_ch_params = { const struct hdlcdrv_channel_params dflt_ch_params = {
20, 2, 10, 40, 0 20, 2, 10, 40, 0
}; };
@ -1182,8 +1176,8 @@ static void baycom_probe(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_nocall, AX25_ADDR_LEN);
dev->tx_queue_len = 16; dev->tx_queue_len = 16;
/* New style flags */ /* New style flags */

View file

@ -88,11 +88,6 @@
static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n"; static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
static unsigned char ax25_bcast[AX25_ADDR_LEN] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
static unsigned char ax25_defaddr[AX25_ADDR_LEN] =
{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
static char bpq_eth_addr[6]; static char bpq_eth_addr[6];
@ -487,8 +482,8 @@ static void bpq_setup(struct net_device *dev)
dev->do_ioctl = bpq_ioctl; dev->do_ioctl = bpq_ioctl;
dev->destructor = free_netdev; dev->destructor = free_netdev;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = 0; dev->flags = 0;

View file

@ -264,12 +264,6 @@ static int io[MAX_NUM_DEVS] __initdata = { 0, };
/* Beware! hw[] is also used in cleanup_module(). */ /* Beware! hw[] is also used in cleanup_module(). */
static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
static char ax25_broadcast[7] __initdata =
{ 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1,
'0' << 1 };
static char ax25_test[7] __initdata =
{ 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1,
'1' << 1 };
/* Global variables */ /* Global variables */
@ -443,8 +437,8 @@ static void __init dev_setup(struct net_device *dev)
dev->mtu = 1500; dev->mtu = 1500;
dev->addr_len = AX25_ADDR_LEN; dev->addr_len = AX25_ADDR_LEN;
dev->tx_queue_len = 64; dev->tx_queue_len = 64;
memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
} }
static int __init setup_adapter(int card_base, int type, int n) static int __init setup_adapter(int card_base, int type, int n)

View file

@ -63,18 +63,6 @@
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
/*
* The name of the card. Is used for messages and in the requests for
* io regions, irqs and dma channels
*/
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
static char ax25_nocall[AX25_ADDR_LEN] =
{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
/* --------------------------------------------------------------------- */
#define KISS_VERBOSE #define KISS_VERBOSE
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -709,8 +697,8 @@ static void hdlcdrv_setup(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->tx_queue_len = 16; dev->tx_queue_len = 16;
} }

View file

@ -672,11 +672,6 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev)
static void ax_setup(struct net_device *dev) static void ax_setup(struct net_device *dev)
{ {
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
static char ax25_test[AX25_ADDR_LEN] =
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
/* Finish setting up the DEVICE info. */ /* Finish setting up the DEVICE info. */
dev->mtu = AX_MTU; dev->mtu = AX_MTU;
dev->hard_start_xmit = ax_xmit; dev->hard_start_xmit = ax_xmit;
@ -691,8 +686,8 @@ static void ax_setup(struct net_device *dev)
dev->hard_header = ax_header; dev->hard_header = ax_header;
dev->rebuild_header = ax_rebuild_header; dev->rebuild_header = ax_rebuild_header;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = IFF_BROADCAST | IFF_MULTICAST; dev->flags = IFF_BROADCAST | IFF_MULTICAST;
} }

View file

@ -1540,11 +1540,6 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc)
/* * Network driver methods * */ /* * Network driver methods * */
/* ******************************************************************** */ /* ******************************************************************** */
static unsigned char ax25_bcast[AX25_ADDR_LEN] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
static unsigned char ax25_nocall[AX25_ADDR_LEN] =
{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
/* ----> Initialize device <----- */ /* ----> Initialize device <----- */
static void scc_net_setup(struct net_device *dev) static void scc_net_setup(struct net_device *dev)
@ -1562,8 +1557,8 @@ static void scc_net_setup(struct net_device *dev)
dev->do_ioctl = scc_net_ioctl; dev->do_ioctl = scc_net_ioctl;
dev->tx_timeout = NULL; dev->tx_timeout = NULL;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = 0; dev->flags = 0;

View file

@ -156,11 +156,6 @@ static struct net_device *yam_devs[NR_PORTS];
static struct yam_mcs *yam_data; static struct yam_mcs *yam_data;
static char ax25_bcast[7] =
{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
static char ax25_test[7] =
{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
static DEFINE_TIMER(yam_timer, NULL, 0, 0); static DEFINE_TIMER(yam_timer, NULL, 0, 0);
/* --------------------------------------------------------------------- */ /* --------------------------------------------------------------------- */
@ -1115,8 +1110,8 @@ static void yam_setup(struct net_device *dev)
dev->hard_header_len = AX25_MAX_HEADER_LEN; dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->mtu = AX25_MTU; dev->mtu = AX25_MTU;
dev->addr_len = AX25_ADDR_LEN; dev->addr_len = AX25_ADDR_LEN;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
} }
static int __init yam_init_driver(void) static int __init yam_init_driver(void)

View file

@ -52,4 +52,10 @@ struct ifa_cacheinfo
__u32 tstamp; /* updated timestamp, hundredths of seconds */ __u32 tstamp; /* updated timestamp, hundredths of seconds */
}; };
/* backwards compatibility for userspace */
#ifndef __KERNEL__
#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
#endif
#endif #endif

View file

@ -82,6 +82,12 @@ enum
#define IFLA_MAX (__IFLA_MAX - 1) #define IFLA_MAX (__IFLA_MAX - 1)
/* backwards compatibility for userspace */
#ifndef __KERNEL__
#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
#endif
/* ifi_flags. /* ifi_flags.
IFF_* flags. IFF_* flags.

View file

@ -193,13 +193,20 @@ struct hh_cache
{ {
struct hh_cache *hh_next; /* Next entry */ struct hh_cache *hh_next; /* Next entry */
atomic_t hh_refcnt; /* number of users */ atomic_t hh_refcnt; /* number of users */
__be16 hh_type; /* protocol identifier, f.e ETH_P_IP /*
* We want hh_output, hh_len, hh_lock and hh_data be a in a separate
* cache line on SMP.
* They are mostly read, but hh_refcnt may be changed quite frequently,
* incurring cache line ping pongs.
*/
__be16 hh_type ____cacheline_aligned_in_smp;
/* protocol identifier, f.e ETH_P_IP
* NOTE: For VLANs, this will be the * NOTE: For VLANs, this will be the
* encapuslated type. --BLG * encapuslated type. --BLG
*/ */
u16 hh_len; /* length of header */ u16 hh_len; /* length of header */
int (*hh_output)(struct sk_buff *skb); int (*hh_output)(struct sk_buff *skb);
rwlock_t hh_lock; seqlock_t hh_lock;
/* cached hardware header; allow for machine alignment needs. */ /* cached hardware header; allow for machine alignment needs. */
#define HH_DATA_MOD 16 #define HH_DATA_MOD 16

View file

@ -3,6 +3,8 @@
#include <linux/netlink.h> #include <linux/netlink.h>
#include <linux/if_link.h> #include <linux/if_link.h>
#include <linux/if_addr.h>
#include <linux/neighbour.h>
/**** /****
* Routing/neighbour discovery messages. * Routing/neighbour discovery messages.

View file

@ -357,7 +357,7 @@ struct xfrm_user_report {
#define XFRMGRP_EXPIRE 2 #define XFRMGRP_EXPIRE 2
#define XFRMGRP_SA 4 #define XFRMGRP_SA 4
#define XFRMGRP_POLICY 8 #define XFRMGRP_POLICY 8
#define XFRMGRP_REPORT 0x10 #define XFRMGRP_REPORT 0x20
#endif #endif
enum xfrm_nlgroups { enum xfrm_nlgroups {

View file

@ -282,15 +282,17 @@ extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
/* ax25_addr.c */ /* ax25_addr.c */
extern ax25_address null_ax25_address; extern const ax25_address ax25_bcast;
extern char *ax2asc(char *buf, ax25_address *); extern const ax25_address ax25_defaddr;
extern void asc2ax(ax25_address *addr, char *callsign); extern const ax25_address null_ax25_address;
extern int ax25cmp(ax25_address *, ax25_address *); extern int ax25cmp(const ax25_address *, const ax25_address *);
extern int ax25digicmp(ax25_digi *, ax25_digi *); extern int ax25digicmp(const ax25_digi *, const ax25_digi *);
extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *); extern const unsigned char *ax25_addr_parse(const unsigned char *, int,
extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int); ax25_address *, ax25_address *, ax25_digi *, int *, int *);
extern int ax25_addr_size(ax25_digi *); extern int ax25_addr_build(unsigned char *, const ax25_address *,
extern void ax25_digi_invert(ax25_digi *, ax25_digi *); const ax25_address *, const ax25_digi *, int, int);
extern int ax25_addr_size(const ax25_digi *);
extern void ax25_digi_invert(const ax25_digi *, ax25_digi *);
/* ax25_dev.c */ /* ax25_dev.c */
extern ax25_dev *ax25_dev_list; extern ax25_dev *ax25_dev_list;

View file

@ -309,6 +309,24 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
return 0; return 0;
} }
static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
{
unsigned seq;
int hh_len;
do {
int hh_alen;
seq = read_seqbegin(&hh->hh_lock);
hh_len = hh->hh_len;
hh_alen = HH_DATA_ALIGN(hh_len);
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
} while (read_seqretry(&hh->hh_lock, seq));
skb_push(skb, hh_len);
return hh->hh_output(skb);
}
static inline struct neighbour * static inline struct neighbour *
__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) __neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
{ {

View file

@ -29,17 +29,26 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
/* /*
* The null address is defined as a callsign of all spaces with an * The default broadcast address of an interface is QST-0; the default address
* SSID of zero. * is LINUX-1. The null address is defined as a callsign of all spaces with
* an SSID of zero.
*/ */
ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
const ax25_address ax25_bcast =
{{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
const ax25_address ax25_defaddr =
{{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}};
const ax25_address null_ax25_address =
{{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
EXPORT_SYMBOL_GPL(ax25_bcast);
EXPORT_SYMBOL_GPL(ax25_defaddr);
EXPORT_SYMBOL(null_ax25_address); EXPORT_SYMBOL(null_ax25_address);
/* /*
* ax25 -> ascii conversion * ax25 -> ascii conversion
*/ */
char *ax2asc(char *buf, ax25_address *a) char *ax2asc(char *buf, const ax25_address *a)
{ {
char c, *s; char c, *s;
int n; int n;
@ -72,7 +81,7 @@ EXPORT_SYMBOL(ax2asc);
/* /*
* ascii -> ax25 conversion * ascii -> ax25 conversion
*/ */
void asc2ax(ax25_address *addr, char *callsign) void asc2ax(ax25_address *addr, const char *callsign)
{ {
char *s; char *s;
int n; int n;
@ -107,7 +116,7 @@ EXPORT_SYMBOL(asc2ax);
/* /*
* Compare two ax.25 addresses * Compare two ax.25 addresses
*/ */
int ax25cmp(ax25_address *a, ax25_address *b) int ax25cmp(const ax25_address *a, const ax25_address *b)
{ {
int ct = 0; int ct = 0;
@ -128,7 +137,7 @@ EXPORT_SYMBOL(ax25cmp);
/* /*
* Compare two AX.25 digipeater paths. * Compare two AX.25 digipeater paths.
*/ */
int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2)
{ {
int i; int i;
@ -149,7 +158,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
* Given an AX.25 address pull of to, from, digi list, command/response and the start of data * Given an AX.25 address pull of to, from, digi list, command/response and the start of data
* *
*/ */
unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) const unsigned char *ax25_addr_parse(const unsigned char *buf, int len,
ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags,
int *dama)
{ {
int d = 0; int d = 0;
@ -204,7 +215,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
/* /*
* Assemble an AX.25 header from the bits * Assemble an AX.25 header from the bits
*/ */
int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) int ax25_addr_build(unsigned char *buf, const ax25_address *src,
const ax25_address *dest, const ax25_digi *d, int flag, int modulus)
{ {
int len = 0; int len = 0;
int ct = 0; int ct = 0;
@ -261,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
return len; return len;
} }
int ax25_addr_size(ax25_digi *dp) int ax25_addr_size(const ax25_digi *dp)
{ {
if (dp == NULL) if (dp == NULL)
return 2 * AX25_ADDR_LEN; return 2 * AX25_ADDR_LEN;
@ -272,7 +284,7 @@ int ax25_addr_size(ax25_digi *dp)
/* /*
* Reverse Digipeat List. May not pass both parameters as same struct * Reverse Digipeat List. May not pass both parameters as same struct
*/ */
void ax25_digi_invert(ax25_digi *in, ax25_digi *out) void ax25_digi_invert(const ax25_digi *in, ax25_digi *out)
{ {
int ct; int ct;

View file

@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh)
while ((hh = neigh->hh) != NULL) { while ((hh = neigh->hh) != NULL) {
neigh->hh = hh->hh_next; neigh->hh = hh->hh_next;
hh->hh_next = NULL; hh->hh_next = NULL;
write_lock_bh(&hh->hh_lock);
write_seqlock_bh(&hh->hh_lock);
hh->hh_output = neigh_blackhole; hh->hh_output = neigh_blackhole;
write_unlock_bh(&hh->hh_lock); write_sequnlock_bh(&hh->hh_lock);
if (atomic_dec_and_test(&hh->hh_refcnt)) if (atomic_dec_and_test(&hh->hh_refcnt))
kfree(hh); kfree(hh);
} }
@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh)
if (update) { if (update) {
for (hh = neigh->hh; hh; hh = hh->hh_next) { for (hh = neigh->hh; hh; hh = hh->hh_next) {
write_lock_bh(&hh->hh_lock); write_seqlock_bh(&hh->hh_lock);
update(hh, neigh->dev, neigh->ha); update(hh, neigh->dev, neigh->ha);
write_unlock_bh(&hh->hh_lock); write_sequnlock_bh(&hh->hh_lock);
} }
} }
} }
@ -1089,7 +1090,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
break; break;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
rwlock_init(&hh->hh_lock); seqlock_init(&hh->hh_lock);
hh->hh_type = protocol; hh->hh_type = protocol;
atomic_set(&hh->hh_refcnt, 0); atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL; hh->hh_next = NULL;

View file

@ -330,6 +330,7 @@ static void arp_reply(struct sk_buff *skb)
unsigned char *arp_ptr; unsigned char *arp_ptr;
int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
__be32 sip, tip; __be32 sip, tip;
unsigned char *sha;
struct sk_buff *send_skb; struct sk_buff *send_skb;
struct netpoll *np = NULL; struct netpoll *np = NULL;
@ -356,9 +357,14 @@ static void arp_reply(struct sk_buff *skb)
arp->ar_op != htons(ARPOP_REQUEST)) arp->ar_op != htons(ARPOP_REQUEST))
return; return;
arp_ptr = (unsigned char *)(arp+1) + skb->dev->addr_len; arp_ptr = (unsigned char *)(arp+1);
/* save the location of the src hw addr */
sha = arp_ptr;
arp_ptr += skb->dev->addr_len;
memcpy(&sip, arp_ptr, 4); memcpy(&sip, arp_ptr, 4);
arp_ptr += 4 + skb->dev->addr_len; arp_ptr += 4;
/* if we actually cared about dst hw addr, it would get copied here */
arp_ptr += skb->dev->addr_len;
memcpy(&tip, arp_ptr, 4); memcpy(&tip, arp_ptr, 4);
/* Should we ignore arp? */ /* Should we ignore arp? */
@ -381,7 +387,7 @@ static void arp_reply(struct sk_buff *skb)
if (np->dev->hard_header && if (np->dev->hard_header &&
np->dev->hard_header(send_skb, skb->dev, ptype, np->dev->hard_header(send_skb, skb->dev, ptype,
np->remote_mac, np->local_mac, sha, np->local_mac,
send_skb->len) < 0) { send_skb->len) < 0) {
kfree_skb(send_skb); kfree_skb(send_skb);
return; return;
@ -405,7 +411,7 @@ static void arp_reply(struct sk_buff *skb)
arp_ptr += np->dev->addr_len; arp_ptr += np->dev->addr_len;
memcpy(arp_ptr, &tip, 4); memcpy(arp_ptr, &tip, 4);
arp_ptr += 4; arp_ptr += 4;
memcpy(arp_ptr, np->remote_mac, np->dev->addr_len); memcpy(arp_ptr, sha, np->dev->addr_len);
arp_ptr += np->dev->addr_len; arp_ptr += np->dev->addr_len;
memcpy(arp_ptr, &sip, 4); memcpy(arp_ptr, &sip, 4);

View file

@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
static inline int ip_finish_output2(struct sk_buff *skb) static inline int ip_finish_output2(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct hh_cache *hh = dst->hh;
struct net_device *dev = dst->dev; struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev); int hh_len = LL_RESERVED_SPACE(dev);
@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb)
skb = skb2; skb = skb2;
} }
if (hh) { if (dst->hh)
int hh_alen; return neigh_hh_output(dst->hh, skb);
else if (dst->neighbour)
read_lock_bh(&hh->hh_lock);
hh_alen = HH_DATA_ALIGN(hh->hh_len);
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
read_unlock_bh(&hh->hh_lock);
skb_push(skb, hh->hh_len);
return hh->hh_output(skb);
} else if (dst->neighbour)
return dst->neighbour->output(skb); return dst->neighbour->output(skb);
if (net_ratelimit()) if (net_ratelimit())

View file

@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
static inline int ip6_output_finish(struct sk_buff *skb) static inline int ip6_output_finish(struct sk_buff *skb)
{ {
struct dst_entry *dst = skb->dst; struct dst_entry *dst = skb->dst;
struct hh_cache *hh = dst->hh;
if (hh) { if (dst->hh)
int hh_alen; return neigh_hh_output(dst->hh, skb);
else if (dst->neighbour)
read_lock_bh(&hh->hh_lock);
hh_alen = HH_DATA_ALIGN(hh->hh_len);
memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
read_unlock_bh(&hh->hh_lock);
skb_push(skb, hh->hh_len);
return hh->hh_output(skb);
} else if (dst->neighbour)
return dst->neighbour->output(skb); return dst->neighbour->output(skb);
IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);

View file

@ -371,8 +371,6 @@ static void cbq_deactivate_class(struct cbq_class *this)
return; return;
} }
} }
cl = cl_prev->next_alive;
return; return;
} }
} while ((cl_prev = cl) != q->active[prio]); } while ((cl_prev = cl) != q->active[prio]);
@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch)
do { do {
if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) { if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
sch->q.qlen--; sch->q.qlen--;
if (!cl->q->q.qlen)
cbq_deactivate_class(cl);
return len; return len;
} }
} while ((cl = cl->next_alive) != cl_head); } while ((cl = cl->next_alive) != cl_head);
@ -1685,8 +1685,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
#endif #endif
} }
sch_tree_lock(sch); sch_tree_lock(sch);
*old = cl->q; *old = xchg(&cl->q, new);
cl->q = new;
qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old); qdisc_reset(*old);
sch_tree_unlock(sch); sch_tree_unlock(sch);
@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg)
return cl ? cl->q : NULL; return cl ? cl->q : NULL;
} }
static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
{
struct cbq_class *cl = (struct cbq_class *)arg;
if (cl->q->q.qlen == 0)
cbq_deactivate_class(cl);
}
static unsigned long cbq_get(struct Qdisc *sch, u32 classid) static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
{ {
struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_sched_data *q = qdisc_priv(sch);
@ -1988,12 +1995,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
{ {
struct cbq_sched_data *q = qdisc_priv(sch); struct cbq_sched_data *q = qdisc_priv(sch);
struct cbq_class *cl = (struct cbq_class*)arg; struct cbq_class *cl = (struct cbq_class*)arg;
unsigned int qlen;
if (cl->filters || cl->children || cl == &q->link) if (cl->filters || cl->children || cl == &q->link)
return -EBUSY; return -EBUSY;
sch_tree_lock(sch); sch_tree_lock(sch);
qlen = cl->q->q.qlen;
qdisc_reset(cl->q);
qdisc_tree_decrease_qlen(cl->q, qlen);
if (cl->next_alive) if (cl->next_alive)
cbq_deactivate_class(cl); cbq_deactivate_class(cl);
@ -2084,6 +2096,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
static struct Qdisc_class_ops cbq_class_ops = { static struct Qdisc_class_ops cbq_class_ops = {
.graft = cbq_graft, .graft = cbq_graft,
.leaf = cbq_leaf, .leaf = cbq_leaf,
.qlen_notify = cbq_qlen_notify,
.get = cbq_get, .get = cbq_get,
.put = cbq_put, .put = cbq_put,
.change = cbq_change_class, .change = cbq_change_class,

View file

@ -147,6 +147,10 @@ struct htb_class {
psched_tdiff_t mbuffer; /* max wait time */ psched_tdiff_t mbuffer; /* max wait time */
long tokens, ctokens; /* current number of tokens */ long tokens, ctokens; /* current number of tokens */
psched_time_t t_c; /* checkpoint time */ psched_time_t t_c; /* checkpoint time */
int prio; /* For parent to leaf return possible here */
int quantum; /* we do backup. Finally full replacement */
/* of un.leaf originals should be done. */
}; };
/* TODO: maybe compute rate when size is too large .. or drop ? */ /* TODO: maybe compute rate when size is too large .. or drop ? */
@ -1271,6 +1275,38 @@ static void htb_destroy_filters(struct tcf_proto **fl)
} }
} }
static inline int htb_parent_last_child(struct htb_class *cl)
{
if (!cl->parent)
/* the root class */
return 0;
if (!(cl->parent->children.next == &cl->sibling &&
cl->parent->children.prev == &cl->sibling))
/* not the last child */
return 0;
return 1;
}
static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q)
{
struct htb_class *parent = cl->parent;
BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity);
parent->level = 0;
memset(&parent->un.inner, 0, sizeof(parent->un.inner));
INIT_LIST_HEAD(&parent->un.leaf.drop_list);
parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
parent->un.leaf.quantum = parent->quantum;
parent->un.leaf.prio = parent->prio;
parent->tokens = parent->buffer;
parent->ctokens = parent->cbuffer;
PSCHED_GET_TIME(parent->t_c);
parent->cmode = HTB_CAN_SEND;
}
static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
{ {
struct htb_sched *q = qdisc_priv(sch); struct htb_sched *q = qdisc_priv(sch);
@ -1328,6 +1364,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
struct htb_sched *q = qdisc_priv(sch); struct htb_sched *q = qdisc_priv(sch);
struct htb_class *cl = (struct htb_class *)arg; struct htb_class *cl = (struct htb_class *)arg;
unsigned int qlen; unsigned int qlen;
struct Qdisc *new_q = NULL;
int last_child = 0;
// TODO: why don't allow to delete subtree ? references ? does // TODO: why don't allow to delete subtree ? references ? does
// tc subsys quarantee us that in htb_destroy it holds no class // tc subsys quarantee us that in htb_destroy it holds no class
@ -1335,6 +1373,12 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (!list_empty(&cl->children) || cl->filter_cnt) if (!list_empty(&cl->children) || cl->filter_cnt)
return -EBUSY; return -EBUSY;
if (!cl->level && htb_parent_last_child(cl)) {
new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
cl->parent->classid);
last_child = 1;
}
sch_tree_lock(sch); sch_tree_lock(sch);
/* delete from hash and active; remainder in destroy_class */ /* delete from hash and active; remainder in destroy_class */
@ -1349,6 +1393,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
if (cl->prio_activity) if (cl->prio_activity)
htb_deactivate(q, cl); htb_deactivate(q, cl);
if (last_child)
htb_parent_to_leaf(cl, new_q);
if (--cl->refcnt == 0) if (--cl->refcnt == 0)
htb_destroy_class(sch, cl); htb_destroy_class(sch, cl);
@ -1483,6 +1530,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
cl->un.leaf.quantum = hopt->quantum; cl->un.leaf.quantum = hopt->quantum;
if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO) if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
cl->un.leaf.prio = TC_HTB_NUMPRIO - 1; cl->un.leaf.prio = TC_HTB_NUMPRIO - 1;
/* backup for htb_parent_to_leaf */
cl->quantum = cl->un.leaf.quantum;
cl->prio = cl->un.leaf.prio;
} }
cl->buffer = hopt->buffer; cl->buffer = hopt->buffer;