net: '&' redux
[safe/jmp/linux-2.6] / net / bridge / br_stp_bpdu.c
index a99e90e..81ae40b 100644 (file)
@@ -5,8 +5,6 @@
  *     Authors:
  *     Lennert Buytenhek               <buytenh@gnu.org>
  *
- *     $Id: br_stp_bpdu.c,v 1.3 2001/11/10 02:35:25 davem Exp $
- *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
  *     as published by the Free Software Foundation; either version
 #include <linux/netfilter_bridge.h>
 #include <linux/etherdevice.h>
 #include <linux/llc.h>
+#include <net/net_namespace.h>
+#include <net/llc.h>
 #include <net/llc_pdu.h>
+#include <net/stp.h>
+#include <asm/unaligned.h>
 
 #include "br_private.h"
 #include "br_private_stp.h"
 
 #define STP_HZ         256
 
-static void br_send_bpdu(struct net_bridge_port *p, unsigned char *data, int length)
+#define LLC_RESERVE sizeof(struct llc_pdu_un)
+
+static void br_send_bpdu(struct net_bridge_port *p,
+                        const unsigned char *data, int length)
 {
-       struct net_device *dev;
        struct sk_buff *skb;
-       int size;
 
-       if (!p->br->stp_enabled)
+       skb = dev_alloc_skb(length+LLC_RESERVE);
+       if (!skb)
                return;
 
-       size = length + 2*ETH_ALEN + 2;
-       if (size < 60)
-               size = 60;
+       skb->dev = p->dev;
+       skb->protocol = htons(ETH_P_802_2);
 
-       dev = p->dev;
+       skb_reserve(skb, LLC_RESERVE);
+       memcpy(__skb_put(skb, length), data, length);
 
-       if ((skb = dev_alloc_skb(size)) == NULL) {
-               printk(KERN_INFO "br: memory squeeze!\n");
-               return;
-       }
+       llc_pdu_header_init(skb, LLC_PDU_TYPE_U, LLC_SAP_BSPAN,
+                           LLC_SAP_BSPAN, LLC_PDU_CMD);
+       llc_pdu_init_as_ui_cmd(skb);
 
-       skb->dev = dev;
-       skb->protocol = htons(ETH_P_802_2);
-       skb->mac.raw = skb_put(skb, size);
-       memcpy(skb->mac.raw, bridge_ula, ETH_ALEN);
-       memcpy(skb->mac.raw+ETH_ALEN, dev->dev_addr, ETH_ALEN);
-       skb->mac.raw[2*ETH_ALEN] = 0;
-       skb->mac.raw[2*ETH_ALEN+1] = length;
-       skb->nh.raw = skb->mac.raw + 2*ETH_ALEN + 2;
-       memcpy(skb->nh.raw, data, length);
-       memset(skb->nh.raw + length, 0xa5, size - length - 2*ETH_ALEN - 2);
+       llc_mac_hdr_init(skb, p->dev->dev_addr, p->br->group_addr);
 
        NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_OUT, skb, NULL, skb->dev,
                dev_queue_xmit);
@@ -63,74 +57,74 @@ static inline void br_set_ticks(unsigned char *dest, int j)
 {
        unsigned long ticks = (STP_HZ * j)/ HZ;
 
-       *((__be16 *) dest) = htons(ticks);
+       put_unaligned_be16(ticks, dest);
 }
 
 static inline int br_get_ticks(const unsigned char *src)
 {
-       unsigned long ticks = ntohs(*(__be16 *)src);
+       unsigned long ticks = get_unaligned_be16(src);
 
-       return (ticks * HZ + STP_HZ - 1) / STP_HZ;
+       return DIV_ROUND_UP(ticks * HZ, STP_HZ);
 }
 
 /* called under bridge lock */
 void br_send_config_bpdu(struct net_bridge_port *p, struct br_config_bpdu *bpdu)
 {
-       unsigned char buf[38];
-
-       buf[0] = 0x42;
-       buf[1] = 0x42;
-       buf[2] = 0x03;
-       buf[3] = 0;
-       buf[4] = 0;
-       buf[5] = 0;
-       buf[6] = BPDU_TYPE_CONFIG;
-       buf[7] = (bpdu->topology_change ? 0x01 : 0) |
+       unsigned char buf[35];
+
+       if (p->br->stp_enabled != BR_KERNEL_STP)
+               return;
+
+       buf[0] = 0;
+       buf[1] = 0;
+       buf[2] = 0;
+       buf[3] = BPDU_TYPE_CONFIG;
+       buf[4] = (bpdu->topology_change ? 0x01 : 0) |
                (bpdu->topology_change_ack ? 0x80 : 0);
-       buf[8] = bpdu->root.prio[0];
-       buf[9] = bpdu->root.prio[1];
-       buf[10] = bpdu->root.addr[0];
-       buf[11] = bpdu->root.addr[1];
-       buf[12] = bpdu->root.addr[2];
-       buf[13] = bpdu->root.addr[3];
-       buf[14] = bpdu->root.addr[4];
-       buf[15] = bpdu->root.addr[5];
-       buf[16] = (bpdu->root_path_cost >> 24) & 0xFF;
-       buf[17] = (bpdu->root_path_cost >> 16) & 0xFF;
-       buf[18] = (bpdu->root_path_cost >> 8) & 0xFF;
-       buf[19] = bpdu->root_path_cost & 0xFF;
-       buf[20] = bpdu->bridge_id.prio[0];
-       buf[21] = bpdu->bridge_id.prio[1];
-       buf[22] = bpdu->bridge_id.addr[0];
-       buf[23] = bpdu->bridge_id.addr[1];
-       buf[24] = bpdu->bridge_id.addr[2];
-       buf[25] = bpdu->bridge_id.addr[3];
-       buf[26] = bpdu->bridge_id.addr[4];
-       buf[27] = bpdu->bridge_id.addr[5];
-       buf[28] = (bpdu->port_id >> 8) & 0xFF;
-       buf[29] = bpdu->port_id & 0xFF;
-
-       br_set_ticks(buf+30, bpdu->message_age);
-       br_set_ticks(buf+32, bpdu->max_age);
-       br_set_ticks(buf+34, bpdu->hello_time);
-       br_set_ticks(buf+36, bpdu->forward_delay);
-
-       br_send_bpdu(p, buf, 38);
+       buf[5] = bpdu->root.prio[0];
+       buf[6] = bpdu->root.prio[1];
+       buf[7] = bpdu->root.addr[0];
+       buf[8] = bpdu->root.addr[1];
+       buf[9] = bpdu->root.addr[2];
+       buf[10] = bpdu->root.addr[3];
+       buf[11] = bpdu->root.addr[4];
+       buf[12] = bpdu->root.addr[5];
+       buf[13] = (bpdu->root_path_cost >> 24) & 0xFF;
+       buf[14] = (bpdu->root_path_cost >> 16) & 0xFF;
+       buf[15] = (bpdu->root_path_cost >> 8) & 0xFF;
+       buf[16] = bpdu->root_path_cost & 0xFF;
+       buf[17] = bpdu->bridge_id.prio[0];
+       buf[18] = bpdu->bridge_id.prio[1];
+       buf[19] = bpdu->bridge_id.addr[0];
+       buf[20] = bpdu->bridge_id.addr[1];
+       buf[21] = bpdu->bridge_id.addr[2];
+       buf[22] = bpdu->bridge_id.addr[3];
+       buf[23] = bpdu->bridge_id.addr[4];
+       buf[24] = bpdu->bridge_id.addr[5];
+       buf[25] = (bpdu->port_id >> 8) & 0xFF;
+       buf[26] = bpdu->port_id & 0xFF;
+
+       br_set_ticks(buf+27, bpdu->message_age);
+       br_set_ticks(buf+29, bpdu->max_age);
+       br_set_ticks(buf+31, bpdu->hello_time);
+       br_set_ticks(buf+33, bpdu->forward_delay);
+
+       br_send_bpdu(p, buf, 35);
 }
 
 /* called under bridge lock */
 void br_send_tcn_bpdu(struct net_bridge_port *p)
 {
-       unsigned char buf[7];
-
-       buf[0] = 0x42;
-       buf[1] = 0x42;
-       buf[2] = 0x03;
-       buf[3] = 0;
-       buf[4] = 0;
-       buf[5] = 0;
-       buf[6] = BPDU_TYPE_TCN;
-       br_send_bpdu(p, buf, 7);
+       unsigned char buf[4];
+
+       if (p->br->stp_enabled != BR_KERNEL_STP)
+               return;
+
+       buf[0] = 0;
+       buf[1] = 0;
+       buf[2] = 0;
+       buf[3] = BPDU_TYPE_TCN;
+       br_send_bpdu(p, buf, 4);
 }
 
 /*
@@ -138,10 +132,9 @@ void br_send_tcn_bpdu(struct net_bridge_port *p)
  *
  * NO locks, but rcu_read_lock (preempt_disabled)
  */
-int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
-              struct packet_type *pt, struct net_device *orig_dev)
+void br_stp_rcv(const struct stp_proto *proto, struct sk_buff *skb,
+               struct net_device *dev)
 {
-       const struct llc_pdu_un *pdu = llc_pdu_un_hdr(skb);
        const unsigned char *dest = eth_hdr(skb)->h_dest;
        struct net_bridge_port *p = rcu_dereference(dev->br_port);
        struct net_bridge *br;
@@ -150,11 +143,6 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
        if (!p)
                goto err;
 
-       if (pdu->ssap != LLC_SAP_BSPAN
-           || pdu->dsap != LLC_SAP_BSPAN
-           || pdu->ctrl_1 != LLC_PDU_TYPE_U)
-               goto err;
-
        if (!pskb_may_pull(skb, 4))
                goto err;
 
@@ -166,12 +154,16 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
        br = p->br;
        spin_lock(&br->lock);
 
-       if (p->state == BR_STATE_DISABLED
-           || !br->stp_enabled
-           || !(br->dev->flags & IFF_UP))
+       if (br->stp_enabled != BR_KERNEL_STP)
+               goto out;
+
+       if (!(br->dev->flags & IFF_UP))
+               goto out;
+
+       if (p->state == BR_STATE_DISABLED)
                goto out;
 
-       if (compare_ether_addr(dest, bridge_ula) != 0)
+       if (compare_ether_addr(dest, br->group_addr) != 0)
                goto out;
 
        buf = skb_pull(skb, 3);
@@ -224,5 +216,4 @@ int br_stp_rcv(struct sk_buff *skb, struct net_device *dev,
        spin_unlock(&br->lock);
  err:
        kfree_skb(skb);
-       return 0;
 }