aboutsummaryrefslogtreecommitdiff
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-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
7 files changed, 114 insertions, 48 deletions
diff --git a/net/ax25/ax25_addr.c b/net/ax25/ax25_addr.c
index 5f0896ad004..21a0616152f 100644
--- a/net/ax25/ax25_addr.c
+++ b/net/ax25/ax25_addr.c
@@ -29,17 +29,26 @@
#include <linux/interrupt.h>
/*
- * The null address is defined as a callsign of all spaces with an
- * SSID of zero.
+ * The default broadcast address of an interface is QST-0; the default address
+ * 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);
/*
* ax25 -> ascii conversion
*/
-char *ax2asc(char *buf, ax25_address *a)
+char *ax2asc(char *buf, const ax25_address *a)
{
char c, *s;
int n;
@@ -72,7 +81,7 @@ EXPORT_SYMBOL(ax2asc);
/*
* ascii -> ax25 conversion
*/
-void asc2ax(ax25_address *addr, char *callsign)
+void asc2ax(ax25_address *addr, const char *callsign)
{
char *s;
int n;
@@ -107,7 +116,7 @@ EXPORT_SYMBOL(asc2ax);
/*
* 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;
@@ -128,7 +137,7 @@ EXPORT_SYMBOL(ax25cmp);
/*
* 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;
@@ -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
*
*/
-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;
@@ -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
*/
-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 ct = 0;
@@ -261,7 +273,7 @@ int ax25_addr_build(unsigned char *buf, ax25_address *src, ax25_address *dest, a
return len;
}
-int ax25_addr_size(ax25_digi *dp)
+int ax25_addr_size(const ax25_digi *dp)
{
if (dp == NULL)
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
*/
-void ax25_digi_invert(ax25_digi *in, ax25_digi *out)
+void ax25_digi_invert(const ax25_digi *in, ax25_digi *out)
{
int ct;
diff --git a/net/core/neighbour.c b/net/core/neighbour.c
index 0ab1987b934..e7300b6b407 100644
--- a/net/core/neighbour.c
+++ b/net/core/neighbour.c
@@ -577,9 +577,10 @@ void neigh_destroy(struct neighbour *neigh)
while ((hh = neigh->hh) != NULL) {
neigh->hh = hh->hh_next;
hh->hh_next = NULL;
- write_lock_bh(&hh->hh_lock);
+
+ write_seqlock_bh(&hh->hh_lock);
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))
kfree(hh);
}
@@ -897,9 +898,9 @@ static void neigh_update_hhs(struct neighbour *neigh)
if (update) {
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);
- 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;
if (!hh && (hh = kzalloc(sizeof(*hh), GFP_ATOMIC)) != NULL) {
- rwlock_init(&hh->hh_lock);
+ seqlock_init(&hh->hh_lock);
hh->hh_type = protocol;
atomic_set(&hh->hh_refcnt, 0);
hh->hh_next = NULL;
diff --git a/net/core/netpoll.c b/net/core/netpoll.c
index b3c559b9ac3..8a271285f2f 100644
--- a/net/core/netpoll.c
+++ b/net/core/netpoll.c
@@ -330,6 +330,7 @@ static void arp_reply(struct sk_buff *skb)
unsigned char *arp_ptr;
int size, type = ARPOP_REPLY, ptype = ETH_P_ARP;
__be32 sip, tip;
+ unsigned char *sha;
struct sk_buff *send_skb;
struct netpoll *np = NULL;
@@ -356,9 +357,14 @@ static void arp_reply(struct sk_buff *skb)
arp->ar_op != htons(ARPOP_REQUEST))
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);
- 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);
/* Should we ignore arp? */
@@ -381,7 +387,7 @@ static void arp_reply(struct sk_buff *skb)
if (np->dev->hard_header &&
np->dev->hard_header(send_skb, skb->dev, ptype,
- np->remote_mac, np->local_mac,
+ sha, np->local_mac,
send_skb->len) < 0) {
kfree_skb(send_skb);
return;
@@ -405,7 +411,7 @@ static void arp_reply(struct sk_buff *skb)
arp_ptr += np->dev->addr_len;
memcpy(arp_ptr, &tip, 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;
memcpy(arp_ptr, &sip, 4);
diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c
index a35209d517a..f071f84808f 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);
static inline int ip_finish_output2(struct sk_buff *skb)
{
struct dst_entry *dst = skb->dst;
- struct hh_cache *hh = dst->hh;
struct net_device *dev = dst->dev;
int hh_len = LL_RESERVED_SPACE(dev);
@@ -183,16 +182,9 @@ static inline int ip_finish_output2(struct sk_buff *skb)
skb = skb2;
}
- if (hh) {
- int hh_alen;
-
- 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)
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
return dst->neighbour->output(skb);
if (net_ratelimit())
diff --git a/net/ipv6/ip6_output.c b/net/ipv6/ip6_output.c
index e9212c7ff5c..7b7bd44fbf4 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
static inline int ip6_output_finish(struct sk_buff *skb)
{
-
struct dst_entry *dst = skb->dst;
- struct hh_cache *hh = dst->hh;
-
- if (hh) {
- int hh_alen;
-
- 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)
+
+ if (dst->hh)
+ return neigh_hh_output(dst->hh, skb);
+ else if (dst->neighbour)
return dst->neighbour->output(skb);
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 ba82dfab604..f79a4f3d0a9 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)
return;
}
}
-
- cl = cl_prev->next_alive;
return;
}
} while ((cl_prev = cl) != q->active[prio]);
@@ -1258,6 +1256,8 @@ static unsigned int cbq_drop(struct Qdisc* sch)
do {
if (cl->q->ops->drop && (len = cl->q->ops->drop(cl->q))) {
sch->q.qlen--;
+ if (!cl->q->q.qlen)
+ cbq_deactivate_class(cl);
return len;
}
} 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
}
sch_tree_lock(sch);
- *old = cl->q;
- cl->q = new;
+ *old = xchg(&cl->q, new);
qdisc_tree_decrease_qlen(*old, (*old)->q.qlen);
qdisc_reset(*old);
sch_tree_unlock(sch);
@@ -1704,6 +1703,14 @@ cbq_leaf(struct Qdisc *sch, unsigned long arg)
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)
{
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_class *cl = (struct cbq_class*)arg;
+ unsigned int qlen;
if (cl->filters || cl->children || cl == &q->link)
return -EBUSY;
sch_tree_lock(sch);
+ qlen = cl->q->q.qlen;
+ qdisc_reset(cl->q);
+ qdisc_tree_decrease_qlen(cl->q, qlen);
+
if (cl->next_alive)
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 = {
.graft = cbq_graft,
.leaf = cbq_leaf,
+ .qlen_notify = cbq_qlen_notify,
.get = cbq_get,
.put = cbq_put,
.change = cbq_change_class,
diff --git a/net/sched/sch_htb.c b/net/sched/sch_htb.c
index 215e68c2b61..15f23c5511a 100644
--- a/net/sched/sch_htb.c
+++ b/net/sched/sch_htb.c
@@ -147,6 +147,10 @@ struct htb_class {
psched_tdiff_t mbuffer; /* max wait time */
long tokens, ctokens; /* current number of tokens */
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 ? */
@@ -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)
{
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_class *cl = (struct htb_class *)arg;
unsigned int qlen;
+ struct Qdisc *new_q = NULL;
+ int last_child = 0;
// TODO: why don't allow to delete subtree ? references ? does
// 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)
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);
/* 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)
htb_deactivate(q, cl);
+ if (last_child)
+ htb_parent_to_leaf(cl, new_q);
+
if (--cl->refcnt == 0)
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;
if ((cl->un.leaf.prio = hopt->prio) >= TC_HTB_NUMPRIO)
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;