aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@woody.osdl.org>2006-12-09 12:38:59 -0500
committerLinus Torvalds <torvalds@woody.osdl.org>2006-12-09 12:38:59 -0500
commit99b48cff405333afe26ac603b37639c410a48e5d (patch)
tree31b427930317b1596ca6070585f66a108b722580
parent200d018eff4be3a1fb9823441cfcebb7de86a677 (diff)
parentd3dcc077bf88806201093f86325ec656e4dbfbce (diff)
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.
-rw-r--r--drivers/net/bnx2.c2
-rw-r--r--drivers/net/hamradio/6pack.c9
-rw-r--r--drivers/net/hamradio/baycom_epp.c10
-rw-r--r--drivers/net/hamradio/bpqether.c9
-rw-r--r--drivers/net/hamradio/dmascc.c10
-rw-r--r--drivers/net/hamradio/hdlcdrv.c16
-rw-r--r--drivers/net/hamradio/mkiss.c9
-rw-r--r--drivers/net/hamradio/scc.c9
-rw-r--r--drivers/net/hamradio/yam.c9
-rw-r--r--include/linux/if_addr.h6
-rw-r--r--include/linux/if_link.h6
-rw-r--r--include/linux/netdevice.h11
-rw-r--r--include/linux/rtnetlink.h2
-rw-r--r--include/linux/xfrm.h2
-rw-r--r--include/net/ax25.h20
-rw-r--r--include/net/neighbour.h18
-rw-r--r--net/ax25/ax25_addr.c34
-rw-r--r--net/core/neighbour.c11
-rw-r--r--net/core/netpoll.c14
-rw-r--r--net/ipv4/ip_output.c14
-rw-r--r--net/ipv6/ip6_output.c17
-rw-r--r--net/sched/sch_cbq.c21
-rw-r--r--net/sched/sch_htb.c51
23 files changed, 184 insertions, 126 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c
index 5bacb7587df4..7d824cf8ee2d 100644
--- a/drivers/net/bnx2.c
+++ b/drivers/net/bnx2.c
@@ -2510,7 +2510,7 @@ bnx2_init_cpus(struct bnx2 *bp)
2510 if (CHIP_NUM(bp) == CHIP_NUM_5709) { 2510 if (CHIP_NUM(bp) == CHIP_NUM_5709) {
2511 fw = &bnx2_cp_fw_09; 2511 fw = &bnx2_cp_fw_09;
2512 2512
2513 load_cpu_fw(bp, &cpu_reg, fw); 2513 rc = load_cpu_fw(bp, &cpu_reg, fw);
2514 if (rc) 2514 if (rc)
2515 goto init_cpu_err; 2515 goto init_cpu_err;
2516 } 2516 }
diff --git a/drivers/net/hamradio/6pack.c b/drivers/net/hamradio/6pack.c
index 92420f007b97..760d04a671f9 100644
--- a/drivers/net/hamradio/6pack.c
+++ b/drivers/net/hamradio/6pack.c
@@ -325,11 +325,6 @@ static int sp_rebuild_header(struct sk_buff *skb)
325 325
326static void sp_setup(struct net_device *dev) 326static void sp_setup(struct net_device *dev)
327{ 327{
328 static char ax25_bcast[AX25_ADDR_LEN] =
329 {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
330 static char ax25_test[AX25_ADDR_LEN] =
331 {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
332
333 /* Finish setting up the DEVICE info. */ 328 /* Finish setting up the DEVICE info. */
334 dev->mtu = SIXP_MTU; 329 dev->mtu = SIXP_MTU;
335 dev->hard_start_xmit = sp_xmit; 330 dev->hard_start_xmit = sp_xmit;
@@ -347,8 +342,8 @@ static void sp_setup(struct net_device *dev)
347 dev->tx_timeout = NULL; 342 dev->tx_timeout = NULL;
348 343
349 /* Only activated in AX.25 mode */ 344 /* Only activated in AX.25 mode */
350 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 345 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
351 memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); 346 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
352 347
353 SET_MODULE_OWNER(dev); 348 SET_MODULE_OWNER(dev);
354 349
diff --git a/drivers/net/hamradio/baycom_epp.c b/drivers/net/hamradio/baycom_epp.c
index 3c33d6f6a6a6..8a83db0fb3b7 100644
--- a/drivers/net/hamradio/baycom_epp.c
+++ b/drivers/net/hamradio/baycom_epp.c
@@ -1141,12 +1141,6 @@ static int baycom_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
1141 */ 1141 */
1142static void baycom_probe(struct net_device *dev) 1142static void baycom_probe(struct net_device *dev)
1143{ 1143{
1144 static char ax25_bcast[AX25_ADDR_LEN] = {
1145 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1
1146 };
1147 static char ax25_nocall[AX25_ADDR_LEN] = {
1148 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1
1149 };
1150 const struct hdlcdrv_channel_params dflt_ch_params = { 1144 const struct hdlcdrv_channel_params dflt_ch_params = {
1151 20, 2, 10, 40, 0 1145 20, 2, 10, 40, 0
1152 }; 1146 };
@@ -1182,8 +1176,8 @@ static void baycom_probe(struct net_device *dev)
1182 dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; 1176 dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
1183 dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ 1177 dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
1184 dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ 1178 dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
1185 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 1179 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
1186 memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); 1180 memcpy(dev->dev_addr, &ax25_nocall, AX25_ADDR_LEN);
1187 dev->tx_queue_len = 16; 1181 dev->tx_queue_len = 16;
1188 1182
1189 /* New style flags */ 1183 /* New style flags */
diff --git a/drivers/net/hamradio/bpqether.c b/drivers/net/hamradio/bpqether.c
index 889f338132fa..5b788d84011f 100644
--- a/drivers/net/hamradio/bpqether.c
+++ b/drivers/net/hamradio/bpqether.c
@@ -88,11 +88,6 @@
88 88
89static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n"; 89static char banner[] __initdata = KERN_INFO "AX.25: bpqether driver version 004\n";
90 90
91static unsigned char ax25_bcast[AX25_ADDR_LEN] =
92 {'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
93static unsigned char ax25_defaddr[AX25_ADDR_LEN] =
94 {'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
95
96static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF}; 91static char bcast_addr[6]={0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
97 92
98static char bpq_eth_addr[6]; 93static char bpq_eth_addr[6];
@@ -487,8 +482,8 @@ static void bpq_setup(struct net_device *dev)
487 dev->do_ioctl = bpq_ioctl; 482 dev->do_ioctl = bpq_ioctl;
488 dev->destructor = free_netdev; 483 dev->destructor = free_netdev;
489 484
490 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 485 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
491 memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN); 486 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
492 487
493 dev->flags = 0; 488 dev->flags = 0;
494 489
diff --git a/drivers/net/hamradio/dmascc.c b/drivers/net/hamradio/dmascc.c
index e6e721aff6f6..0fbb414b5a4d 100644
--- a/drivers/net/hamradio/dmascc.c
+++ b/drivers/net/hamradio/dmascc.c
@@ -264,12 +264,6 @@ static int io[MAX_NUM_DEVS] __initdata = { 0, };
264 264
265/* Beware! hw[] is also used in cleanup_module(). */ 265/* Beware! hw[] is also used in cleanup_module(). */
266static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE; 266static struct scc_hardware hw[NUM_TYPES] __initdata_or_module = HARDWARE;
267static char ax25_broadcast[7] __initdata =
268 { 'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1,
269'0' << 1 };
270static char ax25_test[7] __initdata =
271 { 'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1,
272'1' << 1 };
273 267
274 268
275/* Global variables */ 269/* Global variables */
@@ -443,8 +437,8 @@ static void __init dev_setup(struct net_device *dev)
443 dev->mtu = 1500; 437 dev->mtu = 1500;
444 dev->addr_len = AX25_ADDR_LEN; 438 dev->addr_len = AX25_ADDR_LEN;
445 dev->tx_queue_len = 64; 439 dev->tx_queue_len = 64;
446 memcpy(dev->broadcast, ax25_broadcast, AX25_ADDR_LEN); 440 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
447 memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); 441 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
448} 442}
449 443
450static int __init setup_adapter(int card_base, int type, int n) 444static int __init setup_adapter(int card_base, int type, int n)
diff --git a/drivers/net/hamradio/hdlcdrv.c b/drivers/net/hamradio/hdlcdrv.c
index dacc7687b97f..452873e7c68f 100644
--- a/drivers/net/hamradio/hdlcdrv.c
+++ b/drivers/net/hamradio/hdlcdrv.c
@@ -63,18 +63,6 @@
63 63
64/* --------------------------------------------------------------------- */ 64/* --------------------------------------------------------------------- */
65 65
66/*
67 * The name of the card. Is used for messages and in the requests for
68 * io regions, irqs and dma channels
69 */
70
71static char ax25_bcast[AX25_ADDR_LEN] =
72{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
73static char ax25_nocall[AX25_ADDR_LEN] =
74{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
75
76/* --------------------------------------------------------------------- */
77
78#define KISS_VERBOSE 66#define KISS_VERBOSE
79 67
80/* --------------------------------------------------------------------- */ 68/* --------------------------------------------------------------------- */
@@ -709,8 +697,8 @@ static void hdlcdrv_setup(struct net_device *dev)
709 dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN; 697 dev->hard_header_len = AX25_MAX_HEADER_LEN + AX25_BPQ_HEADER_LEN;
710 dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */ 698 dev->mtu = AX25_DEF_PACLEN; /* eth_mtu is the default */
711 dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */ 699 dev->addr_len = AX25_ADDR_LEN; /* sizeof an ax.25 address */
712 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 700 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
713 memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); 701 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
714 dev->tx_queue_len = 16; 702 dev->tx_queue_len = 16;
715} 703}
716 704
diff --git a/drivers/net/hamradio/mkiss.c b/drivers/net/hamradio/mkiss.c
index d8715b200c17..d08fbc396648 100644
--- a/drivers/net/hamradio/mkiss.c
+++ b/drivers/net/hamradio/mkiss.c
@@ -672,11 +672,6 @@ static struct net_device_stats *ax_get_stats(struct net_device *dev)
672 672
673static void ax_setup(struct net_device *dev) 673static void ax_setup(struct net_device *dev)
674{ 674{
675 static char ax25_bcast[AX25_ADDR_LEN] =
676 {'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
677 static char ax25_test[AX25_ADDR_LEN] =
678 {'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
679
680 /* Finish setting up the DEVICE info. */ 675 /* Finish setting up the DEVICE info. */
681 dev->mtu = AX_MTU; 676 dev->mtu = AX_MTU;
682 dev->hard_start_xmit = ax_xmit; 677 dev->hard_start_xmit = ax_xmit;
@@ -691,8 +686,8 @@ static void ax_setup(struct net_device *dev)
691 dev->hard_header = ax_header; 686 dev->hard_header = ax_header;
692 dev->rebuild_header = ax_rebuild_header; 687 dev->rebuild_header = ax_rebuild_header;
693 688
694 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 689 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
695 memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); 690 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
696 691
697 dev->flags = IFF_BROADCAST | IFF_MULTICAST; 692 dev->flags = IFF_BROADCAST | IFF_MULTICAST;
698} 693}
diff --git a/drivers/net/hamradio/scc.c b/drivers/net/hamradio/scc.c
index ec9b6d9b6f05..2ce047e9d262 100644
--- a/drivers/net/hamradio/scc.c
+++ b/drivers/net/hamradio/scc.c
@@ -1540,11 +1540,6 @@ static int scc_net_alloc(const char *name, struct scc_channel *scc)
1540/* * Network driver methods * */ 1540/* * Network driver methods * */
1541/* ******************************************************************** */ 1541/* ******************************************************************** */
1542 1542
1543static unsigned char ax25_bcast[AX25_ADDR_LEN] =
1544{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
1545static unsigned char ax25_nocall[AX25_ADDR_LEN] =
1546{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
1547
1548/* ----> Initialize device <----- */ 1543/* ----> Initialize device <----- */
1549 1544
1550static void scc_net_setup(struct net_device *dev) 1545static void scc_net_setup(struct net_device *dev)
@@ -1562,8 +1557,8 @@ static void scc_net_setup(struct net_device *dev)
1562 dev->do_ioctl = scc_net_ioctl; 1557 dev->do_ioctl = scc_net_ioctl;
1563 dev->tx_timeout = NULL; 1558 dev->tx_timeout = NULL;
1564 1559
1565 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 1560 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
1566 memcpy(dev->dev_addr, ax25_nocall, AX25_ADDR_LEN); 1561 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
1567 1562
1568 dev->flags = 0; 1563 dev->flags = 0;
1569 1564
diff --git a/drivers/net/hamradio/yam.c b/drivers/net/hamradio/yam.c
index 3c4455bd466d..6d74f08720d5 100644
--- a/drivers/net/hamradio/yam.c
+++ b/drivers/net/hamradio/yam.c
@@ -156,11 +156,6 @@ static struct net_device *yam_devs[NR_PORTS];
156 156
157static struct yam_mcs *yam_data; 157static struct yam_mcs *yam_data;
158 158
159static char ax25_bcast[7] =
160{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, '0' << 1};
161static char ax25_test[7] =
162{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, '1' << 1};
163
164static DEFINE_TIMER(yam_timer, NULL, 0, 0); 159static DEFINE_TIMER(yam_timer, NULL, 0, 0);
165 160
166/* --------------------------------------------------------------------- */ 161/* --------------------------------------------------------------------- */
@@ -1115,8 +1110,8 @@ static void yam_setup(struct net_device *dev)
1115 dev->hard_header_len = AX25_MAX_HEADER_LEN; 1110 dev->hard_header_len = AX25_MAX_HEADER_LEN;
1116 dev->mtu = AX25_MTU; 1111 dev->mtu = AX25_MTU;
1117 dev->addr_len = AX25_ADDR_LEN; 1112 dev->addr_len = AX25_ADDR_LEN;
1118 memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); 1113 memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
1119 memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); 1114 memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
1120} 1115}
1121 1116
1122static int __init yam_init_driver(void) 1117static int __init yam_init_driver(void)
diff --git a/include/linux/if_addr.h b/include/linux/if_addr.h
index dbe8f6120a40..d557e4ce9b6b 100644
--- a/include/linux/if_addr.h
+++ b/include/linux/if_addr.h
@@ -52,4 +52,10 @@ struct ifa_cacheinfo
52 __u32 tstamp; /* updated timestamp, hundredths of seconds */ 52 __u32 tstamp; /* updated timestamp, hundredths of seconds */
53}; 53};
54 54
55/* backwards compatibility for userspace */
56#ifndef __KERNEL__
57#define IFA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifaddrmsg))))
58#define IFA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifaddrmsg))
59#endif
60
55#endif 61#endif
diff --git a/include/linux/if_link.h b/include/linux/if_link.h
index e963a077e6f5..35ed3b5467f3 100644
--- a/include/linux/if_link.h
+++ b/include/linux/if_link.h
@@ -82,6 +82,12 @@ enum
82 82
83#define IFLA_MAX (__IFLA_MAX - 1) 83#define IFLA_MAX (__IFLA_MAX - 1)
84 84
85/* backwards compatibility for userspace */
86#ifndef __KERNEL__
87#define IFLA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct ifinfomsg))))
88#define IFLA_PAYLOAD(n) NLMSG_PAYLOAD(n,sizeof(struct ifinfomsg))
89#endif
90
85/* ifi_flags. 91/* ifi_flags.
86 92
87 IFF_* flags. 93 IFF_* flags.
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index c57088f575a3..6be767c76b37 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -193,13 +193,20 @@ struct hh_cache
193{ 193{
194 struct hh_cache *hh_next; /* Next entry */ 194 struct hh_cache *hh_next; /* Next entry */
195 atomic_t hh_refcnt; /* number of users */ 195 atomic_t hh_refcnt; /* number of users */
196 __be16 hh_type; /* protocol identifier, f.e ETH_P_IP 196/*
197 * We want hh_output, hh_len, hh_lock and hh_data be a in a separate
198 * cache line on SMP.
199 * They are mostly read, but hh_refcnt may be changed quite frequently,
200 * incurring cache line ping pongs.
201 */
202 __be16 hh_type ____cacheline_aligned_in_smp;
203 /* protocol identifier, f.e ETH_P_IP
197 * NOTE: For VLANs, this will be the 204 * NOTE: For VLANs, this will be the
198 * encapuslated type. --BLG 205 * encapuslated type. --BLG
199 */ 206 */
200 u16 hh_len; /* length of header */ 207 u16 hh_len; /* length of header */
201 int (*hh_output)(struct sk_buff *skb); 208 int (*hh_output)(struct sk_buff *skb);
202 rwlock_t hh_lock; 209 seqlock_t hh_lock;
203 210
204 /* cached hardware header; allow for machine alignment needs. */ 211 /* cached hardware header; allow for machine alignment needs. */
205#define HH_DATA_MOD 16 212#define HH_DATA_MOD 16
diff --git a/include/linux/rtnetlink.h b/include/linux/rtnetlink.h
index 493297acdae8..4a629ea70cc4 100644
--- a/include/linux/rtnetlink.h
+++ b/include/linux/rtnetlink.h
@@ -3,6 +3,8 @@
3 3
4#include <linux/netlink.h> 4#include <linux/netlink.h>
5#include <linux/if_link.h> 5#include <linux/if_link.h>
6#include <linux/if_addr.h>
7#include <linux/neighbour.h>
6 8
7/**** 9/****
8 * Routing/neighbour discovery messages. 10 * Routing/neighbour discovery messages.
diff --git a/include/linux/xfrm.h b/include/linux/xfrm.h
index 088ba8113f7e..9529ea1ae392 100644
--- a/include/linux/xfrm.h
+++ b/include/linux/xfrm.h
@@ -357,7 +357,7 @@ struct xfrm_user_report {
357#define XFRMGRP_EXPIRE 2 357#define XFRMGRP_EXPIRE 2
358#define XFRMGRP_SA 4 358#define XFRMGRP_SA 4
359#define XFRMGRP_POLICY 8 359#define XFRMGRP_POLICY 8
360#define XFRMGRP_REPORT 0x10 360#define XFRMGRP_REPORT 0x20
361#endif 361#endif
362 362
363enum xfrm_nlgroups { 363enum xfrm_nlgroups {
diff --git a/include/net/ax25.h b/include/net/ax25.h
index 69374cd1a857..e1d116f11923 100644
--- a/include/net/ax25.h
+++ b/include/net/ax25.h
@@ -282,15 +282,17 @@ extern void ax25_fillin_cb(ax25_cb *, ax25_dev *);
282extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *); 282extern struct sock *ax25_make_new(struct sock *, struct ax25_dev *);
283 283
284/* ax25_addr.c */ 284/* ax25_addr.c */
285extern ax25_address null_ax25_address; 285extern const ax25_address ax25_bcast;
286extern char *ax2asc(char *buf, ax25_address *); 286extern const ax25_address ax25_defaddr;
287extern void asc2ax(ax25_address *addr, char *callsign); 287extern const ax25_address null_ax25_address;
288extern int ax25cmp(ax25_address *, ax25_address *); 288extern int ax25cmp(const ax25_address *, const ax25_address *);
289extern int ax25digicmp(ax25_digi *, ax25_digi *); 289extern int ax25digicmp(const ax25_digi *, const ax25_digi *);
290extern unsigned char *ax25_addr_parse(unsigned char *, int, ax25_address *, ax25_address *, ax25_digi *, int *, int *); 290extern const unsigned char *ax25_addr_parse(const unsigned char *, int,
291extern int ax25_addr_build(unsigned char *, ax25_address *, ax25_address *, ax25_digi *, int, int); 291 ax25_address *, ax25_address *, ax25_digi *, int *, int *);
292extern int ax25_addr_size(ax25_digi *); 292extern int ax25_addr_build(unsigned char *, const ax25_address *,
293extern void ax25_digi_invert(ax25_digi *, ax25_digi *); 293 const ax25_address *, const ax25_digi *, int, int);
294extern int ax25_addr_size(const ax25_digi *);
295extern void ax25_digi_invert(const ax25_digi *, ax25_digi *);
294 296
295/* ax25_dev.c */ 297/* ax25_dev.c */
296extern ax25_dev *ax25_dev_list; 298extern ax25_dev *ax25_dev_list;
diff --git a/include/net/neighbour.h b/include/net/neighbour.h
index 23967031ddb7..3725b93c52f3 100644
--- a/include/net/neighbour.h
+++ b/include/net/neighbour.h
@@ -309,6 +309,24 @@ static inline int neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
309 return 0; 309 return 0;
310} 310}
311 311
312static inline int neigh_hh_output(struct hh_cache *hh, struct sk_buff *skb)
313{
314 unsigned seq;
315 int hh_len;
316
317 do {
318 int hh_alen;
319
320 seq = read_seqbegin(&hh->hh_lock);
321 hh_len = hh->hh_len;
322 hh_alen = HH_DATA_ALIGN(hh_len);
323 memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
324 } while (read_seqretry(&hh->hh_lock, seq));
325
326 skb_push(skb, hh_len);
327 return hh->hh_output(skb);
328}
329
312static inline struct neighbour * 330static inline struct neighbour *
313__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat) 331__neigh_lookup(struct neigh_table *tbl, const void *pkey, struct net_device *dev, int creat)
314{ 332{
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 5f0896ad0042..21a0616152fc 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -29,17 +29,26 @@
29#include <linux/interrupt.h> 29#include <linux/interrupt.h>
30 30
31/* 31/*
32 * The null address is defined as a callsign of all spaces with an 32 * The default broadcast address of an interface is QST-0; the default address
33 * SSID of zero. 33 * is LINUX-1. The null address is defined as a callsign of all spaces with
34 * an SSID of zero.
34 */ 35 */
35ax25_address null_ax25_address = {{0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x00}};
36 36
37const ax25_address ax25_bcast =
38 {{'Q' << 1, 'S' << 1, 'T' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
39const ax25_address ax25_defaddr =
40 {{'L' << 1, 'I' << 1, 'N' << 1, 'U' << 1, 'X' << 1, ' ' << 1, 1 << 1}};
41const ax25_address null_ax25_address =
42 {{' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, ' ' << 1, 0 << 1}};
43
44EXPORT_SYMBOL_GPL(ax25_bcast);
45EXPORT_SYMBOL_GPL(ax25_defaddr);
37EXPORT_SYMBOL(null_ax25_address); 46EXPORT_SYMBOL(null_ax25_address);
38 47
39/* 48/*
40 * ax25 -> ascii conversion 49 * ax25 -> ascii conversion
41 */ 50 */
42char *ax2asc(char *buf, ax25_address *a) 51char *ax2asc(char *buf, const ax25_address *a)
43{ 52{
44 char c, *s; 53 char c, *s;
45 int n; 54 int n;
@@ -72,7 +81,7 @@ EXPORT_SYMBOL(ax2asc);
72/* 81/*
73 * ascii -> ax25 conversion 82 * ascii -> ax25 conversion
74 */ 83 */
75void asc2ax(ax25_address *addr, char *callsign) 84void asc2ax(ax25_address *addr, const char *callsign)
76{ 85{
77 char *s; 86 char *s;
78 int n; 87 int n;
@@ -107,7 +116,7 @@ EXPORT_SYMBOL(asc2ax);
107/* 116/*
108 * Compare two ax.25 addresses 117 * Compare two ax.25 addresses
109 */ 118 */
110int ax25cmp(ax25_address *a, ax25_address *b) 119int ax25cmp(const ax25_address *a, const ax25_address *b)
111{ 120{
112 int ct = 0; 121 int ct = 0;
113 122
@@ -128,7 +137,7 @@ EXPORT_SYMBOL(ax25cmp);
128/* 137/*
129 * Compare two AX.25 digipeater paths. 138 * Compare two AX.25 digipeater paths.
130 */ 139 */
131int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2) 140int ax25digicmp(const ax25_digi *digi1, const ax25_digi *digi2)
132{ 141{
133 int i; 142 int i;
134 143
@@ -149,7 +158,9 @@ int ax25digicmp(ax25_digi *digi1, ax25_digi *digi2)
149 * Given an AX.25 address pull of to, from, digi list, command/response and the start of data 158 * Given an AX.25 address pull of to, from, digi list, command/response and the start of data
150 * 159 *
151 */ 160 */
152unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags, int *dama) 161const unsigned char *ax25_addr_parse(const unsigned char *buf, int len,
162 ax25_address *src, ax25_address *dest, ax25_digi *digi, int *flags,
163 int *dama)
153{ 164{
154 int d = 0; 165 int d = 0;
155 166
@@ -204,7 +215,8 @@ unsigned char *ax25_addr_parse(unsigned char *buf, int len, ax25_address *src, a
204/* 215/*
205 * Assemble an AX.25 header from the bits 216 * Assemble an AX.25 header from the bits
206 */ 217 */
207int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, ax25_digi *d, int flag, int modulus) 218int ax25_addr_build(unsigned char *buf, const ax25_address *src,
219 const ax25_address *dest, const ax25_digi *d, int flag, int modulus)
208{ 220{
209 int len = 0; 221 int len = 0;
210 int ct = 0; 222 int ct = 0;
@@ -261,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
261 return len; 273 return len;
262} 274}
263 275
264int ax25_addr_size(ax25_digi *dp) 276int ax25_addr_size(const ax25_digi *dp)
265{ 277{
266 if (dp == NULL) 278 if (dp == NULL)
267 return 2 * AX25_ADDR_LEN; 279 return 2 * AX25_ADDR_LEN;
@@ -272,7 +284,7 @@ int ax25_addr_size(ax25_digi *dp)
272/* 284/*
273 * Reverse Digipeat List. May not pass both parameters as same struct 285 * Reverse Digipeat List. May not pass both parameters as same struct
274 */ 286 */
275void ax25_digi_invert(ax25_digi *in, ax25_digi *out) 287void ax25_digi_invert(const ax25_digi *in, ax25_digi *out)
276{ 288{
277 int ct; 289 int ct;
278 290
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0ab1987b9348..e7300b6b4079 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh)
577 while ((hh = neigh->hh) != NULL) { 577 while ((hh = neigh->hh) != NULL) {
578 neigh->hh = hh->hh_next; 578 neigh->hh = hh->hh_next;
579 hh->hh_next = NULL; 579 hh->hh_next = NULL;
580 write_lock_bh(&hh->hh_lock); 580
581 write_seqlock_bh(&hh->hh_lock);
581 hh->hh_output = neigh_blackhole; 582 hh->hh_output = neigh_blackhole;
582 write_unlock_bh(&hh->hh_lock); 583 write_sequnlock_bh(&hh->hh_lock);
583 if (atomic_dec_and_test(&hh->hh_refcnt)) 584 if (atomic_dec_and_test(&hh->hh_refcnt))
584 kfree(hh); 585 kfree(hh);
585 } 586 }
@@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh)
897 898
898 if (update) { 899 if (update) {
899 for (hh = neigh->hh; hh; hh = hh->hh_next) { 900 for (hh = neigh->hh; hh; hh = hh->hh_next) {
900 write_lock_bh(&hh->hh_lock); 901 write_seqlock_bh(&hh->hh_lock);
901 update(hh, neigh->dev, neigh->ha); 902 update(hh, neigh->dev, neigh->ha);
902 write_unlock_bh(&hh->hh_lock); 903 write_sequnlock_bh(&hh->hh_lock);
903 } 904 }
904 } 905 }
905} 906}
@@ -1089,7 +1090,7 @@ static void neigh_hh_init(struct neighbour *n, struct dst_entry *dst,
1089 break; 1090 break;
1090 1091
1091 if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) { 1092 if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
1092 rwlock_init(&hh->hh_lock); 1093 seqlock_init(&hh->hh_lock);
1093 hh->hh_type = protocol; 1094 hh->hh_type = protocol;
1094 atomic_set(&hh->hh_refcnt, 0); 1095 atomic_set(&hh->hh_refcnt, 0);
1095 hh->hh_next = NULL; 1096 hh->hh_next = NULL;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b3c559b9ac35..8a271285f2f3 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -330,6 +330,7 @@ static void arp_reply(struct sk_buff *skb)
330 unsigned char *arp_ptr; 330 unsigned char *arp_ptr;
331 int size, type = ARPOP_REPLY, ptype = ETH_P_ARP; 331 int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
332 __be32 sip, tip; 332 __be32 sip, tip;
333 unsigned char *sha;
333 struct sk_buff *send_skb; 334 struct sk_buff *send_skb;
334 struct netpoll *np = NULL; 335 struct netpoll *np = NULL;
335 336
@@ -356,9 +357,14 @@ static void arp_reply(struct sk_buff *skb)
356 arp->ar_op != htons(ARPOP_REQUEST)) 357 arp->ar_op != htons(ARPOP_REQUEST))
357 return; 358 return;
358 359
359 arp_ptr = (unsigned char *)(arp+1) + skb->dev->addr_len; 360 arp_ptr = (unsigned char *)(arp+1);
361 /* save the location of the src hw addr */
362 sha = arp_ptr;
363 arp_ptr += skb->dev->addr_len;
360 memcpy(&sip, arp_ptr, 4); 364 memcpy(&sip, arp_ptr, 4);
361 arp_ptr += 4 + skb->dev->addr_len; 365 arp_ptr += 4;
366 /* if we actually cared about dst hw addr, it would get copied here */
367 arp_ptr += skb->dev->addr_len;
362 memcpy(&tip, arp_ptr, 4); 368 memcpy(&tip, arp_ptr, 4);
363 369
364 /* Should we ignore arp? */ 370 /* Should we ignore arp? */
@@ -381,7 +387,7 @@ static void arp_reply(struct sk_buff *skb)
381 387
382 if (np->dev->hard_header && 388 if (np->dev->hard_header &&
383 np->dev->hard_header(send_skb, skb->dev, ptype, 389 np->dev->hard_header(send_skb, skb->dev, ptype,
384 np->remote_mac, np->local_mac, 390 sha, np->local_mac,
385 send_skb->len) < 0) { 391 send_skb->len) < 0) {
386 kfree_skb(send_skb); 392 kfree_skb(send_skb);
387 return; 393 return;
@@ -405,7 +411,7 @@ static void arp_reply(struct sk_buff *skb)
405 arp_ptr += np->dev->addr_len; 411 arp_ptr += np->dev->addr_len;
406 memcpy(arp_ptr, &tip, 4); 412 memcpy(arp_ptr, &tip, 4);
407 arp_ptr += 4; 413 arp_ptr += 4;
408 memcpy(arp_ptr, np->remote_mac, np->dev->addr_len); 414 memcpy(arp_ptr, sha, np->dev->addr_len);
409 arp_ptr += np->dev->addr_len; 415 arp_ptr += np->dev->addr_len;
410 memcpy(arp_ptr, &sip, 4); 416 memcpy(arp_ptr, &sip, 4);
411 417
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index a35209d517ad..f071f84808fa 100644
--- a/net/ipv4/ip_output.c
+++ b/net/ipv4/ip_output.c
@@ -164,7 +164,6 @@ EXPORT_SYMBOL_GPL(ip_build_and_send_pkt);
164static inline int ip_finish_output2(struct sk_buff *skb) 164static inline int ip_finish_output2(struct sk_buff *skb)
165{ 165{
166 struct dst_entry *dst = skb->dst; 166 struct dst_entry *dst = skb->dst;
167 struct hh_cache *hh = dst->hh;
168 struct net_device *dev = dst->dev; 167 struct net_device *dev = dst->dev;
169 int hh_len = LL_RESERVED_SPACE(dev); 168 int hh_len = LL_RESERVED_SPACE(dev);
170 169
@@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb)
183 skb = skb2; 182 skb = skb2;
184 } 183 }
185 184
186 if (hh) { 185 if (dst->hh)
187 int hh_alen; 186 return neigh_hh_output(dst->hh, skb);
188 187 else if (dst->neighbour)
189 read_lock_bh(&hh->hh_lock);
190 hh_alen = HH_DATA_ALIGN(hh->hh_len);
191 memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
192 read_unlock_bh(&hh->hh_lock);
193 skb_push(skb, hh->hh_len);
194 return hh->hh_output(skb);
195 } else if (dst->neighbour)
196 return dst->neighbour->output(skb); 188 return dst->neighbour->output(skb);
197 189
198 if (net_ratelimit()) 190 if (net_ratelimit())
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e9212c7ff5cf..7b7bd44fbf47 100644
--- a/net/ipv6/ip6_output.c
+++ b/net/ipv6/ip6_output.c
@@ -72,20 +72,11 @@ static __inline__ void ipv6_select_ident(struct sk_buff *skb, struct frag_hdr *f
72 72
73static inline int ip6_output_finish(struct sk_buff *skb) 73static inline int ip6_output_finish(struct sk_buff *skb)
74{ 74{
75
76 struct dst_entry *dst = skb->dst; 75 struct dst_entry *dst = skb->dst;
77 struct hh_cache *hh = dst->hh; 76
78 77 if (dst->hh)
79 if (hh) { 78 return neigh_hh_output(dst->hh, skb);
80 int hh_alen; 79 else if (dst->neighbour)
81
82 read_lock_bh(&hh->hh_lock);
83 hh_alen = HH_DATA_ALIGN(hh->hh_len);
84 memcpy(skb->data - hh_alen, hh->hh_data, hh_alen);
85 read_unlock_bh(&hh->hh_lock);
86 skb_push(skb, hh->hh_len);
87 return hh->hh_output(skb);
88 } else if (dst->neighbour)
89 return dst->neighbour->output(skb); 80 return dst->neighbour->output(skb);
90 81
91 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES); 82 IP6_INC_STATS_BH(ip6_dst_idev(dst), IPSTATS_MIB_OUTNOROUTES);
diff --git a/net/sched/sch_cbq.c b/net/sched/sch_cbq.c
index ba82dfab6043..f79a4f3d0a95 100644
--- a/net/sched/sch_cbq.c
+++ b/net/sched/sch_cbq.c
@@ -371,8 +371,6 @@ static void cbq_deactivate_class(struct cbq_class *this)
371 return; 371 return;
372 } 372 }
373 } 373 }
374
375 cl = cl_prev->next_alive;
376 return; 374 return;
377 } 375 }
378 } while ((cl_prev = cl) != q->active[prio]); 376 } while ((cl_prev = cl) != q->active[prio]);
@@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch)
1258 do { 1256 do {
1259 if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) { 1257 if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
1260 sch->q.qlen--; 1258 sch->q.qlen--;
1259 if (!cl->q->q.qlen)
1260 cbq_deactivate_class(cl);
1261 return len; 1261 return len;
1262 } 1262 }
1263 } while ((cl = cl->next_alive) != cl_head); 1263 } while ((cl = cl->next_alive) != cl_head);
@@ -1685,8 +1685,7 @@ static int cbq_graft(struct Qdisc *sch, unsigned long arg, struct Qdisc *new,
1685#endif 1685#endif
1686 } 1686 }
1687 sch_tree_lock(sch); 1687 sch_tree_lock(sch);
1688 *old = cl->q; 1688 *old = xchg(&cl->q, new);
1689 cl->q = new;
1690 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen); 1689 qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
1691 qdisc_reset(*old); 1690 qdisc_reset(*old);
1692 sch_tree_unlock(sch); 1691 sch_tree_unlock(sch);
@@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg)
1704 return cl ? cl->q : NULL; 1703 return cl ? cl->q : NULL;
1705} 1704}
1706 1705
1706static void cbq_qlen_notify(struct Qdisc *sch, unsigned long arg)
1707{
1708 struct cbq_class *cl = (struct cbq_class *)arg;
1709
1710 if (cl->q->q.qlen == 0)
1711 cbq_deactivate_class(cl);
1712}
1713
1707static unsigned long cbq_get(struct Qdisc *sch, u32 classid) 1714static unsigned long cbq_get(struct Qdisc *sch, u32 classid)
1708{ 1715{
1709 struct cbq_sched_data *q = qdisc_priv(sch); 1716 struct cbq_sched_data *q = qdisc_priv(sch);
@@ -1988,12 +1995,17 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
1988{ 1995{
1989 struct cbq_sched_data *q = qdisc_priv(sch); 1996 struct cbq_sched_data *q = qdisc_priv(sch);
1990 struct cbq_class *cl = (struct cbq_class*)arg; 1997 struct cbq_class *cl = (struct cbq_class*)arg;
1998 unsigned int qlen;
1991 1999
1992 if (cl->filters || cl->children || cl == &q->link) 2000 if (cl->filters || cl->children || cl == &q->link)
1993 return -EBUSY; 2001 return -EBUSY;
1994 2002
1995 sch_tree_lock(sch); 2003 sch_tree_lock(sch);
1996 2004
2005 qlen = cl->q->q.qlen;
2006 qdisc_reset(cl->q);
2007 qdisc_tree_decrease_qlen(cl->q, qlen);
2008
1997 if (cl->next_alive) 2009 if (cl->next_alive)
1998 cbq_deactivate_class(cl); 2010 cbq_deactivate_class(cl);
1999 2011
@@ -2084,6 +2096,7 @@ static void cbq_walk(struct Qdisc *sch, struct qdisc_walker *arg)
2084static struct Qdisc_class_ops cbq_class_ops = { 2096static struct Qdisc_class_ops cbq_class_ops = {
2085 .graft = cbq_graft, 2097 .graft = cbq_graft,
2086 .leaf = cbq_leaf, 2098 .leaf = cbq_leaf,
2099 .qlen_notify = cbq_qlen_notify,
2087 .get = cbq_get, 2100 .get = cbq_get,
2088 .put = cbq_put, 2101 .put = cbq_put,
2089 .change = cbq_change_class, 2102 .change = cbq_change_class,
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 215e68c2b615..15f23c5511a8 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -147,6 +147,10 @@ struct htb_class {
147 psched_tdiff_t mbuffer; /* max wait time */ 147 psched_tdiff_t mbuffer; /* max wait time */
148 long tokens, ctokens; /* current number of tokens */ 148 long tokens, ctokens; /* current number of tokens */
149 psched_time_t t_c; /* checkpoint time */ 149 psched_time_t t_c; /* checkpoint time */
150
151 int prio; /* For parent to leaf return possible here */
152 int quantum; /* we do backup. Finally full replacement */
153 /* of un.leaf originals should be done. */
150}; 154};
151 155
152/* TODO: maybe compute rate when size is too large .. or drop ? */ 156/* TODO: maybe compute rate when size is too large .. or drop ? */
@@ -1271,6 +1275,38 @@ static void htb_destroy_filters(struct tcf_proto **fl)
1271 } 1275 }
1272} 1276}
1273 1277
1278static inline int htb_parent_last_child(struct htb_class *cl)
1279{
1280 if (!cl->parent)
1281 /* the root class */
1282 return 0;
1283
1284 if (!(cl->parent->children.next == &cl->sibling &&
1285 cl->parent->children.prev == &cl->sibling))
1286 /* not the last child */
1287 return 0;
1288
1289 return 1;
1290}
1291
1292static void htb_parent_to_leaf(struct htb_class *cl, struct Qdisc *new_q)
1293{
1294 struct htb_class *parent = cl->parent;
1295
1296 BUG_TRAP(!cl->level && cl->un.leaf.q && !cl->prio_activity);
1297
1298 parent->level = 0;
1299 memset(&parent->un.inner, 0, sizeof(parent->un.inner));
1300 INIT_LIST_HEAD(&parent->un.leaf.drop_list);
1301 parent->un.leaf.q = new_q ? new_q : &noop_qdisc;
1302 parent->un.leaf.quantum = parent->quantum;
1303 parent->un.leaf.prio = parent->prio;
1304 parent->tokens = parent->buffer;
1305 parent->ctokens = parent->cbuffer;
1306 PSCHED_GET_TIME(parent->t_c);
1307 parent->cmode = HTB_CAN_SEND;
1308}
1309
1274static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl) 1310static void htb_destroy_class(struct Qdisc *sch, struct htb_class *cl)
1275{ 1311{
1276 struct htb_sched *q = qdisc_priv(sch); 1312 struct htb_sched *q = qdisc_priv(sch);
@@ -1328,6 +1364,8 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1328 struct htb_sched *q = qdisc_priv(sch); 1364 struct htb_sched *q = qdisc_priv(sch);
1329 struct htb_class *cl = (struct htb_class *)arg; 1365 struct htb_class *cl = (struct htb_class *)arg;
1330 unsigned int qlen; 1366 unsigned int qlen;
1367 struct Qdisc *new_q = NULL;
1368 int last_child = 0;
1331 1369
1332 // TODO: why don't allow to delete subtree ? references ? does 1370 // TODO: why don't allow to delete subtree ? references ? does
1333 // tc subsys quarantee us that in htb_destroy it holds no class 1371 // 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)
1335 if (!list_empty(&cl->children) || cl->filter_cnt) 1373 if (!list_empty(&cl->children) || cl->filter_cnt)
1336 return -EBUSY; 1374 return -EBUSY;
1337 1375
1376 if (!cl->level && htb_parent_last_child(cl)) {
1377 new_q = qdisc_create_dflt(sch->dev, &pfifo_qdisc_ops,
1378 cl->parent->classid);
1379 last_child = 1;
1380 }
1381
1338 sch_tree_lock(sch); 1382 sch_tree_lock(sch);
1339 1383
1340 /* delete from hash and active; remainder in destroy_class */ 1384 /* delete from hash and active; remainder in destroy_class */
@@ -1349,6 +1393,9 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
1349 if (cl->prio_activity) 1393 if (cl->prio_activity)
1350 htb_deactivate(q, cl); 1394 htb_deactivate(q, cl);
1351 1395
1396 if (last_child)
1397 htb_parent_to_leaf(cl, new_q);
1398
1352 if (--cl->refcnt == 0) 1399 if (--cl->refcnt == 0)
1353 htb_destroy_class(sch, cl); 1400 htb_destroy_class(sch, cl);
1354 1401
@@ -1483,6 +1530,10 @@ static int htb_change_class(struct Qdisc *sch, u32 classid,
1483 cl->un.leaf.quantum = hopt->quantum; 1530 cl->un.leaf.quantum = hopt->quantum;
1484 if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO) 1531 if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
1485 cl->un.leaf.prio = TC_HTB_NUMPRIO - 1; 1532 cl->un.leaf.prio = TC_HTB_NUMPRIO - 1;
1533
1534 /* backup for htb_parent_to_leaf */
1535 cl->quantum = cl->un.leaf.quantum;
1536 cl->prio = cl->un.leaf.prio;
1486 } 1537 }
1487 1538
1488 cl->buffer = hopt->buffer; 1539 cl->buffer = hopt->buffer;