* BPQ 004 Joerg(DL1BKE) Fixed to not lock up on ifconfig.
*/
-#include <linux/config.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/socket.h>
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 bpq_eth_addr[6];
-static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *);
+static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
static int bpq_device_event(struct notifier_block *, unsigned long, void *);
static const char *bpq_print_ethaddr(const unsigned char *);
};
-#define MAXBPQDEV 100
-
struct bpqdev {
struct list_head bpq_list; /* list of bpq devices chain */
struct net_device *ethdev; /* link to ethernet device */
static LIST_HEAD(bpq_devices);
+/*
+ * bpqether network devices are paired with ethernet devices below them, so
+ * form a special "super class" of normal ethernet devices; split their locks
+ * off into a separate class since they always nest.
+ */
+static struct lock_class_key bpq_netdev_xmit_lock_key;
/* ------------------------------------------------------------------------ */
*/
static inline struct net_device *bpq_get_ether_dev(struct net_device *dev)
{
- struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+ struct bpqdev *bpq = netdev_priv(dev);
return bpq ? bpq->ethdev : NULL;
}
{
struct bpqdev *bpq;
- list_for_each_entry(bpq, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpq, &bpq_devices, bpq_list) {
if (bpq->ethdev == dev)
return bpq->axdev;
}
/*
* Receive an AX.25 frame via an ethernet interface.
*/
-static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype)
+static int bpq_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *ptype, struct net_device *orig_dev)
{
int len;
char * ptr;
* we check the source address of the sender.
*/
- bpq = (struct bpqdev *)dev->priv;
+ bpq = netdev_priv(dev);
- eth = (struct ethhdr *)skb->mac.raw;
+ eth = eth_hdr(skb);
if (!(bpq->acpt_addr[0] & 0x01) &&
memcmp(eth->h_source, bpq->acpt_addr, ETH_ALEN))
ptr = skb_push(skb, 1);
*ptr = 0;
- skb->dev = dev;
- skb->protocol = htons(ETH_P_AX25);
- skb->mac.raw = skb->data;
- skb->pkt_type = PACKET_HOST;
-
+ skb->protocol = ax25_type_trans(skb, dev);
netif_rx(skb);
dev->last_rx = jiffies;
unlock:
skb = newskb;
}
- skb->protocol = htons(ETH_P_AX25);
-
ptr = skb_push(skb, 2);
*ptr++ = (size + 5) % 256;
*ptr++ = (size + 5) / 256;
- bpq = (struct bpqdev *)dev->priv;
+ bpq = netdev_priv(dev);
if ((dev = bpq_get_ether_dev(dev)) == NULL) {
bpq->stats.tx_dropped++;
return -ENODEV;
}
- skb->dev = dev;
+ skb->protocol = ax25_type_trans(skb, dev);
skb->nh.raw = skb->data;
dev->hard_header(skb, dev, ETH_P_BPQ, bpq->dest_addr, NULL, 0);
bpq->stats.tx_packets++;
*/
static struct net_device_stats *bpq_get_stats(struct net_device *dev)
{
- struct bpqdev *bpq = (struct bpqdev *) dev->priv;
+ struct bpqdev *bpq = netdev_priv(dev);
return &bpq->stats;
}
*/
static int bpq_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
{
- struct bpq_ethaddr *ethaddr = (struct bpq_ethaddr *)ifr->ifr_data;
- struct bpqdev *bpq = dev->priv;
+ struct bpq_ethaddr __user *ethaddr = ifr->ifr_data;
+ struct bpqdev *bpq = netdev_priv(dev);
struct bpq_req req;
if (!capable(CAP_NET_ADMIN))
return -EPERM;
- if (bpq == NULL) /* woops! */
- return -ENODEV;
-
switch (cmd) {
case SIOCSBPQETHOPT:
if (copy_from_user(&req, ifr->ifr_data, sizeof(struct bpq_req)))
if (*pos == 0)
return SEQ_START_TOKEN;
- list_for_each_entry(bpqdev, &bpq_devices, bpq_list) {
+ list_for_each_entry_rcu(bpqdev, &bpq_devices, bpq_list) {
if (i == *pos)
return bpqdev;
}
p = ((struct bpqdev *)v)->bpq_list.next;
return (p == &bpq_devices) ? NULL
- : list_entry(p, struct bpqdev, bpq_list);
+ : rcu_dereference(list_entry(p, struct bpqdev, bpq_list));
}
static void bpq_seq_stop(struct seq_file *seq, void *v)
dev->do_ioctl = bpq_ioctl;
dev->destructor = free_netdev;
- memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
- memcpy(dev->dev_addr, ax25_defaddr, AX25_ADDR_LEN);
+ memcpy(dev->broadcast, &ax25_bcast, AX25_ADDR_LEN);
+ memcpy(dev->dev_addr, &ax25_defaddr, AX25_ADDR_LEN);
dev->flags = 0;
#if defined(CONFIG_AX25) || defined(CONFIG_AX25_MODULE)
- dev->hard_header = ax25_encapsulate;
+ dev->hard_header = ax25_hard_header;
dev->rebuild_header = ax25_rebuild_header;
#endif
return -ENOMEM;
- bpq = ndev->priv;
+ bpq = netdev_priv(ndev);
dev_hold(edev);
bpq->ethdev = edev;
bpq->axdev = ndev;
err = register_netdevice(ndev);
if (err)
goto error;
+ lockdep_set_class(&ndev->_xmit_lock, &bpq_netdev_xmit_lock_key);
/* List protected by RTNL */
list_add_rcu(&bpq->bpq_list, &bpq_devices);
static void bpq_free_device(struct net_device *ndev)
{
- struct bpqdev *bpq = ndev->priv;
+ struct bpqdev *bpq = netdev_priv(ndev);
dev_put(bpq->ethdev);
list_del_rcu(&bpq->bpq_list);
if (!dev_is_ethdev(dev))
return NOTIFY_DONE;
- rcu_read_lock();
-
switch (event) {
case NETDEV_UP: /* new ethernet device -> new BPQ interface */
if (bpq_get_ax25_dev(dev) == NULL)
default:
break;
}
- rcu_read_unlock();
return NOTIFY_DONE;
}