aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wan/hdlc_cisco.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wan/hdlc_cisco.c')
-rw-r--r--drivers/net/wan/hdlc_cisco.c168
1 files changed, 88 insertions, 80 deletions
diff --git a/drivers/net/wan/hdlc_cisco.c b/drivers/net/wan/hdlc_cisco.c
index 7133c688cf2..3f20808b5ff 100644
--- a/drivers/net/wan/hdlc_cisco.c
+++ b/drivers/net/wan/hdlc_cisco.c
@@ -9,19 +9,17 @@
* as published by the Free Software Foundation.
*/
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/poll.h>
#include <linux/errno.h>
+#include <linux/hdlc.h>
#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
#include <linux/init.h>
-#include <linux/skbuff.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/pkt_sched.h>
-#include <linux/inetdevice.h>
-#include <linux/lapb.h>
+#include <linux/poll.h>
#include <linux/rtnetlink.h>
-#include <linux/hdlc.h>
+#include <linux/skbuff.h>
#undef DEBUG_HARD_HEADER
@@ -38,7 +36,7 @@ struct hdlc_header {
u8 address;
u8 control;
__be16 protocol;
-}__attribute__ ((packed));
+}__packed;
struct cisco_packet {
@@ -47,7 +45,7 @@ struct cisco_packet {
__be32 par2;
__be16 rel; /* reliability */
__be32 time;
-}__attribute__ ((packed));
+}__packed;
#define CISCO_PACKET_LEN 18
#define CISCO_BIG_PACKET_LEN 20
@@ -56,10 +54,10 @@ struct cisco_state {
cisco_proto settings;
struct timer_list timer;
+ spinlock_t lock;
unsigned long last_poll;
int up;
- int request_sent;
- u32 txseq; /* TX sequence number */
+ u32 txseq; /* TX sequence number, 0 = none */
u32 rxseq; /* RX sequence number */
};
@@ -67,9 +65,9 @@ struct cisco_state {
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
-static inline struct cisco_state * state(hdlc_device *hdlc)
+static inline struct cisco_state* state(hdlc_device *hdlc)
{
- return(struct cisco_state *)(hdlc->state);
+ return (struct cisco_state *)hdlc->state;
}
@@ -105,9 +103,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
skb = dev_alloc_skb(sizeof(struct hdlc_header) +
sizeof(struct cisco_packet));
if (!skb) {
- printk(KERN_WARNING
- "%s: Memory squeeze on cisco_keepalive_send()\n",
- dev->name);
+ netdev_warn(dev, "Memory squeeze on cisco_keepalive_send()\n");
return;
}
skb_reserve(skb, 4);
@@ -117,7 +113,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
data->type = htonl(type);
data->par1 = par1;
data->par2 = par2;
- data->rel = __constant_htons(0xFFFF);
+ data->rel = cpu_to_be16(0xFFFF);
/* we will need do_div here if 1000 % HZ != 0 */
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
@@ -136,20 +132,20 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
struct hdlc_header *data = (struct hdlc_header*)skb->data;
if (skb->len < sizeof(struct hdlc_header))
- return __constant_htons(ETH_P_HDLC);
+ return cpu_to_be16(ETH_P_HDLC);
if (data->address != CISCO_MULTICAST &&
data->address != CISCO_UNICAST)
- return __constant_htons(ETH_P_HDLC);
+ return cpu_to_be16(ETH_P_HDLC);
- switch(data->protocol) {
- case __constant_htons(ETH_P_IP):
- case __constant_htons(ETH_P_IPX):
- case __constant_htons(ETH_P_IPV6):
+ switch (data->protocol) {
+ case cpu_to_be16(ETH_P_IP):
+ case cpu_to_be16(ETH_P_IPX):
+ case cpu_to_be16(ETH_P_IPV6):
skb_pull(skb, sizeof(struct hdlc_header));
return data->protocol;
default:
- return __constant_htons(ETH_P_HDLC);
+ return cpu_to_be16(ETH_P_HDLC);
}
}
@@ -158,10 +154,12 @@ static int cisco_rx(struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct cisco_state *st = state(hdlc);
struct hdlc_header *data = (struct hdlc_header*)skb->data;
struct cisco_packet *cisco_data;
struct in_device *in_dev;
__be32 addr, mask;
+ u32 ack;
if (skb->len < sizeof(struct hdlc_header))
goto rx_error;
@@ -170,7 +168,7 @@ static int cisco_rx(struct sk_buff *skb)
data->address != CISCO_UNICAST)
goto rx_error;
- switch(ntohs(data->protocol)) {
+ switch (ntohs(data->protocol)) {
case CISCO_SYS_INFO:
/* Packet is not needed, drop it. */
dev_kfree_skb_any(skb);
@@ -181,19 +179,20 @@ static int cisco_rx(struct sk_buff *skb)
CISCO_PACKET_LEN) &&
(skb->len != sizeof(struct hdlc_header) +
CISCO_BIG_PACKET_LEN)) {
- printk(KERN_INFO "%s: Invalid length of Cisco control"
- " packet (%d bytes)\n", dev->name, skb->len);
+ netdev_info(dev, "Invalid length of Cisco control packet (%d bytes)\n",
+ skb->len);
goto rx_error;
}
cisco_data = (struct cisco_packet*)(skb->data + sizeof
(struct hdlc_header));
- switch(ntohl (cisco_data->type)) {
+ switch (ntohl (cisco_data->type)) {
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
- in_dev = dev->ip_ptr;
+ rcu_read_lock();
+ in_dev = __in_dev_get_rcu(dev);
addr = 0;
- mask = __constant_htonl(~0); /* is the mask correct? */
+ mask = ~cpu_to_be32(0); /* is the mask correct? */
if (in_dev != NULL) {
struct in_ifaddr **ifap = &in_dev->ifa_list;
@@ -211,46 +210,47 @@ static int cisco_rx(struct sk_buff *skb)
cisco_keepalive_send(dev, CISCO_ADDR_REPLY,
addr, mask);
}
+ rcu_read_unlock();
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
case CISCO_ADDR_REPLY:
- printk(KERN_INFO "%s: Unexpected Cisco IP address "
- "reply\n", dev->name);
+ netdev_info(dev, "Unexpected Cisco IP address reply\n");
goto rx_error;
case CISCO_KEEPALIVE_REQ:
- state(hdlc)->rxseq = ntohl(cisco_data->par1);
- if (state(hdlc)->request_sent &&
- ntohl(cisco_data->par2) == state(hdlc)->txseq) {
- state(hdlc)->last_poll = jiffies;
- if (!state(hdlc)->up) {
+ spin_lock(&st->lock);
+ st->rxseq = ntohl(cisco_data->par1);
+ ack = ntohl(cisco_data->par2);
+ if (ack && (ack == st->txseq ||
+ /* our current REQ may be in transit */
+ ack == st->txseq - 1)) {
+ st->last_poll = jiffies;
+ if (!st->up) {
u32 sec, min, hrs, days;
sec = ntohl(cisco_data->time) / 1000;
min = sec / 60; sec -= min * 60;
hrs = min / 60; min -= hrs * 60;
days = hrs / 24; hrs -= days * 24;
- printk(KERN_INFO "%s: Link up (peer "
- "uptime %ud%uh%um%us)\n",
- dev->name, days, hrs,
- min, sec);
+ netdev_info(dev, "Link up (peer uptime %ud%uh%um%us)\n",
+ days, hrs, min, sec);
netif_dormant_off(dev);
- state(hdlc)->up = 1;
+ st->up = 1;
}
}
+ spin_unlock(&st->lock);
dev_kfree_skb_any(skb);
return NET_RX_SUCCESS;
- } /* switch(keepalive type) */
- } /* switch(protocol) */
+ } /* switch (keepalive type) */
+ } /* switch (protocol) */
- printk(KERN_INFO "%s: Unsupported protocol %x\n", dev->name,
- ntohs(data->protocol));
+ netdev_info(dev, "Unsupported protocol %x\n", ntohs(data->protocol));
dev_kfree_skb_any(skb);
return NET_RX_DROP;
- rx_error:
- dev_to_hdlc(dev)->stats.rx_errors++; /* Mark error */
+rx_error:
+ dev->stats.rx_errors++; /* Mark error */
dev_kfree_skb_any(skb);
return NET_RX_DROP;
}
@@ -261,24 +261,24 @@ static void cisco_timer(unsigned long arg)
{
struct net_device *dev = (struct net_device *)arg;
hdlc_device *hdlc = dev_to_hdlc(dev);
+ struct cisco_state *st = state(hdlc);
- if (state(hdlc)->up &&
- time_after(jiffies, state(hdlc)->last_poll +
- state(hdlc)->settings.timeout * HZ)) {
- state(hdlc)->up = 0;
- printk(KERN_INFO "%s: Link down\n", dev->name);
+ spin_lock(&st->lock);
+ if (st->up &&
+ time_after(jiffies, st->last_poll + st->settings.timeout * HZ)) {
+ st->up = 0;
+ netdev_info(dev, "Link down\n");
netif_dormant_on(dev);
}
- cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
- htonl(++state(hdlc)->txseq),
- htonl(state(hdlc)->rxseq));
- state(hdlc)->request_sent = 1;
- state(hdlc)->timer.expires = jiffies +
- state(hdlc)->settings.interval * HZ;
- state(hdlc)->timer.function = cisco_timer;
- state(hdlc)->timer.data = arg;
- add_timer(&state(hdlc)->timer);
+ cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, htonl(++st->txseq),
+ htonl(st->rxseq));
+ spin_unlock(&st->lock);
+
+ st->timer.expires = jiffies + st->settings.interval * HZ;
+ st->timer.function = cisco_timer;
+ st->timer.data = arg;
+ add_timer(&st->timer);
}
@@ -286,15 +286,18 @@ static void cisco_timer(unsigned long arg)
static void cisco_start(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- state(hdlc)->up = 0;
- state(hdlc)->request_sent = 0;
- state(hdlc)->txseq = state(hdlc)->rxseq = 0;
-
- init_timer(&state(hdlc)->timer);
- state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
- state(hdlc)->timer.function = cisco_timer;
- state(hdlc)->timer.data = (unsigned long)dev;
- add_timer(&state(hdlc)->timer);
+ struct cisco_state *st = state(hdlc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&st->lock, flags);
+ st->up = st->txseq = st->rxseq = 0;
+ spin_unlock_irqrestore(&st->lock, flags);
+
+ init_timer(&st->timer);
+ st->timer.expires = jiffies + HZ; /* First poll after 1 s */
+ st->timer.function = cisco_timer;
+ st->timer.data = (unsigned long)dev;
+ add_timer(&st->timer);
}
@@ -302,10 +305,15 @@ static void cisco_start(struct net_device *dev)
static void cisco_stop(struct net_device *dev)
{
hdlc_device *hdlc = dev_to_hdlc(dev);
- del_timer_sync(&state(hdlc)->timer);
+ struct cisco_state *st = state(hdlc);
+ unsigned long flags;
+
+ del_timer_sync(&st->timer);
+
+ spin_lock_irqsave(&st->lock, flags);
netif_dormant_on(dev);
- state(hdlc)->up = 0;
- state(hdlc)->request_sent = 0;
+ st->up = st->txseq = 0;
+ spin_unlock_irqrestore(&st->lock, flags);
}
@@ -321,7 +329,7 @@ static struct hdlc_proto proto = {
static const struct header_ops cisco_header_ops = {
.create = cisco_hard_header,
};
-
+
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
{
cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
@@ -344,10 +352,10 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return 0;
case IF_PROTO_CISCO:
- if(!capable(CAP_NET_ADMIN))
+ if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if(dev->flags & IFF_UP)
+ if (dev->flags & IFF_UP)
return -EBUSY;
if (copy_from_user(&new_settings, cisco_s, size))
@@ -357,7 +365,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
new_settings.timeout < 2)
return -EINVAL;
- result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
+ result = hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
if (result)
return result;
@@ -367,7 +375,7 @@ static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
return result;
memcpy(&state(hdlc)->settings, &new_settings, size);
- dev->hard_start_xmit = hdlc->xmit;
+ spin_lock_init(&state(hdlc)->lock);
dev->header_ops = &cisco_header_ops;
dev->type = ARPHRD_CISCO;
netif_dormant_on(dev);