Merge branch 'writeback-for-2.6.34' into nfs-for-2.6.34
This commit is contained in:
+2
-2
@@ -663,7 +663,7 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int vlan_init_net(struct net *net)
|
||||
static int __net_init vlan_init_net(struct net *net)
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
int err;
|
||||
@@ -675,7 +675,7 @@ static int vlan_init_net(struct net *net)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void vlan_exit_net(struct net *net)
|
||||
static void __net_exit vlan_exit_net(struct net *net)
|
||||
{
|
||||
vlan_proc_cleanup(net);
|
||||
}
|
||||
|
||||
+1
-1
@@ -61,7 +61,7 @@ struct vlan_dev_info {
|
||||
struct proc_dir_entry *dent;
|
||||
unsigned long cnt_inc_headroom_on_tx;
|
||||
unsigned long cnt_encap_on_xmit;
|
||||
struct vlan_rx_stats *vlan_rx_stats;
|
||||
struct vlan_rx_stats __percpu *vlan_rx_stats;
|
||||
};
|
||||
|
||||
static inline struct vlan_dev_info *vlan_dev_info(const struct net_device *dev)
|
||||
|
||||
@@ -14,6 +14,7 @@ int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
|
||||
if (skb_bond_should_drop(skb))
|
||||
goto drop;
|
||||
|
||||
skb->skb_iif = skb->dev->ifindex;
|
||||
__vlan_hwaccel_put_tag(skb, vlan_tci);
|
||||
skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
|
||||
|
||||
@@ -85,6 +86,7 @@ vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
|
||||
if (skb_bond_should_drop(skb))
|
||||
goto drop;
|
||||
|
||||
skb->skb_iif = skb->dev->ifindex;
|
||||
__vlan_hwaccel_put_tag(skb, vlan_tci);
|
||||
skb->dev = vlan_group_get_device(grp, vlan_tci & VLAN_VID_MASK);
|
||||
|
||||
|
||||
@@ -263,11 +263,10 @@ static int vlan_dev_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
vhdr->h_vlan_TCI = htons(vlan_tci);
|
||||
|
||||
/*
|
||||
* Set the protocol type. For a packet of type ETH_P_802_3 we
|
||||
* put the length in here instead. It is up to the 802.2
|
||||
* layer to carry protocol information.
|
||||
* Set the protocol type. For a packet of type ETH_P_802_3/2 we
|
||||
* put the length in here instead.
|
||||
*/
|
||||
if (type != ETH_P_802_3)
|
||||
if (type != ETH_P_802_3 && type != ETH_P_802_2)
|
||||
vhdr->h_vlan_encapsulated_proto = htons(type);
|
||||
else
|
||||
vhdr->h_vlan_encapsulated_proto = htons(len);
|
||||
@@ -323,7 +322,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
|
||||
}
|
||||
|
||||
|
||||
skb->dev = vlan_dev_info(dev)->real_dev;
|
||||
skb_set_dev(skb, vlan_dev_info(dev)->real_dev);
|
||||
len = skb->len;
|
||||
ret = dev_queue_xmit(skb);
|
||||
|
||||
|
||||
@@ -140,7 +140,7 @@ void vlan_proc_cleanup(struct net *net)
|
||||
* Create /proc/net/vlan entries
|
||||
*/
|
||||
|
||||
int vlan_proc_init(struct net *net)
|
||||
int __net_init vlan_proc_init(struct net *net)
|
||||
{
|
||||
struct vlan_net *vn = net_generic(net, vlan_net_id);
|
||||
|
||||
|
||||
@@ -144,40 +144,16 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __inline__ struct sock *atalk_get_socket_idx(loff_t pos)
|
||||
{
|
||||
struct sock *s;
|
||||
struct hlist_node *node;
|
||||
|
||||
sk_for_each(s, node, &atalk_sockets)
|
||||
if (!pos--)
|
||||
goto found;
|
||||
s = NULL;
|
||||
found:
|
||||
return s;
|
||||
}
|
||||
|
||||
static void *atalk_seq_socket_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(atalk_sockets_lock)
|
||||
{
|
||||
loff_t l = *pos;
|
||||
|
||||
read_lock_bh(&atalk_sockets_lock);
|
||||
return l ? atalk_get_socket_idx(--l) : SEQ_START_TOKEN;
|
||||
return seq_hlist_start_head(&atalk_sockets, *pos);
|
||||
}
|
||||
|
||||
static void *atalk_seq_socket_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct sock *i;
|
||||
|
||||
++*pos;
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
i = sk_head(&atalk_sockets);
|
||||
goto out;
|
||||
}
|
||||
i = sk_next(v);
|
||||
out:
|
||||
return i;
|
||||
return seq_hlist_next(v, &atalk_sockets, pos);
|
||||
}
|
||||
|
||||
static void atalk_seq_socket_stop(struct seq_file *seq, void *v)
|
||||
@@ -197,7 +173,7 @@ static int atalk_seq_socket_show(struct seq_file *seq, void *v)
|
||||
goto out;
|
||||
}
|
||||
|
||||
s = v;
|
||||
s = sk_entry(v);
|
||||
at = at_sk(s);
|
||||
|
||||
seq_printf(seq, "%02X %04X:%02X:%02X %04X:%02X:%02X %08X:%08X "
|
||||
|
||||
+1
-1
@@ -4,7 +4,7 @@
|
||||
|
||||
#include <linux/atm.h>
|
||||
#include <linux/atmdev.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "signaling.h"
|
||||
#include "addr.h"
|
||||
|
||||
+16
-24
@@ -2,37 +2,35 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL ICA */
|
||||
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/atm.h>
|
||||
#include <linux/atmdev.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/sonet.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/errno.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/errno.h>
|
||||
|
||||
|
||||
int atm_charge(struct atm_vcc *vcc,int truesize)
|
||||
int atm_charge(struct atm_vcc *vcc, int truesize)
|
||||
{
|
||||
atm_force_charge(vcc,truesize);
|
||||
atm_force_charge(vcc, truesize);
|
||||
if (atomic_read(&sk_atm(vcc)->sk_rmem_alloc) <= sk_atm(vcc)->sk_rcvbuf)
|
||||
return 1;
|
||||
atm_return(vcc,truesize);
|
||||
atm_return(vcc, truesize);
|
||||
atomic_inc(&vcc->stats->rx_drop);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atm_charge);
|
||||
|
||||
|
||||
struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
|
||||
gfp_t gfp_flags)
|
||||
struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc, int pdu_size,
|
||||
gfp_t gfp_flags)
|
||||
{
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
int guess = atm_guess_pdu2truesize(pdu_size);
|
||||
|
||||
atm_force_charge(vcc,guess);
|
||||
atm_force_charge(vcc, guess);
|
||||
if (atomic_read(&sk->sk_rmem_alloc) <= sk->sk_rcvbuf) {
|
||||
struct sk_buff *skb = alloc_skb(pdu_size,gfp_flags);
|
||||
struct sk_buff *skb = alloc_skb(pdu_size, gfp_flags);
|
||||
|
||||
if (skb) {
|
||||
atomic_add(skb->truesize-guess,
|
||||
@@ -40,10 +38,11 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
|
||||
return skb;
|
||||
}
|
||||
}
|
||||
atm_return(vcc,guess);
|
||||
atm_return(vcc, guess);
|
||||
atomic_inc(&vcc->stats->rx_drop);
|
||||
return NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(atm_alloc_charge);
|
||||
|
||||
|
||||
/*
|
||||
@@ -73,7 +72,6 @@ struct sk_buff *atm_alloc_charge(struct atm_vcc *vcc,int pdu_size,
|
||||
* else *
|
||||
*/
|
||||
|
||||
|
||||
int atm_pcr_goal(const struct atm_trafprm *tp)
|
||||
{
|
||||
if (tp->pcr && tp->pcr != ATM_MAX_PCR)
|
||||
@@ -84,26 +82,20 @@ int atm_pcr_goal(const struct atm_trafprm *tp)
|
||||
return -tp->max_pcr;
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(atm_pcr_goal);
|
||||
|
||||
|
||||
void sonet_copy_stats(struct k_sonet_stats *from,struct sonet_stats *to)
|
||||
void sonet_copy_stats(struct k_sonet_stats *from, struct sonet_stats *to)
|
||||
{
|
||||
#define __HANDLE_ITEM(i) to->i = atomic_read(&from->i)
|
||||
__SONET_ITEMS
|
||||
#undef __HANDLE_ITEM
|
||||
}
|
||||
EXPORT_SYMBOL(sonet_copy_stats);
|
||||
|
||||
|
||||
void sonet_subtract_stats(struct k_sonet_stats *from,struct sonet_stats *to)
|
||||
void sonet_subtract_stats(struct k_sonet_stats *from, struct sonet_stats *to)
|
||||
{
|
||||
#define __HANDLE_ITEM(i) atomic_sub(to->i,&from->i)
|
||||
#define __HANDLE_ITEM(i) atomic_sub(to->i, &from->i)
|
||||
__SONET_ITEMS
|
||||
#undef __HANDLE_ITEM
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(atm_charge);
|
||||
EXPORT_SYMBOL(atm_alloc_charge);
|
||||
EXPORT_SYMBOL(atm_pcr_goal);
|
||||
EXPORT_SYMBOL(sonet_copy_stats);
|
||||
EXPORT_SYMBOL(sonet_subtract_stats);
|
||||
|
||||
+14
-13
@@ -42,13 +42,14 @@ static ssize_t show_atmaddress(struct device *cdev,
|
||||
|
||||
spin_lock_irqsave(&adev->lock, flags);
|
||||
list_for_each_entry(aaddr, &adev->local, entry) {
|
||||
for(i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
|
||||
for (i = 0, j = 0; i < ATM_ESA_LEN; ++i, ++j) {
|
||||
if (j == *fmt) {
|
||||
pos += sprintf(pos, ".");
|
||||
++fmt;
|
||||
j = 0;
|
||||
}
|
||||
pos += sprintf(pos, "%02x", aaddr->addr.sas_addr.prv[i]);
|
||||
pos += sprintf(pos, "%02x",
|
||||
aaddr->addr.sas_addr.prv[i]);
|
||||
}
|
||||
pos += sprintf(pos, "\n");
|
||||
}
|
||||
@@ -78,17 +79,17 @@ static ssize_t show_link_rate(struct device *cdev,
|
||||
|
||||
/* show the link rate, not the data rate */
|
||||
switch (adev->link_rate) {
|
||||
case ATM_OC3_PCR:
|
||||
link_rate = 155520000;
|
||||
break;
|
||||
case ATM_OC12_PCR:
|
||||
link_rate = 622080000;
|
||||
break;
|
||||
case ATM_25_PCR:
|
||||
link_rate = 25600000;
|
||||
break;
|
||||
default:
|
||||
link_rate = adev->link_rate * 8 * 53;
|
||||
case ATM_OC3_PCR:
|
||||
link_rate = 155520000;
|
||||
break;
|
||||
case ATM_OC12_PCR:
|
||||
link_rate = 622080000;
|
||||
break;
|
||||
case ATM_25_PCR:
|
||||
link_rate = 25600000;
|
||||
break;
|
||||
default:
|
||||
link_rate = adev->link_rate * 8 * 53;
|
||||
}
|
||||
pos += sprintf(pos, "%d\n", link_rate);
|
||||
|
||||
|
||||
+40
-50
@@ -6,6 +6,8 @@
|
||||
* Eric Kinzie, 2006-2007, US Naval Research Laboratory
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -15,7 +17,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/ip.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <net/arp.h>
|
||||
#include <linux/atm.h>
|
||||
#include <linux/atmdev.h>
|
||||
@@ -26,20 +28,14 @@
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef SKB_DEBUG
|
||||
static void skb_debug(const struct sk_buff *skb)
|
||||
{
|
||||
#ifdef SKB_DEBUG
|
||||
#define NUM2PRINT 50
|
||||
char buf[NUM2PRINT * 3 + 1]; /* 3 chars per byte */
|
||||
int i = 0;
|
||||
for (i = 0; i < skb->len && i < NUM2PRINT; i++) {
|
||||
sprintf(buf + i * 3, "%2.2x ", 0xff & skb->data[i]);
|
||||
}
|
||||
printk(KERN_DEBUG "br2684: skb: %s\n", buf);
|
||||
}
|
||||
#else
|
||||
#define skb_debug(skb) do {} while (0)
|
||||
print_hex_dump(KERN_DEBUG, "br2684: skb: ", DUMP_OFFSET,
|
||||
16, 1, skb->data, min(NUM2PRINT, skb->len), true);
|
||||
#endif
|
||||
}
|
||||
|
||||
#define BR2684_ETHERTYPE_LEN 2
|
||||
#define BR2684_PAD_LEN 2
|
||||
@@ -68,7 +64,7 @@ struct br2684_vcc {
|
||||
struct atm_vcc *atmvcc;
|
||||
struct net_device *device;
|
||||
/* keep old push, pop functions for chaining */
|
||||
void (*old_push) (struct atm_vcc * vcc, struct sk_buff * skb);
|
||||
void (*old_push)(struct atm_vcc *vcc, struct sk_buff *skb);
|
||||
void (*old_pop)(struct atm_vcc *vcc, struct sk_buff *skb);
|
||||
enum br2684_encaps encaps;
|
||||
struct list_head brvccs;
|
||||
@@ -148,7 +144,7 @@ static void br2684_pop(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
struct br2684_vcc *brvcc = BR2684_VCC(vcc);
|
||||
struct net_device *net_dev = skb->dev;
|
||||
|
||||
pr_debug("br2684_pop(vcc %p ; net_dev %p )\n", vcc, net_dev);
|
||||
pr_debug("(vcc %p ; net_dev %p )\n", vcc, net_dev);
|
||||
brvcc->old_pop(vcc, skb);
|
||||
|
||||
if (!net_dev)
|
||||
@@ -244,7 +240,7 @@ static netdev_tx_t br2684_start_xmit(struct sk_buff *skb,
|
||||
struct br2684_dev *brdev = BRPRIV(dev);
|
||||
struct br2684_vcc *brvcc;
|
||||
|
||||
pr_debug("br2684_start_xmit, skb_dst(skb)=%p\n", skb_dst(skb));
|
||||
pr_debug("skb_dst(skb)=%p\n", skb_dst(skb));
|
||||
read_lock(&devs_lock);
|
||||
brvcc = pick_outgoing_vcc(skb, brdev);
|
||||
if (brvcc == NULL) {
|
||||
@@ -300,7 +296,8 @@ static int br2684_setfilt(struct atm_vcc *atmvcc, void __user * arg)
|
||||
struct br2684_dev *brdev;
|
||||
read_lock(&devs_lock);
|
||||
brdev = BRPRIV(br2684_find_dev(&fs.ifspec));
|
||||
if (brdev == NULL || list_empty(&brdev->brvccs) || brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */
|
||||
if (brdev == NULL || list_empty(&brdev->brvccs) ||
|
||||
brdev->brvccs.next != brdev->brvccs.prev) /* >1 VCC */
|
||||
brvcc = NULL;
|
||||
else
|
||||
brvcc = list_entry_brvcc(brdev->brvccs.next);
|
||||
@@ -352,7 +349,7 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||
struct net_device *net_dev = brvcc->device;
|
||||
struct br2684_dev *brdev = BRPRIV(net_dev);
|
||||
|
||||
pr_debug("br2684_push\n");
|
||||
pr_debug("\n");
|
||||
|
||||
if (unlikely(skb == NULL)) {
|
||||
/* skb==NULL means VCC is being destroyed */
|
||||
@@ -376,29 +373,25 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||
__skb_trim(skb, skb->len - 4);
|
||||
|
||||
/* accept packets that have "ipv[46]" in the snap header */
|
||||
if ((skb->len >= (sizeof(llc_oui_ipv4)))
|
||||
&&
|
||||
(memcmp
|
||||
(skb->data, llc_oui_ipv4,
|
||||
sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) {
|
||||
if (memcmp
|
||||
(skb->data + 6, ethertype_ipv6,
|
||||
sizeof(ethertype_ipv6)) == 0)
|
||||
if ((skb->len >= (sizeof(llc_oui_ipv4))) &&
|
||||
(memcmp(skb->data, llc_oui_ipv4,
|
||||
sizeof(llc_oui_ipv4) - BR2684_ETHERTYPE_LEN) == 0)) {
|
||||
if (memcmp(skb->data + 6, ethertype_ipv6,
|
||||
sizeof(ethertype_ipv6)) == 0)
|
||||
skb->protocol = htons(ETH_P_IPV6);
|
||||
else if (memcmp
|
||||
(skb->data + 6, ethertype_ipv4,
|
||||
sizeof(ethertype_ipv4)) == 0)
|
||||
else if (memcmp(skb->data + 6, ethertype_ipv4,
|
||||
sizeof(ethertype_ipv4)) == 0)
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
else
|
||||
goto error;
|
||||
skb_pull(skb, sizeof(llc_oui_ipv4));
|
||||
skb_reset_network_header(skb);
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
/*
|
||||
* Let us waste some time for checking the encapsulation.
|
||||
* Note, that only 7 char is checked so frames with a valid FCS
|
||||
* are also accepted (but FCS is not checked of course).
|
||||
*/
|
||||
/*
|
||||
* Let us waste some time for checking the encapsulation.
|
||||
* Note, that only 7 char is checked so frames with a valid FCS
|
||||
* are also accepted (but FCS is not checked of course).
|
||||
*/
|
||||
} else if ((skb->len >= sizeof(llc_oui_pid_pad)) &&
|
||||
(memcmp(skb->data, llc_oui_pid_pad, 7) == 0)) {
|
||||
skb_pull(skb, sizeof(llc_oui_pid_pad));
|
||||
@@ -479,8 +472,7 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
|
||||
write_lock_irq(&devs_lock);
|
||||
net_dev = br2684_find_dev(&be.ifspec);
|
||||
if (net_dev == NULL) {
|
||||
printk(KERN_ERR
|
||||
"br2684: tried to attach to non-existant device\n");
|
||||
pr_err("tried to attach to non-existant device\n");
|
||||
err = -ENXIO;
|
||||
goto error;
|
||||
}
|
||||
@@ -494,17 +486,16 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
|
||||
err = -EEXIST;
|
||||
goto error;
|
||||
}
|
||||
if (be.fcs_in != BR2684_FCSIN_NO || be.fcs_out != BR2684_FCSOUT_NO ||
|
||||
be.fcs_auto || be.has_vpiid || be.send_padding || (be.encaps !=
|
||||
BR2684_ENCAPS_VC
|
||||
&& be.encaps !=
|
||||
BR2684_ENCAPS_LLC)
|
||||
|| be.min_size != 0) {
|
||||
if (be.fcs_in != BR2684_FCSIN_NO ||
|
||||
be.fcs_out != BR2684_FCSOUT_NO ||
|
||||
be.fcs_auto || be.has_vpiid || be.send_padding ||
|
||||
(be.encaps != BR2684_ENCAPS_VC &&
|
||||
be.encaps != BR2684_ENCAPS_LLC) ||
|
||||
be.min_size != 0) {
|
||||
err = -EINVAL;
|
||||
goto error;
|
||||
}
|
||||
pr_debug("br2684_regvcc vcc=%p, encaps=%d, brvcc=%p\n", atmvcc,
|
||||
be.encaps, brvcc);
|
||||
pr_debug("vcc=%p, encaps=%d, brvcc=%p\n", atmvcc, be.encaps, brvcc);
|
||||
if (list_empty(&brdev->brvccs) && !brdev->mac_was_set) {
|
||||
unsigned char *esi = atmvcc->dev->esi;
|
||||
if (esi[0] | esi[1] | esi[2] | esi[3] | esi[4] | esi[5])
|
||||
@@ -541,7 +532,8 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
|
||||
}
|
||||
__module_get(THIS_MODULE);
|
||||
return 0;
|
||||
error:
|
||||
|
||||
error:
|
||||
write_unlock_irq(&devs_lock);
|
||||
kfree(brvcc);
|
||||
return err;
|
||||
@@ -587,7 +579,7 @@ static void br2684_setup_routed(struct net_device *netdev)
|
||||
INIT_LIST_HEAD(&brdev->brvccs);
|
||||
}
|
||||
|
||||
static int br2684_create(void __user * arg)
|
||||
static int br2684_create(void __user *arg)
|
||||
{
|
||||
int err;
|
||||
struct net_device *netdev;
|
||||
@@ -595,11 +587,10 @@ static int br2684_create(void __user * arg)
|
||||
struct atm_newif_br2684 ni;
|
||||
enum br2684_payload payload;
|
||||
|
||||
pr_debug("br2684_create\n");
|
||||
pr_debug("\n");
|
||||
|
||||
if (copy_from_user(&ni, arg, sizeof ni)) {
|
||||
if (copy_from_user(&ni, arg, sizeof ni))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
if (ni.media & BR2684_FLAG_ROUTED)
|
||||
payload = p_routed;
|
||||
@@ -607,9 +598,8 @@ static int br2684_create(void __user * arg)
|
||||
payload = p_bridged;
|
||||
ni.media &= 0xffff; /* strip flags */
|
||||
|
||||
if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500) {
|
||||
if (ni.media != BR2684_MEDIA_ETHERNET || ni.mtu != 1500)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
netdev = alloc_netdev(sizeof(struct br2684_dev),
|
||||
ni.ifname[0] ? ni.ifname : "nas%d",
|
||||
@@ -624,7 +614,7 @@ static int br2684_create(void __user * arg)
|
||||
/* open, stop, do_ioctl ? */
|
||||
err = register_netdev(netdev);
|
||||
if (err < 0) {
|
||||
printk(KERN_ERR "br2684_create: register_netdev failed\n");
|
||||
pr_err("register_netdev failed\n");
|
||||
free_netdev(netdev);
|
||||
return err;
|
||||
}
|
||||
|
||||
+41
-45
@@ -2,6 +2,8 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h> /* for UINT_MAX */
|
||||
@@ -30,10 +32,10 @@
|
||||
#include <linux/jhash.h>
|
||||
#include <net/route.h> /* for struct rtable and routing */
|
||||
#include <net/icmp.h> /* icmp_send */
|
||||
#include <asm/param.h> /* for HZ */
|
||||
#include <linux/param.h> /* for HZ */
|
||||
#include <linux/uaccess.h>
|
||||
#include <asm/byteorder.h> /* for htons etc. */
|
||||
#include <asm/system.h> /* save/restore_flags */
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/atomic.h>
|
||||
|
||||
#include "common.h"
|
||||
@@ -51,13 +53,13 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
|
||||
struct atmarp_ctrl *ctrl;
|
||||
struct sk_buff *skb;
|
||||
|
||||
pr_debug("to_atmarpd(%d)\n", type);
|
||||
pr_debug("(%d)\n", type);
|
||||
if (!atmarpd)
|
||||
return -EUNATCH;
|
||||
skb = alloc_skb(sizeof(struct atmarp_ctrl),GFP_ATOMIC);
|
||||
skb = alloc_skb(sizeof(struct atmarp_ctrl), GFP_ATOMIC);
|
||||
if (!skb)
|
||||
return -ENOMEM;
|
||||
ctrl = (struct atmarp_ctrl *) skb_put(skb,sizeof(struct atmarp_ctrl));
|
||||
ctrl = (struct atmarp_ctrl *)skb_put(skb, sizeof(struct atmarp_ctrl));
|
||||
ctrl->type = type;
|
||||
ctrl->itf_num = itf;
|
||||
ctrl->ip = ip;
|
||||
@@ -71,8 +73,7 @@ static int to_atmarpd(enum atmarp_ctrl_type type, int itf, __be32 ip)
|
||||
|
||||
static void link_vcc(struct clip_vcc *clip_vcc, struct atmarp_entry *entry)
|
||||
{
|
||||
pr_debug("link_vcc %p to entry %p (neigh %p)\n", clip_vcc, entry,
|
||||
entry->neigh);
|
||||
pr_debug("%p to entry %p (neigh %p)\n", clip_vcc, entry, entry->neigh);
|
||||
clip_vcc->entry = entry;
|
||||
clip_vcc->xoff = 0; /* @@@ may overrun buffer by one packet */
|
||||
clip_vcc->next = entry->vccs;
|
||||
@@ -86,7 +87,7 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
|
||||
struct clip_vcc **walk;
|
||||
|
||||
if (!entry) {
|
||||
printk(KERN_CRIT "!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
|
||||
pr_crit("!clip_vcc->entry (clip_vcc %p)\n", clip_vcc);
|
||||
return;
|
||||
}
|
||||
netif_tx_lock_bh(entry->neigh->dev); /* block clip_start_xmit() */
|
||||
@@ -106,13 +107,11 @@ static void unlink_clip_vcc(struct clip_vcc *clip_vcc)
|
||||
error = neigh_update(entry->neigh, NULL, NUD_NONE,
|
||||
NEIGH_UPDATE_F_ADMIN);
|
||||
if (error)
|
||||
printk(KERN_CRIT "unlink_clip_vcc: "
|
||||
"neigh_update failed with %d\n", error);
|
||||
pr_crit("neigh_update failed with %d\n", error);
|
||||
goto out;
|
||||
}
|
||||
printk(KERN_CRIT "ATMARP: unlink_clip_vcc failed (entry %p, vcc "
|
||||
"0x%p)\n", entry, clip_vcc);
|
||||
out:
|
||||
pr_crit("ATMARP: failed (entry %p, vcc 0x%p)\n", entry, clip_vcc);
|
||||
out:
|
||||
netif_tx_unlock_bh(entry->neigh->dev);
|
||||
}
|
||||
|
||||
@@ -127,7 +126,7 @@ static int neigh_check_cb(struct neighbour *n)
|
||||
|
||||
if (cv->idle_timeout && time_after(jiffies, exp)) {
|
||||
pr_debug("releasing vcc %p->%p of entry %p\n",
|
||||
cv, cv->vcc, entry);
|
||||
cv, cv->vcc, entry);
|
||||
vcc_release_async(cv->vcc, -ETIMEDOUT);
|
||||
}
|
||||
}
|
||||
@@ -139,7 +138,7 @@ static int neigh_check_cb(struct neighbour *n)
|
||||
struct sk_buff *skb;
|
||||
|
||||
pr_debug("destruction postponed with ref %d\n",
|
||||
atomic_read(&n->refcnt));
|
||||
atomic_read(&n->refcnt));
|
||||
|
||||
while ((skb = skb_dequeue(&n->arp_queue)) != NULL)
|
||||
dev_kfree_skb(skb);
|
||||
@@ -163,7 +162,7 @@ static int clip_arp_rcv(struct sk_buff *skb)
|
||||
{
|
||||
struct atm_vcc *vcc;
|
||||
|
||||
pr_debug("clip_arp_rcv\n");
|
||||
pr_debug("\n");
|
||||
vcc = ATM_SKB(skb)->vcc;
|
||||
if (!vcc || !atm_charge(vcc, skb->truesize)) {
|
||||
dev_kfree_skb_any(skb);
|
||||
@@ -188,7 +187,7 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
|
||||
|
||||
pr_debug("clip push\n");
|
||||
pr_debug("\n");
|
||||
if (!skb) {
|
||||
pr_debug("removing VCC %p\n", clip_vcc);
|
||||
if (clip_vcc->entry)
|
||||
@@ -206,12 +205,12 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
}
|
||||
ATM_SKB(skb)->vcc = vcc;
|
||||
skb_reset_mac_header(skb);
|
||||
if (!clip_vcc->encap
|
||||
|| skb->len < RFC1483LLC_LEN
|
||||
|| memcmp(skb->data, llc_oui, sizeof (llc_oui)))
|
||||
if (!clip_vcc->encap ||
|
||||
skb->len < RFC1483LLC_LEN ||
|
||||
memcmp(skb->data, llc_oui, sizeof(llc_oui)))
|
||||
skb->protocol = htons(ETH_P_IP);
|
||||
else {
|
||||
skb->protocol = ((__be16 *) skb->data)[3];
|
||||
skb->protocol = ((__be16 *)skb->data)[3];
|
||||
skb_pull(skb, RFC1483LLC_LEN);
|
||||
if (skb->protocol == htons(ETH_P_ARP)) {
|
||||
skb->dev->stats.rx_packets++;
|
||||
@@ -239,7 +238,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
int old;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("clip_pop(vcc %p)\n", vcc);
|
||||
pr_debug("(vcc %p)\n", vcc);
|
||||
clip_vcc->old_pop(vcc, skb);
|
||||
/* skb->dev == NULL in outbound ARP packets */
|
||||
if (!dev)
|
||||
@@ -255,7 +254,7 @@ static void clip_pop(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
|
||||
static void clip_neigh_solicit(struct neighbour *neigh, struct sk_buff *skb)
|
||||
{
|
||||
pr_debug("clip_neigh_solicit (neigh %p, skb %p)\n", neigh, skb);
|
||||
pr_debug("(neigh %p, skb %p)\n", neigh, skb);
|
||||
to_atmarpd(act_need, PRIV(neigh->dev)->number, NEIGH2ENTRY(neigh)->ip);
|
||||
}
|
||||
|
||||
@@ -284,7 +283,7 @@ static int clip_constructor(struct neighbour *neigh)
|
||||
struct in_device *in_dev;
|
||||
struct neigh_parms *parms;
|
||||
|
||||
pr_debug("clip_constructor (neigh %p, entry %p)\n", neigh, entry);
|
||||
pr_debug("(neigh %p, entry %p)\n", neigh, entry);
|
||||
neigh->type = inet_addr_type(&init_net, entry->ip);
|
||||
if (neigh->type != RTN_UNICAST)
|
||||
return -EINVAL;
|
||||
@@ -369,9 +368,9 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
|
||||
int old;
|
||||
unsigned long flags;
|
||||
|
||||
pr_debug("clip_start_xmit (skb %p)\n", skb);
|
||||
pr_debug("(skb %p)\n", skb);
|
||||
if (!skb_dst(skb)) {
|
||||
printk(KERN_ERR "clip_start_xmit: skb_dst(skb) == NULL\n");
|
||||
pr_err("skb_dst(skb) == NULL\n");
|
||||
dev_kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
@@ -385,7 +384,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
|
||||
pr_err("NO NEIGHBOUR !\n");
|
||||
dev_kfree_skb(skb);
|
||||
dev->stats.tx_dropped++;
|
||||
return NETDEV_TX_OK;
|
||||
@@ -421,7 +420,7 @@ static netdev_tx_t clip_start_xmit(struct sk_buff *skb,
|
||||
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, vcc, vcc->dev);
|
||||
old = xchg(&entry->vccs->xoff, 1); /* assume XOFF ... */
|
||||
if (old) {
|
||||
printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
|
||||
pr_warning("XOFF->XOFF transition\n");
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
dev->stats.tx_packets++;
|
||||
@@ -456,7 +455,7 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
|
||||
clip_vcc = kmalloc(sizeof(struct clip_vcc), GFP_KERNEL);
|
||||
if (!clip_vcc)
|
||||
return -ENOMEM;
|
||||
pr_debug("mkip clip_vcc %p vcc %p\n", clip_vcc, vcc);
|
||||
pr_debug("%p vcc %p\n", clip_vcc, vcc);
|
||||
clip_vcc->vcc = vcc;
|
||||
vcc->user_back = clip_vcc;
|
||||
set_bit(ATM_VF_IS_CLIP, &vcc->flags);
|
||||
@@ -506,16 +505,16 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
|
||||
struct rtable *rt;
|
||||
|
||||
if (vcc->push != clip_push) {
|
||||
printk(KERN_WARNING "clip_setentry: non-CLIP VCC\n");
|
||||
pr_warning("non-CLIP VCC\n");
|
||||
return -EBADF;
|
||||
}
|
||||
clip_vcc = CLIP_VCC(vcc);
|
||||
if (!ip) {
|
||||
if (!clip_vcc->entry) {
|
||||
printk(KERN_ERR "hiding hidden ATMARP entry\n");
|
||||
pr_err("hiding hidden ATMARP entry\n");
|
||||
return 0;
|
||||
}
|
||||
pr_debug("setentry: remove\n");
|
||||
pr_debug("remove\n");
|
||||
unlink_clip_vcc(clip_vcc);
|
||||
return 0;
|
||||
}
|
||||
@@ -529,9 +528,9 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
|
||||
entry = NEIGH2ENTRY(neigh);
|
||||
if (entry != clip_vcc->entry) {
|
||||
if (!clip_vcc->entry)
|
||||
pr_debug("setentry: add\n");
|
||||
pr_debug("add\n");
|
||||
else {
|
||||
pr_debug("setentry: update\n");
|
||||
pr_debug("update\n");
|
||||
unlink_clip_vcc(clip_vcc);
|
||||
}
|
||||
link_vcc(clip_vcc, entry);
|
||||
@@ -614,16 +613,16 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UP:
|
||||
pr_debug("clip_device_event NETDEV_UP\n");
|
||||
pr_debug("NETDEV_UP\n");
|
||||
to_atmarpd(act_up, PRIV(dev)->number, 0);
|
||||
break;
|
||||
case NETDEV_GOING_DOWN:
|
||||
pr_debug("clip_device_event NETDEV_DOWN\n");
|
||||
pr_debug("NETDEV_DOWN\n");
|
||||
to_atmarpd(act_down, PRIV(dev)->number, 0);
|
||||
break;
|
||||
case NETDEV_CHANGE:
|
||||
case NETDEV_CHANGEMTU:
|
||||
pr_debug("clip_device_event NETDEV_CHANGE*\n");
|
||||
pr_debug("NETDEV_CHANGE*\n");
|
||||
to_atmarpd(act_change, PRIV(dev)->number, 0);
|
||||
break;
|
||||
}
|
||||
@@ -645,7 +644,6 @@ static int clip_inet_event(struct notifier_block *this, unsigned long event,
|
||||
return clip_device_event(this, NETDEV_CHANGE, in_dev->dev);
|
||||
}
|
||||
|
||||
|
||||
static struct notifier_block clip_dev_notifier = {
|
||||
.notifier_call = clip_device_event,
|
||||
};
|
||||
@@ -660,7 +658,7 @@ static struct notifier_block clip_inet_notifier = {
|
||||
|
||||
static void atmarpd_close(struct atm_vcc *vcc)
|
||||
{
|
||||
pr_debug("atmarpd_close\n");
|
||||
pr_debug("\n");
|
||||
|
||||
rtnl_lock();
|
||||
atmarpd = NULL;
|
||||
@@ -671,7 +669,6 @@ static void atmarpd_close(struct atm_vcc *vcc)
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
|
||||
static struct atmdev_ops atmarpd_dev_ops = {
|
||||
.close = atmarpd_close
|
||||
};
|
||||
@@ -693,11 +690,11 @@ static int atm_init_atmarp(struct atm_vcc *vcc)
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
|
||||
mod_timer(&idle_timer, jiffies+CLIP_CHECK_INTERVAL*HZ);
|
||||
mod_timer(&idle_timer, jiffies + CLIP_CHECK_INTERVAL * HZ);
|
||||
|
||||
atmarpd = vcc;
|
||||
set_bit(ATM_VF_META,&vcc->flags);
|
||||
set_bit(ATM_VF_READY,&vcc->flags);
|
||||
set_bit(ATM_VF_META, &vcc->flags);
|
||||
set_bit(ATM_VF_READY, &vcc->flags);
|
||||
/* allow replies and avoid getting closed if signaling dies */
|
||||
vcc->dev = &atmarpd_dev;
|
||||
vcc_insert_socket(sk_atm(vcc));
|
||||
@@ -950,8 +947,7 @@ static int __init atm_clip_init(void)
|
||||
|
||||
p = proc_create("arp", S_IRUGO, atm_proc_root, &arp_seq_fops);
|
||||
if (!p) {
|
||||
printk(KERN_ERR "Unable to initialize "
|
||||
"/proc/net/atm/arp\n");
|
||||
pr_err("Unable to initialize /proc/net/atm/arp\n");
|
||||
atm_clip_exit_noproc();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
+198
-184
@@ -2,6 +2,7 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
@@ -18,11 +19,10 @@
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/init.h>
|
||||
#include <net/sock.h> /* struct sock */
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/poll.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/poll.h>
|
||||
|
||||
|
||||
#include "resources.h" /* atm_find_dev */
|
||||
#include "common.h" /* prototypes */
|
||||
@@ -31,13 +31,15 @@
|
||||
#include "signaling.h" /* for WAITING and sigd_attach */
|
||||
|
||||
struct hlist_head vcc_hash[VCC_HTABLE_SIZE];
|
||||
EXPORT_SYMBOL(vcc_hash);
|
||||
|
||||
DEFINE_RWLOCK(vcc_sklist_lock);
|
||||
EXPORT_SYMBOL(vcc_sklist_lock);
|
||||
|
||||
static void __vcc_insert_socket(struct sock *sk)
|
||||
{
|
||||
struct atm_vcc *vcc = atm_sk(sk);
|
||||
struct hlist_head *head = &vcc_hash[vcc->vci &
|
||||
(VCC_HTABLE_SIZE - 1)];
|
||||
struct hlist_head *head = &vcc_hash[vcc->vci & (VCC_HTABLE_SIZE - 1)];
|
||||
sk->sk_hash = vcc->vci & (VCC_HTABLE_SIZE - 1);
|
||||
sk_add_node(sk, head);
|
||||
}
|
||||
@@ -48,6 +50,7 @@ void vcc_insert_socket(struct sock *sk)
|
||||
__vcc_insert_socket(sk);
|
||||
write_unlock_irq(&vcc_sklist_lock);
|
||||
}
|
||||
EXPORT_SYMBOL(vcc_insert_socket);
|
||||
|
||||
static void vcc_remove_socket(struct sock *sk)
|
||||
{
|
||||
@@ -56,37 +59,32 @@ static void vcc_remove_socket(struct sock *sk)
|
||||
write_unlock_irq(&vcc_sklist_lock);
|
||||
}
|
||||
|
||||
|
||||
static struct sk_buff *alloc_tx(struct atm_vcc *vcc,unsigned int size)
|
||||
static struct sk_buff *alloc_tx(struct atm_vcc *vcc, unsigned int size)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
|
||||
if (sk_wmem_alloc_get(sk) && !atm_may_send(vcc, size)) {
|
||||
pr_debug("Sorry: wmem_alloc = %d, size = %d, sndbuf = %d\n",
|
||||
sk_wmem_alloc_get(sk), size,
|
||||
sk->sk_sndbuf);
|
||||
sk_wmem_alloc_get(sk), size, sk->sk_sndbuf);
|
||||
return NULL;
|
||||
}
|
||||
while (!(skb = alloc_skb(size, GFP_KERNEL)))
|
||||
schedule();
|
||||
pr_debug("AlTx %d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
|
||||
pr_debug("%d += %d\n", sk_wmem_alloc_get(sk), skb->truesize);
|
||||
atomic_add(skb->truesize, &sk->sk_wmem_alloc);
|
||||
return skb;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(vcc_hash);
|
||||
EXPORT_SYMBOL(vcc_sklist_lock);
|
||||
EXPORT_SYMBOL(vcc_insert_socket);
|
||||
|
||||
static void vcc_sock_destruct(struct sock *sk)
|
||||
{
|
||||
if (atomic_read(&sk->sk_rmem_alloc))
|
||||
printk(KERN_DEBUG "vcc_sock_destruct: rmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_rmem_alloc));
|
||||
printk(KERN_DEBUG "%s: rmem leakage (%d bytes) detected.\n",
|
||||
__func__, atomic_read(&sk->sk_rmem_alloc));
|
||||
|
||||
if (atomic_read(&sk->sk_wmem_alloc))
|
||||
printk(KERN_DEBUG "vcc_sock_destruct: wmem leakage (%d bytes) detected.\n", atomic_read(&sk->sk_wmem_alloc));
|
||||
printk(KERN_DEBUG "%s: wmem leakage (%d bytes) detected.\n",
|
||||
__func__, atomic_read(&sk->sk_wmem_alloc));
|
||||
}
|
||||
|
||||
static void vcc_def_wakeup(struct sock *sk)
|
||||
@@ -142,8 +140,8 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)
|
||||
|
||||
vcc = atm_sk(sk);
|
||||
vcc->dev = NULL;
|
||||
memset(&vcc->local,0,sizeof(struct sockaddr_atmsvc));
|
||||
memset(&vcc->remote,0,sizeof(struct sockaddr_atmsvc));
|
||||
memset(&vcc->local, 0, sizeof(struct sockaddr_atmsvc));
|
||||
memset(&vcc->remote, 0, sizeof(struct sockaddr_atmsvc));
|
||||
vcc->qos.txtp.max_sdu = 1 << 16; /* for meta VCs */
|
||||
atomic_set(&sk->sk_wmem_alloc, 1);
|
||||
atomic_set(&sk->sk_rmem_alloc, 0);
|
||||
@@ -156,7 +154,6 @@ int vcc_create(struct net *net, struct socket *sock, int protocol, int family)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void vcc_destroy_socket(struct sock *sk)
|
||||
{
|
||||
struct atm_vcc *vcc = atm_sk(sk);
|
||||
@@ -171,7 +168,7 @@ static void vcc_destroy_socket(struct sock *sk)
|
||||
vcc->push(vcc, NULL); /* atmarpd has no push */
|
||||
|
||||
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
|
||||
atm_return(vcc,skb->truesize);
|
||||
atm_return(vcc, skb->truesize);
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
@@ -182,7 +179,6 @@ static void vcc_destroy_socket(struct sock *sk)
|
||||
vcc_remove_socket(sk);
|
||||
}
|
||||
|
||||
|
||||
int vcc_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -197,7 +193,6 @@ int vcc_release(struct socket *sock)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void vcc_release_async(struct atm_vcc *vcc, int reply)
|
||||
{
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
@@ -208,8 +203,6 @@ void vcc_release_async(struct atm_vcc *vcc, int reply)
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
sk->sk_state_change(sk);
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(vcc_release_async);
|
||||
|
||||
|
||||
@@ -235,37 +228,37 @@ void atm_dev_release_vccs(struct atm_dev *dev)
|
||||
write_unlock_irq(&vcc_sklist_lock);
|
||||
}
|
||||
|
||||
|
||||
static int adjust_tp(struct atm_trafprm *tp,unsigned char aal)
|
||||
static int adjust_tp(struct atm_trafprm *tp, unsigned char aal)
|
||||
{
|
||||
int max_sdu;
|
||||
|
||||
if (!tp->traffic_class) return 0;
|
||||
if (!tp->traffic_class)
|
||||
return 0;
|
||||
switch (aal) {
|
||||
case ATM_AAL0:
|
||||
max_sdu = ATM_CELL_SIZE-1;
|
||||
break;
|
||||
case ATM_AAL34:
|
||||
max_sdu = ATM_MAX_AAL34_PDU;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_WARNING "ATM: AAL problems ... "
|
||||
"(%d)\n",aal);
|
||||
/* fall through */
|
||||
case ATM_AAL5:
|
||||
max_sdu = ATM_MAX_AAL5_PDU;
|
||||
case ATM_AAL0:
|
||||
max_sdu = ATM_CELL_SIZE-1;
|
||||
break;
|
||||
case ATM_AAL34:
|
||||
max_sdu = ATM_MAX_AAL34_PDU;
|
||||
break;
|
||||
default:
|
||||
pr_warning("AAL problems ... (%d)\n", aal);
|
||||
/* fall through */
|
||||
case ATM_AAL5:
|
||||
max_sdu = ATM_MAX_AAL5_PDU;
|
||||
}
|
||||
if (!tp->max_sdu) tp->max_sdu = max_sdu;
|
||||
else if (tp->max_sdu > max_sdu) return -EINVAL;
|
||||
if (!tp->max_cdv) tp->max_cdv = ATM_MAX_CDV;
|
||||
if (!tp->max_sdu)
|
||||
tp->max_sdu = max_sdu;
|
||||
else if (tp->max_sdu > max_sdu)
|
||||
return -EINVAL;
|
||||
if (!tp->max_cdv)
|
||||
tp->max_cdv = ATM_MAX_CDV;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
|
||||
{
|
||||
struct hlist_head *head = &vcc_hash[vci &
|
||||
(VCC_HTABLE_SIZE - 1)];
|
||||
struct hlist_head *head = &vcc_hash[vci & (VCC_HTABLE_SIZE - 1)];
|
||||
struct hlist_node *node;
|
||||
struct sock *s;
|
||||
struct atm_vcc *walk;
|
||||
@@ -289,7 +282,6 @@ static int check_ci(const struct atm_vcc *vcc, short vpi, int vci)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
|
||||
{
|
||||
static short p; /* poor man's per-device cache */
|
||||
@@ -327,14 +319,13 @@ static int find_ci(const struct atm_vcc *vcc, short *vpi, int *vci)
|
||||
if ((c == ATM_NOT_RSV_VCI || *vci != ATM_VCI_ANY) &&
|
||||
*vpi == ATM_VPI_ANY) {
|
||||
p++;
|
||||
if (p >= 1 << vcc->dev->ci_range.vpi_bits) p = 0;
|
||||
if (p >= 1 << vcc->dev->ci_range.vpi_bits)
|
||||
p = 0;
|
||||
}
|
||||
}
|
||||
while (old_p != p || old_c != c);
|
||||
} while (old_p != p || old_c != c);
|
||||
return -EADDRINUSE;
|
||||
}
|
||||
|
||||
|
||||
static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
|
||||
int vci)
|
||||
{
|
||||
@@ -362,37 +353,46 @@ static int __vcc_connect(struct atm_vcc *vcc, struct atm_dev *dev, short vpi,
|
||||
__vcc_insert_socket(sk);
|
||||
write_unlock_irq(&vcc_sklist_lock);
|
||||
switch (vcc->qos.aal) {
|
||||
case ATM_AAL0:
|
||||
error = atm_init_aal0(vcc);
|
||||
vcc->stats = &dev->stats.aal0;
|
||||
break;
|
||||
case ATM_AAL34:
|
||||
error = atm_init_aal34(vcc);
|
||||
vcc->stats = &dev->stats.aal34;
|
||||
break;
|
||||
case ATM_NO_AAL:
|
||||
/* ATM_AAL5 is also used in the "0 for default" case */
|
||||
vcc->qos.aal = ATM_AAL5;
|
||||
/* fall through */
|
||||
case ATM_AAL5:
|
||||
error = atm_init_aal5(vcc);
|
||||
vcc->stats = &dev->stats.aal5;
|
||||
break;
|
||||
default:
|
||||
error = -EPROTOTYPE;
|
||||
case ATM_AAL0:
|
||||
error = atm_init_aal0(vcc);
|
||||
vcc->stats = &dev->stats.aal0;
|
||||
break;
|
||||
case ATM_AAL34:
|
||||
error = atm_init_aal34(vcc);
|
||||
vcc->stats = &dev->stats.aal34;
|
||||
break;
|
||||
case ATM_NO_AAL:
|
||||
/* ATM_AAL5 is also used in the "0 for default" case */
|
||||
vcc->qos.aal = ATM_AAL5;
|
||||
/* fall through */
|
||||
case ATM_AAL5:
|
||||
error = atm_init_aal5(vcc);
|
||||
vcc->stats = &dev->stats.aal5;
|
||||
break;
|
||||
default:
|
||||
error = -EPROTOTYPE;
|
||||
}
|
||||
if (!error) error = adjust_tp(&vcc->qos.txtp,vcc->qos.aal);
|
||||
if (!error) error = adjust_tp(&vcc->qos.rxtp,vcc->qos.aal);
|
||||
if (!error)
|
||||
error = adjust_tp(&vcc->qos.txtp, vcc->qos.aal);
|
||||
if (!error)
|
||||
error = adjust_tp(&vcc->qos.rxtp, vcc->qos.aal);
|
||||
if (error)
|
||||
goto fail;
|
||||
pr_debug("VCC %d.%d, AAL %d\n",vpi,vci,vcc->qos.aal);
|
||||
pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",vcc->qos.txtp.traffic_class,
|
||||
vcc->qos.txtp.min_pcr,vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu);
|
||||
pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",vcc->qos.rxtp.traffic_class,
|
||||
vcc->qos.rxtp.min_pcr,vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu);
|
||||
pr_debug("VCC %d.%d, AAL %d\n", vpi, vci, vcc->qos.aal);
|
||||
pr_debug(" TX: %d, PCR %d..%d, SDU %d\n",
|
||||
vcc->qos.txtp.traffic_class,
|
||||
vcc->qos.txtp.min_pcr,
|
||||
vcc->qos.txtp.max_pcr,
|
||||
vcc->qos.txtp.max_sdu);
|
||||
pr_debug(" RX: %d, PCR %d..%d, SDU %d\n",
|
||||
vcc->qos.rxtp.traffic_class,
|
||||
vcc->qos.rxtp.min_pcr,
|
||||
vcc->qos.rxtp.max_pcr,
|
||||
vcc->qos.rxtp.max_sdu);
|
||||
|
||||
if (dev->ops->open) {
|
||||
if ((error = dev->ops->open(vcc)))
|
||||
error = dev->ops->open(vcc);
|
||||
if (error)
|
||||
goto fail;
|
||||
}
|
||||
return 0;
|
||||
@@ -406,14 +406,13 @@ fail_module_put:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
|
||||
{
|
||||
struct atm_dev *dev;
|
||||
struct atm_vcc *vcc = ATM_SD(sock);
|
||||
int error;
|
||||
|
||||
pr_debug("vcc_connect (vpi %d, vci %d)\n",vpi,vci);
|
||||
pr_debug("(vpi %d, vci %d)\n", vpi, vci);
|
||||
if (sock->state == SS_CONNECTED)
|
||||
return -EISCONN;
|
||||
if (sock->state != SS_UNCONNECTED)
|
||||
@@ -422,30 +421,33 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
|
||||
return -EINVAL;
|
||||
|
||||
if (vpi != ATM_VPI_UNSPEC && vci != ATM_VCI_UNSPEC)
|
||||
clear_bit(ATM_VF_PARTIAL,&vcc->flags);
|
||||
clear_bit(ATM_VF_PARTIAL, &vcc->flags);
|
||||
else
|
||||
if (test_bit(ATM_VF_PARTIAL,&vcc->flags))
|
||||
if (test_bit(ATM_VF_PARTIAL, &vcc->flags))
|
||||
return -EINVAL;
|
||||
pr_debug("vcc_connect (TX: cl %d,bw %d-%d,sdu %d; "
|
||||
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
|
||||
vcc->qos.txtp.traffic_class,vcc->qos.txtp.min_pcr,
|
||||
vcc->qos.txtp.max_pcr,vcc->qos.txtp.max_sdu,
|
||||
vcc->qos.rxtp.traffic_class,vcc->qos.rxtp.min_pcr,
|
||||
vcc->qos.rxtp.max_pcr,vcc->qos.rxtp.max_sdu,
|
||||
vcc->qos.aal == ATM_AAL5 ? "" : vcc->qos.aal == ATM_AAL0 ? "" :
|
||||
" ??? code ",vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
|
||||
pr_debug("(TX: cl %d,bw %d-%d,sdu %d; "
|
||||
"RX: cl %d,bw %d-%d,sdu %d,AAL %s%d)\n",
|
||||
vcc->qos.txtp.traffic_class, vcc->qos.txtp.min_pcr,
|
||||
vcc->qos.txtp.max_pcr, vcc->qos.txtp.max_sdu,
|
||||
vcc->qos.rxtp.traffic_class, vcc->qos.rxtp.min_pcr,
|
||||
vcc->qos.rxtp.max_pcr, vcc->qos.rxtp.max_sdu,
|
||||
vcc->qos.aal == ATM_AAL5 ? "" :
|
||||
vcc->qos.aal == ATM_AAL0 ? "" : " ??? code ",
|
||||
vcc->qos.aal == ATM_AAL0 ? 0 : vcc->qos.aal);
|
||||
if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
|
||||
return -EBADFD;
|
||||
if (vcc->qos.txtp.traffic_class == ATM_ANYCLASS ||
|
||||
vcc->qos.rxtp.traffic_class == ATM_ANYCLASS)
|
||||
return -EINVAL;
|
||||
if (likely(itf != ATM_ITF_ANY)) {
|
||||
dev = try_then_request_module(atm_dev_lookup(itf), "atm-device-%d", itf);
|
||||
dev = try_then_request_module(atm_dev_lookup(itf),
|
||||
"atm-device-%d", itf);
|
||||
} else {
|
||||
dev = NULL;
|
||||
mutex_lock(&atm_dev_mutex);
|
||||
if (!list_empty(&atm_devs)) {
|
||||
dev = list_entry(atm_devs.next, struct atm_dev, dev_list);
|
||||
dev = list_entry(atm_devs.next,
|
||||
struct atm_dev, dev_list);
|
||||
atm_dev_hold(dev);
|
||||
}
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
@@ -458,13 +460,12 @@ int vcc_connect(struct socket *sock, int itf, short vpi, int vci)
|
||||
return error;
|
||||
}
|
||||
if (vpi == ATM_VPI_UNSPEC || vci == ATM_VCI_UNSPEC)
|
||||
set_bit(ATM_VF_PARTIAL,&vcc->flags);
|
||||
if (test_bit(ATM_VF_READY,&ATM_SD(sock)->flags))
|
||||
set_bit(ATM_VF_PARTIAL, &vcc->flags);
|
||||
if (test_bit(ATM_VF_READY, &ATM_SD(sock)->flags))
|
||||
sock->state = SS_CONNECTED;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
|
||||
size_t size, int flags)
|
||||
{
|
||||
@@ -478,8 +479,8 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
|
||||
if (flags & ~MSG_DONTWAIT) /* only handle MSG_DONTWAIT */
|
||||
return -EOPNOTSUPP;
|
||||
vcc = ATM_SD(sock);
|
||||
if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
|
||||
test_bit(ATM_VF_CLOSE,&vcc->flags) ||
|
||||
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
|
||||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
|
||||
!test_bit(ATM_VF_READY, &vcc->flags))
|
||||
return 0;
|
||||
|
||||
@@ -497,13 +498,12 @@ int vcc_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
|
||||
if (error)
|
||||
return error;
|
||||
sock_recv_ts_and_drops(msg, sk, skb);
|
||||
pr_debug("RcvM %d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
|
||||
pr_debug("%d -= %d\n", atomic_read(&sk->sk_rmem_alloc), skb->truesize);
|
||||
atm_return(vcc, skb->truesize);
|
||||
skb_free_datagram(sk, skb);
|
||||
return copied;
|
||||
}
|
||||
|
||||
|
||||
int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
|
||||
size_t total_len)
|
||||
{
|
||||
@@ -511,7 +511,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
|
||||
DEFINE_WAIT(wait);
|
||||
struct atm_vcc *vcc;
|
||||
struct sk_buff *skb;
|
||||
int eff,error;
|
||||
int eff, error;
|
||||
const void __user *buff;
|
||||
int size;
|
||||
|
||||
@@ -550,7 +550,7 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
|
||||
eff = (size+3) & ~3; /* align to word boundary */
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
error = 0;
|
||||
while (!(skb = alloc_tx(vcc,eff))) {
|
||||
while (!(skb = alloc_tx(vcc, eff))) {
|
||||
if (m->msg_flags & MSG_DONTWAIT) {
|
||||
error = -EAGAIN;
|
||||
break;
|
||||
@@ -560,9 +560,9 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
|
||||
error = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
|
||||
test_bit(ATM_VF_CLOSE,&vcc->flags) ||
|
||||
!test_bit(ATM_VF_READY,&vcc->flags)) {
|
||||
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
|
||||
test_bit(ATM_VF_CLOSE, &vcc->flags) ||
|
||||
!test_bit(ATM_VF_READY, &vcc->flags)) {
|
||||
error = -EPIPE;
|
||||
send_sig(SIGPIPE, current, 0);
|
||||
break;
|
||||
@@ -574,20 +574,20 @@ int vcc_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *m,
|
||||
goto out;
|
||||
skb->dev = NULL; /* for paths shared with net_device interfaces */
|
||||
ATM_SKB(skb)->atm_options = vcc->atm_options;
|
||||
if (copy_from_user(skb_put(skb,size),buff,size)) {
|
||||
if (copy_from_user(skb_put(skb, size), buff, size)) {
|
||||
kfree_skb(skb);
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (eff != size) memset(skb->data+size,0,eff-size);
|
||||
error = vcc->dev->ops->send(vcc,skb);
|
||||
if (eff != size)
|
||||
memset(skb->data + size, 0, eff-size);
|
||||
error = vcc->dev->ops->send(vcc, skb);
|
||||
error = error ? error : size;
|
||||
out:
|
||||
release_sock(sk);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -623,8 +623,7 @@ unsigned int vcc_poll(struct file *file, struct socket *sock, poll_table *wait)
|
||||
return mask;
|
||||
}
|
||||
|
||||
|
||||
static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
|
||||
static int atm_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -636,25 +635,31 @@ static int atm_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
|
||||
qos->rxtp.traffic_class != vcc->qos.rxtp.traffic_class ||
|
||||
qos->txtp.traffic_class != vcc->qos.txtp.traffic_class)
|
||||
return -EINVAL;
|
||||
error = adjust_tp(&qos->txtp,qos->aal);
|
||||
if (!error) error = adjust_tp(&qos->rxtp,qos->aal);
|
||||
if (error) return error;
|
||||
if (!vcc->dev->ops->change_qos) return -EOPNOTSUPP;
|
||||
error = adjust_tp(&qos->txtp, qos->aal);
|
||||
if (!error)
|
||||
error = adjust_tp(&qos->rxtp, qos->aal);
|
||||
if (error)
|
||||
return error;
|
||||
if (!vcc->dev->ops->change_qos)
|
||||
return -EOPNOTSUPP;
|
||||
if (sk_atm(vcc)->sk_family == AF_ATMPVC)
|
||||
return vcc->dev->ops->change_qos(vcc,qos,ATM_MF_SET);
|
||||
return svc_change_qos(vcc,qos);
|
||||
return vcc->dev->ops->change_qos(vcc, qos, ATM_MF_SET);
|
||||
return svc_change_qos(vcc, qos);
|
||||
}
|
||||
|
||||
|
||||
static int check_tp(const struct atm_trafprm *tp)
|
||||
{
|
||||
/* @@@ Should be merged with adjust_tp */
|
||||
if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS) return 0;
|
||||
if (!tp->traffic_class || tp->traffic_class == ATM_ANYCLASS)
|
||||
return 0;
|
||||
if (tp->traffic_class != ATM_UBR && !tp->min_pcr && !tp->pcr &&
|
||||
!tp->max_pcr) return -EINVAL;
|
||||
if (tp->min_pcr == ATM_MAX_PCR) return -EINVAL;
|
||||
!tp->max_pcr)
|
||||
return -EINVAL;
|
||||
if (tp->min_pcr == ATM_MAX_PCR)
|
||||
return -EINVAL;
|
||||
if (tp->min_pcr && tp->max_pcr && tp->max_pcr != ATM_MAX_PCR &&
|
||||
tp->min_pcr > tp->max_pcr) return -EINVAL;
|
||||
tp->min_pcr > tp->max_pcr)
|
||||
return -EINVAL;
|
||||
/*
|
||||
* We allow pcr to be outside [min_pcr,max_pcr], because later
|
||||
* adjustment may still push it in the valid range.
|
||||
@@ -662,7 +667,6 @@ static int check_tp(const struct atm_trafprm *tp)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int check_qos(const struct atm_qos *qos)
|
||||
{
|
||||
int error;
|
||||
@@ -672,9 +676,11 @@ static int check_qos(const struct atm_qos *qos)
|
||||
if (qos->txtp.traffic_class != qos->rxtp.traffic_class &&
|
||||
qos->txtp.traffic_class && qos->rxtp.traffic_class &&
|
||||
qos->txtp.traffic_class != ATM_ANYCLASS &&
|
||||
qos->rxtp.traffic_class != ATM_ANYCLASS) return -EINVAL;
|
||||
qos->rxtp.traffic_class != ATM_ANYCLASS)
|
||||
return -EINVAL;
|
||||
error = check_tp(&qos->txtp);
|
||||
if (error) return error;
|
||||
if (error)
|
||||
return error;
|
||||
return check_tp(&qos->rxtp);
|
||||
}
|
||||
|
||||
@@ -690,37 +696,41 @@ int vcc_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
vcc = ATM_SD(sock);
|
||||
switch (optname) {
|
||||
case SO_ATMQOS:
|
||||
{
|
||||
struct atm_qos qos;
|
||||
case SO_ATMQOS:
|
||||
{
|
||||
struct atm_qos qos;
|
||||
|
||||
if (copy_from_user(&qos,optval,sizeof(qos)))
|
||||
return -EFAULT;
|
||||
error = check_qos(&qos);
|
||||
if (error) return error;
|
||||
if (sock->state == SS_CONNECTED)
|
||||
return atm_change_qos(vcc,&qos);
|
||||
if (sock->state != SS_UNCONNECTED)
|
||||
return -EBADFD;
|
||||
vcc->qos = qos;
|
||||
set_bit(ATM_VF_HASQOS,&vcc->flags);
|
||||
return 0;
|
||||
}
|
||||
case SO_SETCLP:
|
||||
if (get_user(value,(unsigned long __user *)optval))
|
||||
return -EFAULT;
|
||||
if (value) vcc->atm_options |= ATM_ATMOPT_CLP;
|
||||
else vcc->atm_options &= ~ATM_ATMOPT_CLP;
|
||||
return 0;
|
||||
default:
|
||||
if (level == SOL_SOCKET) return -EINVAL;
|
||||
break;
|
||||
if (copy_from_user(&qos, optval, sizeof(qos)))
|
||||
return -EFAULT;
|
||||
error = check_qos(&qos);
|
||||
if (error)
|
||||
return error;
|
||||
if (sock->state == SS_CONNECTED)
|
||||
return atm_change_qos(vcc, &qos);
|
||||
if (sock->state != SS_UNCONNECTED)
|
||||
return -EBADFD;
|
||||
vcc->qos = qos;
|
||||
set_bit(ATM_VF_HASQOS, &vcc->flags);
|
||||
return 0;
|
||||
}
|
||||
if (!vcc->dev || !vcc->dev->ops->setsockopt) return -EINVAL;
|
||||
return vcc->dev->ops->setsockopt(vcc,level,optname,optval,optlen);
|
||||
case SO_SETCLP:
|
||||
if (get_user(value, (unsigned long __user *)optval))
|
||||
return -EFAULT;
|
||||
if (value)
|
||||
vcc->atm_options |= ATM_ATMOPT_CLP;
|
||||
else
|
||||
vcc->atm_options &= ~ATM_ATMOPT_CLP;
|
||||
return 0;
|
||||
default:
|
||||
if (level == SOL_SOCKET)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!vcc->dev || !vcc->dev->ops->setsockopt)
|
||||
return -EINVAL;
|
||||
return vcc->dev->ops->setsockopt(vcc, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
|
||||
int vcc_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
@@ -734,33 +744,33 @@ int vcc_getsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
vcc = ATM_SD(sock);
|
||||
switch (optname) {
|
||||
case SO_ATMQOS:
|
||||
if (!test_bit(ATM_VF_HASQOS,&vcc->flags))
|
||||
return -EINVAL;
|
||||
return copy_to_user(optval,&vcc->qos,sizeof(vcc->qos)) ?
|
||||
-EFAULT : 0;
|
||||
case SO_SETCLP:
|
||||
return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 :
|
||||
0,(unsigned long __user *)optval) ? -EFAULT : 0;
|
||||
case SO_ATMPVC:
|
||||
{
|
||||
struct sockaddr_atmpvc pvc;
|
||||
case SO_ATMQOS:
|
||||
if (!test_bit(ATM_VF_HASQOS, &vcc->flags))
|
||||
return -EINVAL;
|
||||
return copy_to_user(optval, &vcc->qos, sizeof(vcc->qos))
|
||||
? -EFAULT : 0;
|
||||
case SO_SETCLP:
|
||||
return put_user(vcc->atm_options & ATM_ATMOPT_CLP ? 1 : 0,
|
||||
(unsigned long __user *)optval) ? -EFAULT : 0;
|
||||
case SO_ATMPVC:
|
||||
{
|
||||
struct sockaddr_atmpvc pvc;
|
||||
|
||||
if (!vcc->dev ||
|
||||
!test_bit(ATM_VF_ADDR,&vcc->flags))
|
||||
return -ENOTCONN;
|
||||
pvc.sap_family = AF_ATMPVC;
|
||||
pvc.sap_addr.itf = vcc->dev->number;
|
||||
pvc.sap_addr.vpi = vcc->vpi;
|
||||
pvc.sap_addr.vci = vcc->vci;
|
||||
return copy_to_user(optval,&pvc,sizeof(pvc)) ?
|
||||
-EFAULT : 0;
|
||||
}
|
||||
default:
|
||||
if (level == SOL_SOCKET) return -EINVAL;
|
||||
if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
|
||||
return -ENOTCONN;
|
||||
pvc.sap_family = AF_ATMPVC;
|
||||
pvc.sap_addr.itf = vcc->dev->number;
|
||||
pvc.sap_addr.vpi = vcc->vpi;
|
||||
pvc.sap_addr.vci = vcc->vci;
|
||||
return copy_to_user(optval, &pvc, sizeof(pvc)) ? -EFAULT : 0;
|
||||
}
|
||||
default:
|
||||
if (level == SOL_SOCKET)
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
if (!vcc->dev || !vcc->dev->ops->getsockopt) return -EINVAL;
|
||||
if (!vcc->dev || !vcc->dev->ops->getsockopt)
|
||||
return -EINVAL;
|
||||
return vcc->dev->ops->getsockopt(vcc, level, optname, optval, len);
|
||||
}
|
||||
|
||||
@@ -768,23 +778,27 @@ static int __init atm_init(void)
|
||||
{
|
||||
int error;
|
||||
|
||||
if ((error = proto_register(&vcc_proto, 0)) < 0)
|
||||
error = proto_register(&vcc_proto, 0);
|
||||
if (error < 0)
|
||||
goto out;
|
||||
|
||||
if ((error = atmpvc_init()) < 0) {
|
||||
printk(KERN_ERR "atmpvc_init() failed with %d\n", error);
|
||||
error = atmpvc_init();
|
||||
if (error < 0) {
|
||||
pr_err("atmpvc_init() failed with %d\n", error);
|
||||
goto out_unregister_vcc_proto;
|
||||
}
|
||||
if ((error = atmsvc_init()) < 0) {
|
||||
printk(KERN_ERR "atmsvc_init() failed with %d\n", error);
|
||||
error = atmsvc_init();
|
||||
if (error < 0) {
|
||||
pr_err("atmsvc_init() failed with %d\n", error);
|
||||
goto out_atmpvc_exit;
|
||||
}
|
||||
if ((error = atm_proc_init()) < 0) {
|
||||
printk(KERN_ERR "atm_proc_init() failed with %d\n",error);
|
||||
error = atm_proc_init();
|
||||
if (error < 0) {
|
||||
pr_err("atm_proc_init() failed with %d\n", error);
|
||||
goto out_atmsvc_exit;
|
||||
}
|
||||
if ((error = atm_sysfs_init()) < 0) {
|
||||
printk(KERN_ERR "atm_sysfs_init() failed with %d\n",error);
|
||||
error = atm_sysfs_init();
|
||||
if (error < 0) {
|
||||
pr_err("atm_sysfs_init() failed with %d\n", error);
|
||||
goto out_atmproc_exit;
|
||||
}
|
||||
out:
|
||||
|
||||
+98
-98
@@ -3,6 +3,7 @@
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
/* 2003 John Levon <levon@movementarian.org> */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/kmod.h>
|
||||
@@ -36,6 +37,7 @@ void register_atm_ioctl(struct atm_ioctl *ioctl)
|
||||
list_add_tail(&ioctl->list, &ioctl_list);
|
||||
mutex_unlock(&ioctl_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(register_atm_ioctl);
|
||||
|
||||
void deregister_atm_ioctl(struct atm_ioctl *ioctl)
|
||||
{
|
||||
@@ -43,129 +45,128 @@ void deregister_atm_ioctl(struct atm_ioctl *ioctl)
|
||||
list_del(&ioctl->list);
|
||||
mutex_unlock(&ioctl_mutex);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(register_atm_ioctl);
|
||||
EXPORT_SYMBOL(deregister_atm_ioctl);
|
||||
|
||||
static int do_vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg, int compat)
|
||||
static int do_vcc_ioctl(struct socket *sock, unsigned int cmd,
|
||||
unsigned long arg, int compat)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct atm_vcc *vcc;
|
||||
int error;
|
||||
struct list_head * pos;
|
||||
struct list_head *pos;
|
||||
void __user *argp = (void __user *)arg;
|
||||
|
||||
vcc = ATM_SD(sock);
|
||||
switch (cmd) {
|
||||
case SIOCOUTQ:
|
||||
if (sock->state != SS_CONNECTED ||
|
||||
!test_bit(ATM_VF_READY, &vcc->flags)) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
|
||||
(int __user *) argp) ? -EFAULT : 0;
|
||||
case SIOCOUTQ:
|
||||
if (sock->state != SS_CONNECTED ||
|
||||
!test_bit(ATM_VF_READY, &vcc->flags)) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
case SIOCINQ:
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
}
|
||||
error = put_user(sk->sk_sndbuf - sk_wmem_alloc_get(sk),
|
||||
(int __user *)argp) ? -EFAULT : 0;
|
||||
goto done;
|
||||
case SIOCINQ:
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (sock->state != SS_CONNECTED) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
skb = skb_peek(&sk->sk_receive_queue);
|
||||
error = put_user(skb ? skb->len : 0,
|
||||
(int __user *)argp) ? -EFAULT : 0;
|
||||
goto done;
|
||||
}
|
||||
case SIOCGSTAMP: /* borrowed from IP */
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
error = compat_sock_get_timestamp(sk, argp);
|
||||
else
|
||||
#endif
|
||||
error = sock_get_timestamp(sk, argp);
|
||||
if (sock->state != SS_CONNECTED) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
case SIOCGSTAMPNS: /* borrowed from IP */
|
||||
}
|
||||
skb = skb_peek(&sk->sk_receive_queue);
|
||||
error = put_user(skb ? skb->len : 0,
|
||||
(int __user *)argp) ? -EFAULT : 0;
|
||||
goto done;
|
||||
}
|
||||
case SIOCGSTAMP: /* borrowed from IP */
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
error = compat_sock_get_timestampns(sk, argp);
|
||||
else
|
||||
if (compat)
|
||||
error = compat_sock_get_timestamp(sk, argp);
|
||||
else
|
||||
#endif
|
||||
error = sock_get_timestampns(sk, argp);
|
||||
error = sock_get_timestamp(sk, argp);
|
||||
goto done;
|
||||
case SIOCGSTAMPNS: /* borrowed from IP */
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (compat)
|
||||
error = compat_sock_get_timestampns(sk, argp);
|
||||
else
|
||||
#endif
|
||||
error = sock_get_timestampns(sk, argp);
|
||||
goto done;
|
||||
case ATM_SETSC:
|
||||
if (net_ratelimit())
|
||||
pr_warning("ATM_SETSC is obsolete; used by %s:%d\n",
|
||||
current->comm, task_pid_nr(current));
|
||||
error = 0;
|
||||
goto done;
|
||||
case ATMSIGD_CTRL:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
case ATM_SETSC:
|
||||
}
|
||||
/*
|
||||
* The user/kernel protocol for exchanging signalling
|
||||
* info uses kernel pointers as opaque references,
|
||||
* so the holder of the file descriptor can scribble
|
||||
* on the kernel... so we should make sure that we
|
||||
* have the same privileges that /proc/kcore needs
|
||||
*/
|
||||
if (!capable(CAP_SYS_RAWIO)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* WTF? I don't even want to _think_ about making this
|
||||
work for 32-bit userspace. TBH I don't really want
|
||||
to think about it at all. dwmw2. */
|
||||
if (compat) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "ATM_SETSC is obsolete; used by %s:%d\n",
|
||||
current->comm, task_pid_nr(current));
|
||||
error = 0;
|
||||
pr_warning("32-bit task cannot be atmsigd\n");
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
case ATMSIGD_CTRL:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
/*
|
||||
* The user/kernel protocol for exchanging signalling
|
||||
* info uses kernel pointers as opaque references,
|
||||
* so the holder of the file descriptor can scribble
|
||||
* on the kernel... so we should make sure that we
|
||||
* have the same privileges that /proc/kcore needs
|
||||
*/
|
||||
if (!capable(CAP_SYS_RAWIO)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
/* WTF? I don't even want to _think_ about making this
|
||||
work for 32-bit userspace. TBH I don't really want
|
||||
to think about it at all. dwmw2. */
|
||||
if (compat) {
|
||||
if (net_ratelimit())
|
||||
printk(KERN_WARNING "32-bit task cannot be atmsigd\n");
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
error = sigd_attach(vcc);
|
||||
if (!error)
|
||||
sock->state = SS_CONNECTED;
|
||||
error = sigd_attach(vcc);
|
||||
if (!error)
|
||||
sock->state = SS_CONNECTED;
|
||||
goto done;
|
||||
case ATM_SETBACKEND:
|
||||
case ATM_NEWBACKENDIF:
|
||||
{
|
||||
atm_backend_t backend;
|
||||
error = get_user(backend, (atm_backend_t __user *)argp);
|
||||
if (error)
|
||||
goto done;
|
||||
case ATM_SETBACKEND:
|
||||
case ATM_NEWBACKENDIF:
|
||||
{
|
||||
atm_backend_t backend;
|
||||
error = get_user(backend, (atm_backend_t __user *) argp);
|
||||
if (error)
|
||||
goto done;
|
||||
switch (backend) {
|
||||
case ATM_BACKEND_PPP:
|
||||
request_module("pppoatm");
|
||||
break;
|
||||
case ATM_BACKEND_BR2684:
|
||||
request_module("br2684");
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (backend) {
|
||||
case ATM_BACKEND_PPP:
|
||||
request_module("pppoatm");
|
||||
break;
|
||||
case ATMMPC_CTRL:
|
||||
case ATMMPC_DATA:
|
||||
request_module("mpoa");
|
||||
break;
|
||||
case ATMARPD_CTRL:
|
||||
request_module("clip");
|
||||
break;
|
||||
case ATMLEC_CTRL:
|
||||
request_module("lec");
|
||||
case ATM_BACKEND_BR2684:
|
||||
request_module("br2684");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ATMMPC_CTRL:
|
||||
case ATMMPC_DATA:
|
||||
request_module("mpoa");
|
||||
break;
|
||||
case ATMARPD_CTRL:
|
||||
request_module("clip");
|
||||
break;
|
||||
case ATMLEC_CTRL:
|
||||
request_module("lec");
|
||||
break;
|
||||
}
|
||||
|
||||
error = -ENOIOCTLCMD;
|
||||
|
||||
mutex_lock(&ioctl_mutex);
|
||||
list_for_each(pos, &ioctl_list) {
|
||||
struct atm_ioctl * ic = list_entry(pos, struct atm_ioctl, list);
|
||||
struct atm_ioctl *ic = list_entry(pos, struct atm_ioctl, list);
|
||||
if (try_module_get(ic->owner)) {
|
||||
error = ic->ioctl(sock, cmd, arg);
|
||||
module_put(ic->owner);
|
||||
@@ -184,7 +185,6 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
int vcc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
return do_vcc_ioctl(sock, cmd, arg, 0);
|
||||
@@ -287,8 +287,8 @@ static int do_atmif_sioc(struct socket *sock, unsigned int cmd,
|
||||
sioc = compat_alloc_user_space(sizeof(*sioc));
|
||||
sioc32 = compat_ptr(arg);
|
||||
|
||||
if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int))
|
||||
|| get_user(data, &sioc32->arg))
|
||||
if (copy_in_user(&sioc->number, &sioc32->number, 2 * sizeof(int)) ||
|
||||
get_user(data, &sioc32->arg))
|
||||
return -EFAULT;
|
||||
datap = compat_ptr(data);
|
||||
if (put_user(datap, &sioc->arg))
|
||||
|
||||
+281
-314
File diff suppressed because it is too large
Load Diff
+303
-239
File diff suppressed because it is too large
Load Diff
+105
-85
@@ -11,15 +11,23 @@
|
||||
*/
|
||||
|
||||
#if 0
|
||||
#define dprintk printk /* debug */
|
||||
#define dprintk(format, args...) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
|
||||
#else
|
||||
#define dprintk(format,args...)
|
||||
#define dprintk(format, args...) \
|
||||
do { if (0) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define ddprintk printk /* more debug */
|
||||
#define ddprintk(format, args...) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
|
||||
#else
|
||||
#define ddprintk(format,args...)
|
||||
#define ddprintk(format, args...) \
|
||||
do { if (0) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static in_cache_entry *in_cache_get(__be32 dst_ip,
|
||||
@@ -29,8 +37,8 @@ static in_cache_entry *in_cache_get(__be32 dst_ip,
|
||||
|
||||
read_lock_bh(&client->ingress_lock);
|
||||
entry = client->in_cache;
|
||||
while(entry != NULL){
|
||||
if( entry->ctrl_info.in_dst_ip == dst_ip ){
|
||||
while (entry != NULL) {
|
||||
if (entry->ctrl_info.in_dst_ip == dst_ip) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_bh(&client->ingress_lock);
|
||||
return entry;
|
||||
@@ -50,8 +58,8 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
|
||||
|
||||
read_lock_bh(&client->ingress_lock);
|
||||
entry = client->in_cache;
|
||||
while(entry != NULL){
|
||||
if((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask )){
|
||||
while (entry != NULL) {
|
||||
if ((entry->ctrl_info.in_dst_ip & mask) == (dst_ip & mask)) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_bh(&client->ingress_lock);
|
||||
return entry;
|
||||
@@ -65,14 +73,14 @@ static in_cache_entry *in_cache_get_with_mask(__be32 dst_ip,
|
||||
}
|
||||
|
||||
static in_cache_entry *in_cache_get_by_vcc(struct atm_vcc *vcc,
|
||||
struct mpoa_client *client )
|
||||
struct mpoa_client *client)
|
||||
{
|
||||
in_cache_entry *entry;
|
||||
|
||||
read_lock_bh(&client->ingress_lock);
|
||||
entry = client->in_cache;
|
||||
while(entry != NULL){
|
||||
if(entry->shortcut == vcc) {
|
||||
while (entry != NULL) {
|
||||
if (entry->shortcut == vcc) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_bh(&client->ingress_lock);
|
||||
return entry;
|
||||
@@ -90,14 +98,14 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
|
||||
in_cache_entry *entry = kzalloc(sizeof(in_cache_entry), GFP_KERNEL);
|
||||
|
||||
if (entry == NULL) {
|
||||
printk("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
|
||||
pr_info("mpoa: mpoa_caches.c: new_in_cache_entry: out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dprintk("mpoa: mpoa_caches.c: adding an ingress entry, ip = %pI4\n", &dst_ip);
|
||||
dprintk("adding an ingress entry, ip = %pI4\n", &dst_ip);
|
||||
|
||||
atomic_set(&entry->use, 1);
|
||||
dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: about to lock\n");
|
||||
dprintk("new_in_cache_entry: about to lock\n");
|
||||
write_lock_bh(&client->ingress_lock);
|
||||
entry->next = client->in_cache;
|
||||
entry->prev = NULL;
|
||||
@@ -115,7 +123,7 @@ static in_cache_entry *in_cache_add_entry(__be32 dst_ip,
|
||||
atomic_inc(&entry->use);
|
||||
|
||||
write_unlock_bh(&client->ingress_lock);
|
||||
dprintk("mpoa: mpoa_caches.c: new_in_cache_entry: unlocked\n");
|
||||
dprintk("new_in_cache_entry: unlocked\n");
|
||||
|
||||
return entry;
|
||||
}
|
||||
@@ -126,39 +134,41 @@ static int cache_hit(in_cache_entry *entry, struct mpoa_client *mpc)
|
||||
struct k_message msg;
|
||||
|
||||
entry->count++;
|
||||
if(entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
|
||||
if (entry->entry_state == INGRESS_RESOLVED && entry->shortcut != NULL)
|
||||
return OPEN;
|
||||
|
||||
if(entry->entry_state == INGRESS_REFRESHING){
|
||||
if(entry->count > mpc->parameters.mpc_p1){
|
||||
if (entry->entry_state == INGRESS_REFRESHING) {
|
||||
if (entry->count > mpc->parameters.mpc_p1) {
|
||||
msg.type = SND_MPOA_RES_RQST;
|
||||
msg.content.in_info = entry->ctrl_info;
|
||||
memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
|
||||
qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
|
||||
if (qos != NULL) msg.qos = qos->qos;
|
||||
if (qos != NULL)
|
||||
msg.qos = qos->qos;
|
||||
msg_to_mpoad(&msg, mpc);
|
||||
do_gettimeofday(&(entry->reply_wait));
|
||||
entry->entry_state = INGRESS_RESOLVING;
|
||||
}
|
||||
if(entry->shortcut != NULL)
|
||||
if (entry->shortcut != NULL)
|
||||
return OPEN;
|
||||
return CLOSED;
|
||||
}
|
||||
|
||||
if(entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
|
||||
if (entry->entry_state == INGRESS_RESOLVING && entry->shortcut != NULL)
|
||||
return OPEN;
|
||||
|
||||
if( entry->count > mpc->parameters.mpc_p1 &&
|
||||
entry->entry_state == INGRESS_INVALID){
|
||||
dprintk("mpoa: (%s) mpoa_caches.c: threshold exceeded for ip %pI4, sending MPOA res req\n",
|
||||
if (entry->count > mpc->parameters.mpc_p1 &&
|
||||
entry->entry_state == INGRESS_INVALID) {
|
||||
dprintk("(%s) threshold exceeded for ip %pI4, sending MPOA res req\n",
|
||||
mpc->dev->name, &entry->ctrl_info.in_dst_ip);
|
||||
entry->entry_state = INGRESS_RESOLVING;
|
||||
msg.type = SND_MPOA_RES_RQST;
|
||||
memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN );
|
||||
msg.type = SND_MPOA_RES_RQST;
|
||||
memcpy(msg.MPS_ctrl, mpc->mps_ctrl_addr, ATM_ESA_LEN);
|
||||
msg.content.in_info = entry->ctrl_info;
|
||||
qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
|
||||
if (qos != NULL) msg.qos = qos->qos;
|
||||
msg_to_mpoad( &msg, mpc);
|
||||
if (qos != NULL)
|
||||
msg.qos = qos->qos;
|
||||
msg_to_mpoad(&msg, mpc);
|
||||
do_gettimeofday(&(entry->reply_wait));
|
||||
}
|
||||
|
||||
@@ -185,7 +195,7 @@ static void in_cache_remove_entry(in_cache_entry *entry,
|
||||
struct k_message msg;
|
||||
|
||||
vcc = entry->shortcut;
|
||||
dprintk("mpoa: mpoa_caches.c: removing an ingress entry, ip = %pI4\n",
|
||||
dprintk("removing an ingress entry, ip = %pI4\n",
|
||||
&entry->ctrl_info.in_dst_ip);
|
||||
|
||||
if (entry->prev != NULL)
|
||||
@@ -195,14 +205,15 @@ static void in_cache_remove_entry(in_cache_entry *entry,
|
||||
if (entry->next != NULL)
|
||||
entry->next->prev = entry->prev;
|
||||
client->in_ops->put(entry);
|
||||
if(client->in_cache == NULL && client->eg_cache == NULL){
|
||||
if (client->in_cache == NULL && client->eg_cache == NULL) {
|
||||
msg.type = STOP_KEEP_ALIVE_SM;
|
||||
msg_to_mpoad(&msg,client);
|
||||
msg_to_mpoad(&msg, client);
|
||||
}
|
||||
|
||||
/* Check if the egress side still uses this VCC */
|
||||
if (vcc != NULL) {
|
||||
eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc, client);
|
||||
eg_cache_entry *eg_entry = client->eg_ops->get_by_vcc(vcc,
|
||||
client);
|
||||
if (eg_entry != NULL) {
|
||||
client->eg_ops->put(eg_entry);
|
||||
return;
|
||||
@@ -213,7 +224,6 @@ static void in_cache_remove_entry(in_cache_entry *entry,
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* Call this every MPC-p2 seconds... Not exactly correct solution,
|
||||
but an easy one... */
|
||||
static void clear_count_and_expired(struct mpoa_client *client)
|
||||
@@ -225,12 +235,12 @@ static void clear_count_and_expired(struct mpoa_client *client)
|
||||
|
||||
write_lock_bh(&client->ingress_lock);
|
||||
entry = client->in_cache;
|
||||
while(entry != NULL){
|
||||
entry->count=0;
|
||||
while (entry != NULL) {
|
||||
entry->count = 0;
|
||||
next_entry = entry->next;
|
||||
if((now.tv_sec - entry->tv.tv_sec)
|
||||
> entry->ctrl_info.holding_time){
|
||||
dprintk("mpoa: mpoa_caches.c: holding time expired, ip = %pI4\n",
|
||||
if ((now.tv_sec - entry->tv.tv_sec)
|
||||
> entry->ctrl_info.holding_time) {
|
||||
dprintk("holding time expired, ip = %pI4\n",
|
||||
&entry->ctrl_info.in_dst_ip);
|
||||
client->in_ops->remove_entry(entry, client);
|
||||
}
|
||||
@@ -250,33 +260,38 @@ static void check_resolving_entries(struct mpoa_client *client)
|
||||
struct timeval now;
|
||||
struct k_message msg;
|
||||
|
||||
do_gettimeofday( &now );
|
||||
do_gettimeofday(&now);
|
||||
|
||||
read_lock_bh(&client->ingress_lock);
|
||||
entry = client->in_cache;
|
||||
while( entry != NULL ){
|
||||
if(entry->entry_state == INGRESS_RESOLVING){
|
||||
if(now.tv_sec - entry->hold_down.tv_sec < client->parameters.mpc_p6){
|
||||
entry = entry->next; /* Entry in hold down */
|
||||
while (entry != NULL) {
|
||||
if (entry->entry_state == INGRESS_RESOLVING) {
|
||||
if ((now.tv_sec - entry->hold_down.tv_sec) <
|
||||
client->parameters.mpc_p6) {
|
||||
entry = entry->next; /* Entry in hold down */
|
||||
continue;
|
||||
}
|
||||
if( (now.tv_sec - entry->reply_wait.tv_sec) >
|
||||
entry->retry_time ){
|
||||
entry->retry_time = MPC_C1*( entry->retry_time );
|
||||
if(entry->retry_time > client->parameters.mpc_p5){
|
||||
/* Retry time maximum exceeded, put entry in hold down. */
|
||||
if ((now.tv_sec - entry->reply_wait.tv_sec) >
|
||||
entry->retry_time) {
|
||||
entry->retry_time = MPC_C1 * (entry->retry_time);
|
||||
/*
|
||||
* Retry time maximum exceeded,
|
||||
* put entry in hold down.
|
||||
*/
|
||||
if (entry->retry_time > client->parameters.mpc_p5) {
|
||||
do_gettimeofday(&(entry->hold_down));
|
||||
entry->retry_time = client->parameters.mpc_p4;
|
||||
entry = entry->next;
|
||||
continue;
|
||||
}
|
||||
/* Ask daemon to send a resolution request. */
|
||||
memset(&(entry->hold_down),0,sizeof(struct timeval));
|
||||
memset(&(entry->hold_down), 0, sizeof(struct timeval));
|
||||
msg.type = SND_MPOA_RES_RTRY;
|
||||
memcpy(msg.MPS_ctrl, client->mps_ctrl_addr, ATM_ESA_LEN);
|
||||
msg.content.in_info = entry->ctrl_info;
|
||||
qos = atm_mpoa_search_qos(entry->ctrl_info.in_dst_ip);
|
||||
if (qos != NULL) msg.qos = qos->qos;
|
||||
if (qos != NULL)
|
||||
msg.qos = qos->qos;
|
||||
msg_to_mpoad(&msg, client);
|
||||
do_gettimeofday(&(entry->reply_wait));
|
||||
}
|
||||
@@ -292,16 +307,17 @@ static void refresh_entries(struct mpoa_client *client)
|
||||
struct timeval now;
|
||||
struct in_cache_entry *entry = client->in_cache;
|
||||
|
||||
ddprintk("mpoa: mpoa_caches.c: refresh_entries\n");
|
||||
ddprintk("refresh_entries\n");
|
||||
do_gettimeofday(&now);
|
||||
|
||||
read_lock_bh(&client->ingress_lock);
|
||||
while( entry != NULL ){
|
||||
if( entry->entry_state == INGRESS_RESOLVED ){
|
||||
if(!(entry->refresh_time))
|
||||
entry->refresh_time = (2*(entry->ctrl_info.holding_time))/3;
|
||||
if( (now.tv_sec - entry->reply_wait.tv_sec) > entry->refresh_time ){
|
||||
dprintk("mpoa: mpoa_caches.c: refreshing an entry.\n");
|
||||
while (entry != NULL) {
|
||||
if (entry->entry_state == INGRESS_RESOLVED) {
|
||||
if (!(entry->refresh_time))
|
||||
entry->refresh_time = (2 * (entry->ctrl_info.holding_time))/3;
|
||||
if ((now.tv_sec - entry->reply_wait.tv_sec) >
|
||||
entry->refresh_time) {
|
||||
dprintk("refreshing an entry.\n");
|
||||
entry->entry_state = INGRESS_REFRESHING;
|
||||
|
||||
}
|
||||
@@ -314,21 +330,22 @@ static void refresh_entries(struct mpoa_client *client)
|
||||
static void in_destroy_cache(struct mpoa_client *mpc)
|
||||
{
|
||||
write_lock_irq(&mpc->ingress_lock);
|
||||
while(mpc->in_cache != NULL)
|
||||
while (mpc->in_cache != NULL)
|
||||
mpc->in_ops->remove_entry(mpc->in_cache, mpc);
|
||||
write_unlock_irq(&mpc->ingress_lock);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id, struct mpoa_client *mpc)
|
||||
static eg_cache_entry *eg_cache_get_by_cache_id(__be32 cache_id,
|
||||
struct mpoa_client *mpc)
|
||||
{
|
||||
eg_cache_entry *entry;
|
||||
|
||||
read_lock_irq(&mpc->egress_lock);
|
||||
entry = mpc->eg_cache;
|
||||
while(entry != NULL){
|
||||
if(entry->ctrl_info.cache_id == cache_id){
|
||||
while (entry != NULL) {
|
||||
if (entry->ctrl_info.cache_id == cache_id) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_irq(&mpc->egress_lock);
|
||||
return entry;
|
||||
@@ -348,7 +365,7 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
|
||||
|
||||
read_lock_irqsave(&mpc->egress_lock, flags);
|
||||
entry = mpc->eg_cache;
|
||||
while (entry != NULL){
|
||||
while (entry != NULL) {
|
||||
if (entry->ctrl_info.tag == tag) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_irqrestore(&mpc->egress_lock, flags);
|
||||
@@ -362,14 +379,15 @@ static eg_cache_entry *eg_cache_get_by_tag(__be32 tag, struct mpoa_client *mpc)
|
||||
}
|
||||
|
||||
/* This can be called from any context since it saves CPU flags */
|
||||
static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_client *mpc)
|
||||
static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc,
|
||||
struct mpoa_client *mpc)
|
||||
{
|
||||
unsigned long flags;
|
||||
eg_cache_entry *entry;
|
||||
|
||||
read_lock_irqsave(&mpc->egress_lock, flags);
|
||||
entry = mpc->eg_cache;
|
||||
while (entry != NULL){
|
||||
while (entry != NULL) {
|
||||
if (entry->shortcut == vcc) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_irqrestore(&mpc->egress_lock, flags);
|
||||
@@ -382,14 +400,15 @@ static eg_cache_entry *eg_cache_get_by_vcc(struct atm_vcc *vcc, struct mpoa_clie
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr, struct mpoa_client *mpc)
|
||||
static eg_cache_entry *eg_cache_get_by_src_ip(__be32 ipaddr,
|
||||
struct mpoa_client *mpc)
|
||||
{
|
||||
eg_cache_entry *entry;
|
||||
|
||||
read_lock_irq(&mpc->egress_lock);
|
||||
entry = mpc->eg_cache;
|
||||
while(entry != NULL){
|
||||
if(entry->latest_ip_addr == ipaddr) {
|
||||
while (entry != NULL) {
|
||||
if (entry->latest_ip_addr == ipaddr) {
|
||||
atomic_inc(&entry->use);
|
||||
read_unlock_irq(&mpc->egress_lock);
|
||||
return entry;
|
||||
@@ -421,7 +440,7 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
|
||||
struct k_message msg;
|
||||
|
||||
vcc = entry->shortcut;
|
||||
dprintk("mpoa: mpoa_caches.c: removing an egress entry.\n");
|
||||
dprintk("removing an egress entry.\n");
|
||||
if (entry->prev != NULL)
|
||||
entry->prev->next = entry->next;
|
||||
else
|
||||
@@ -429,9 +448,9 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
|
||||
if (entry->next != NULL)
|
||||
entry->next->prev = entry->prev;
|
||||
client->eg_ops->put(entry);
|
||||
if(client->in_cache == NULL && client->eg_cache == NULL){
|
||||
if (client->in_cache == NULL && client->eg_cache == NULL) {
|
||||
msg.type = STOP_KEEP_ALIVE_SM;
|
||||
msg_to_mpoad(&msg,client);
|
||||
msg_to_mpoad(&msg, client);
|
||||
}
|
||||
|
||||
/* Check if the ingress side still uses this VCC */
|
||||
@@ -447,20 +466,21 @@ static void eg_cache_remove_entry(eg_cache_entry *entry,
|
||||
return;
|
||||
}
|
||||
|
||||
static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_client *client)
|
||||
static eg_cache_entry *eg_cache_add_entry(struct k_message *msg,
|
||||
struct mpoa_client *client)
|
||||
{
|
||||
eg_cache_entry *entry = kzalloc(sizeof(eg_cache_entry), GFP_KERNEL);
|
||||
|
||||
if (entry == NULL) {
|
||||
printk("mpoa: mpoa_caches.c: new_eg_cache_entry: out of memory\n");
|
||||
pr_info("out of memory\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
dprintk("mpoa: mpoa_caches.c: adding an egress entry, ip = %pI4, this should be our IP\n",
|
||||
dprintk("adding an egress entry, ip = %pI4, this should be our IP\n",
|
||||
&msg->content.eg_info.eg_dst_ip);
|
||||
|
||||
atomic_set(&entry->use, 1);
|
||||
dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: about to lock\n");
|
||||
dprintk("new_eg_cache_entry: about to lock\n");
|
||||
write_lock_irq(&client->egress_lock);
|
||||
entry->next = client->eg_cache;
|
||||
entry->prev = NULL;
|
||||
@@ -472,18 +492,18 @@ static eg_cache_entry *eg_cache_add_entry(struct k_message *msg, struct mpoa_cli
|
||||
entry->ctrl_info = msg->content.eg_info;
|
||||
do_gettimeofday(&(entry->tv));
|
||||
entry->entry_state = EGRESS_RESOLVED;
|
||||
dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry cache_id %lu\n", ntohl(entry->ctrl_info.cache_id));
|
||||
dprintk("mpoa: mpoa_caches.c: mps_ip = %pI4\n",
|
||||
&entry->ctrl_info.mps_ip);
|
||||
dprintk("new_eg_cache_entry cache_id %u\n",
|
||||
ntohl(entry->ctrl_info.cache_id));
|
||||
dprintk("mps_ip = %pI4\n", &entry->ctrl_info.mps_ip);
|
||||
atomic_inc(&entry->use);
|
||||
|
||||
write_unlock_irq(&client->egress_lock);
|
||||
dprintk("mpoa: mpoa_caches.c: new_eg_cache_entry: unlocked\n");
|
||||
dprintk("new_eg_cache_entry: unlocked\n");
|
||||
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void update_eg_cache_entry(eg_cache_entry * entry, uint16_t holding_time)
|
||||
static void update_eg_cache_entry(eg_cache_entry *entry, uint16_t holding_time)
|
||||
{
|
||||
do_gettimeofday(&(entry->tv));
|
||||
entry->entry_state = EGRESS_RESOLVED;
|
||||
@@ -502,13 +522,14 @@ static void clear_expired(struct mpoa_client *client)
|
||||
|
||||
write_lock_irq(&client->egress_lock);
|
||||
entry = client->eg_cache;
|
||||
while(entry != NULL){
|
||||
while (entry != NULL) {
|
||||
next_entry = entry->next;
|
||||
if((now.tv_sec - entry->tv.tv_sec)
|
||||
> entry->ctrl_info.holding_time){
|
||||
if ((now.tv_sec - entry->tv.tv_sec)
|
||||
> entry->ctrl_info.holding_time) {
|
||||
msg.type = SND_EGRESS_PURGE;
|
||||
msg.content.eg_info = entry->ctrl_info;
|
||||
dprintk("mpoa: mpoa_caches.c: egress_cache: holding time expired, cache_id = %lu.\n",ntohl(entry->ctrl_info.cache_id));
|
||||
dprintk("egress_cache: holding time expired, cache_id = %u.\n",
|
||||
ntohl(entry->ctrl_info.cache_id));
|
||||
msg_to_mpoad(&msg, client);
|
||||
client->eg_ops->remove_entry(entry, client);
|
||||
}
|
||||
@@ -522,7 +543,7 @@ static void clear_expired(struct mpoa_client *client)
|
||||
static void eg_destroy_cache(struct mpoa_client *mpc)
|
||||
{
|
||||
write_lock_irq(&mpc->egress_lock);
|
||||
while(mpc->eg_cache != NULL)
|
||||
while (mpc->eg_cache != NULL)
|
||||
mpc->eg_ops->remove_entry(mpc->eg_cache, mpc);
|
||||
write_unlock_irq(&mpc->egress_lock);
|
||||
|
||||
@@ -530,7 +551,6 @@ static void eg_destroy_cache(struct mpoa_client *mpc)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static struct in_cache_ops ingress_ops = {
|
||||
in_cache_add_entry, /* add_entry */
|
||||
in_cache_get, /* get */
|
||||
|
||||
+49
-40
@@ -1,3 +1,4 @@
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#include <linux/errno.h>
|
||||
@@ -8,7 +9,7 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/atmmpc.h>
|
||||
#include <linux/atm.h>
|
||||
#include "mpc.h"
|
||||
@@ -20,9 +21,23 @@
|
||||
*/
|
||||
|
||||
#if 1
|
||||
#define dprintk printk /* debug */
|
||||
#define dprintk(format, args...) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
|
||||
#else
|
||||
#define dprintk(format,args...)
|
||||
#define dprintk(format, args...) \
|
||||
do { if (0) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
#define ddprintk(format, args...) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args) /* debug */
|
||||
#else
|
||||
#define ddprintk(format, args...) \
|
||||
do { if (0) \
|
||||
printk(KERN_DEBUG "mpoa:%s: " format, __FILE__, ##args);\
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
#define STAT_FILE_NAME "mpc" /* Our statistic file's name */
|
||||
@@ -51,42 +66,37 @@ static const struct file_operations mpc_file_operations = {
|
||||
/*
|
||||
* Returns the state of an ingress cache entry as a string
|
||||
*/
|
||||
static const char *ingress_state_string(int state){
|
||||
switch(state) {
|
||||
static const char *ingress_state_string(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case INGRESS_RESOLVING:
|
||||
return "resolving ";
|
||||
break;
|
||||
case INGRESS_RESOLVED:
|
||||
return "resolved ";
|
||||
break;
|
||||
case INGRESS_INVALID:
|
||||
return "invalid ";
|
||||
break;
|
||||
case INGRESS_REFRESHING:
|
||||
return "refreshing ";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the state of an egress cache entry as a string
|
||||
*/
|
||||
static const char *egress_state_string(int state){
|
||||
switch(state) {
|
||||
static const char *egress_state_string(int state)
|
||||
{
|
||||
switch (state) {
|
||||
case EGRESS_RESOLVED:
|
||||
return "resolved ";
|
||||
break;
|
||||
case EGRESS_PURGE:
|
||||
return "purge ";
|
||||
break;
|
||||
case EGRESS_INVALID:
|
||||
return "invalid ";
|
||||
break;
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -123,7 +133,6 @@ static void mpc_stop(struct seq_file *m, void *v)
|
||||
static int mpc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct mpoa_client *mpc = v;
|
||||
unsigned char *temp;
|
||||
int i;
|
||||
in_cache_entry *in_entry;
|
||||
eg_cache_entry *eg_entry;
|
||||
@@ -140,15 +149,17 @@ static int mpc_show(struct seq_file *m, void *v)
|
||||
do_gettimeofday(&now);
|
||||
|
||||
for (in_entry = mpc->in_cache; in_entry; in_entry = in_entry->next) {
|
||||
temp = (unsigned char *)&in_entry->ctrl_info.in_dst_ip;
|
||||
sprintf(ip_string,"%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
|
||||
sprintf(ip_string, "%pI4", &in_entry->ctrl_info.in_dst_ip);
|
||||
seq_printf(m, "%-16s%s%-14lu%-12u",
|
||||
ip_string,
|
||||
ingress_state_string(in_entry->entry_state),
|
||||
in_entry->ctrl_info.holding_time-(now.tv_sec-in_entry->tv.tv_sec),
|
||||
in_entry->packets_fwded);
|
||||
ip_string,
|
||||
ingress_state_string(in_entry->entry_state),
|
||||
in_entry->ctrl_info.holding_time -
|
||||
(now.tv_sec-in_entry->tv.tv_sec),
|
||||
in_entry->packets_fwded);
|
||||
if (in_entry->shortcut)
|
||||
seq_printf(m, " %-3d %-3d",in_entry->shortcut->vpi,in_entry->shortcut->vci);
|
||||
seq_printf(m, " %-3d %-3d",
|
||||
in_entry->shortcut->vpi,
|
||||
in_entry->shortcut->vci);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
|
||||
@@ -156,21 +167,23 @@ static int mpc_show(struct seq_file *m, void *v)
|
||||
seq_printf(m, "Egress Entries:\nIngress MPC ATM addr\nCache-id State Holding time Packets recvd Latest IP addr VPI VCI\n");
|
||||
for (eg_entry = mpc->eg_cache; eg_entry; eg_entry = eg_entry->next) {
|
||||
unsigned char *p = eg_entry->ctrl_info.in_MPC_data_ATM_addr;
|
||||
for(i = 0; i < ATM_ESA_LEN; i++)
|
||||
for (i = 0; i < ATM_ESA_LEN; i++)
|
||||
seq_printf(m, "%02x", p[i]);
|
||||
seq_printf(m, "\n%-16lu%s%-14lu%-15u",
|
||||
(unsigned long)ntohl(eg_entry->ctrl_info.cache_id),
|
||||
egress_state_string(eg_entry->entry_state),
|
||||
(eg_entry->ctrl_info.holding_time-(now.tv_sec-eg_entry->tv.tv_sec)),
|
||||
(eg_entry->ctrl_info.holding_time -
|
||||
(now.tv_sec-eg_entry->tv.tv_sec)),
|
||||
eg_entry->packets_rcvd);
|
||||
|
||||
/* latest IP address */
|
||||
temp = (unsigned char *)&eg_entry->latest_ip_addr;
|
||||
sprintf(ip_string, "%d.%d.%d.%d", temp[0], temp[1], temp[2], temp[3]);
|
||||
sprintf(ip_string, "%pI4", &eg_entry->latest_ip_addr);
|
||||
seq_printf(m, "%-16s", ip_string);
|
||||
|
||||
if (eg_entry->shortcut)
|
||||
seq_printf(m, " %-3d %-3d",eg_entry->shortcut->vpi,eg_entry->shortcut->vci);
|
||||
seq_printf(m, " %-3d %-3d",
|
||||
eg_entry->shortcut->vpi,
|
||||
eg_entry->shortcut->vci);
|
||||
seq_printf(m, "\n");
|
||||
}
|
||||
seq_printf(m, "\n");
|
||||
@@ -258,12 +271,9 @@ static int parse_qos(const char *buff)
|
||||
qos.rxtp.max_pcr = rx_pcr;
|
||||
qos.rxtp.max_sdu = rx_sdu;
|
||||
qos.aal = ATM_AAL5;
|
||||
dprintk("mpoa: mpoa_proc.c: parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
|
||||
qos.txtp.max_pcr,
|
||||
qos.txtp.max_sdu,
|
||||
qos.rxtp.max_pcr,
|
||||
qos.rxtp.max_sdu
|
||||
);
|
||||
dprintk("parse_qos(): setting qos paramameters to tx=%d,%d rx=%d,%d\n",
|
||||
qos.txtp.max_pcr, qos.txtp.max_sdu,
|
||||
qos.rxtp.max_pcr, qos.rxtp.max_sdu);
|
||||
|
||||
atm_mpoa_add_qos(ipaddr, &qos);
|
||||
return 1;
|
||||
@@ -278,7 +288,7 @@ int mpc_proc_init(void)
|
||||
|
||||
p = proc_create(STAT_FILE_NAME, 0, atm_proc_root, &mpc_file_operations);
|
||||
if (!p) {
|
||||
printk(KERN_ERR "Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
|
||||
pr_err("Unable to initialize /proc/atm/%s\n", STAT_FILE_NAME);
|
||||
return -ENOMEM;
|
||||
}
|
||||
return 0;
|
||||
@@ -289,10 +299,9 @@ int mpc_proc_init(void)
|
||||
*/
|
||||
void mpc_proc_clean(void)
|
||||
{
|
||||
remove_proc_entry(STAT_FILE_NAME,atm_proc_root);
|
||||
remove_proc_entry(STAT_FILE_NAME, atm_proc_root);
|
||||
}
|
||||
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
|
||||
|
||||
+16
-12
@@ -33,6 +33,8 @@
|
||||
* These hooks are not yet available in ppp_generic
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/skbuff.h>
|
||||
@@ -132,7 +134,7 @@ static void pppoatm_unassign_vcc(struct atm_vcc *atmvcc)
|
||||
static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||
{
|
||||
struct pppoatm_vcc *pvcc = atmvcc_to_pvcc(atmvcc);
|
||||
pr_debug("pppoatm push\n");
|
||||
pr_debug("\n");
|
||||
if (skb == NULL) { /* VCC was closed */
|
||||
pr_debug("removing ATMPPP VCC %p\n", pvcc);
|
||||
pppoatm_unassign_vcc(atmvcc);
|
||||
@@ -165,17 +167,17 @@ static void pppoatm_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
|
||||
pvcc->chan.mtu += LLC_LEN;
|
||||
break;
|
||||
}
|
||||
pr_debug("Couldn't autodetect yet "
|
||||
"(skb: %02X %02X %02X %02X %02X %02X)\n",
|
||||
skb->data[0], skb->data[1], skb->data[2],
|
||||
skb->data[3], skb->data[4], skb->data[5]);
|
||||
pr_debug("Couldn't autodetect yet (skb: %02X %02X %02X %02X %02X %02X)\n",
|
||||
skb->data[0], skb->data[1], skb->data[2],
|
||||
skb->data[3], skb->data[4], skb->data[5]);
|
||||
goto error;
|
||||
case e_vc:
|
||||
break;
|
||||
}
|
||||
ppp_input(&pvcc->chan, skb);
|
||||
return;
|
||||
error:
|
||||
|
||||
error:
|
||||
kfree_skb(skb);
|
||||
ppp_input_error(&pvcc->chan, 0);
|
||||
}
|
||||
@@ -194,7 +196,7 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
||||
{
|
||||
struct pppoatm_vcc *pvcc = chan_to_pvcc(chan);
|
||||
ATM_SKB(skb)->vcc = pvcc->atmvcc;
|
||||
pr_debug("pppoatm_send (skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
|
||||
pr_debug("(skb=0x%p, vcc=0x%p)\n", skb, pvcc->atmvcc);
|
||||
if (skb->data[0] == '\0' && (pvcc->flags & SC_COMP_PROT))
|
||||
(void) skb_pull(skb, 1);
|
||||
switch (pvcc->encaps) { /* LLC encapsulation needed */
|
||||
@@ -208,7 +210,8 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
||||
goto nospace;
|
||||
}
|
||||
kfree_skb(skb);
|
||||
if ((skb = n) == NULL)
|
||||
skb = n;
|
||||
if (skb == NULL)
|
||||
return DROP_PACKET;
|
||||
} else if (!atm_may_send(pvcc->atmvcc, skb->truesize))
|
||||
goto nospace;
|
||||
@@ -226,11 +229,11 @@ static int pppoatm_send(struct ppp_channel *chan, struct sk_buff *skb)
|
||||
|
||||
atomic_add(skb->truesize, &sk_atm(ATM_SKB(skb)->vcc)->sk_wmem_alloc);
|
||||
ATM_SKB(skb)->atm_options = ATM_SKB(skb)->vcc->atm_options;
|
||||
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n", skb, ATM_SKB(skb)->vcc,
|
||||
ATM_SKB(skb)->vcc->dev);
|
||||
pr_debug("atm_skb(%p)->vcc(%p)->dev(%p)\n",
|
||||
skb, ATM_SKB(skb)->vcc, ATM_SKB(skb)->vcc->dev);
|
||||
return ATM_SKB(skb)->vcc->send(ATM_SKB(skb)->vcc, skb)
|
||||
? DROP_PACKET : 1;
|
||||
nospace:
|
||||
nospace:
|
||||
/*
|
||||
* We don't have space to send this SKB now, but we might have
|
||||
* already applied SC_COMP_PROT compression, so may need to undo
|
||||
@@ -289,7 +292,8 @@ static int pppoatm_assign_vcc(struct atm_vcc *atmvcc, void __user *arg)
|
||||
(be.encaps == e_vc ? 0 : LLC_LEN);
|
||||
pvcc->wakeup_tasklet = tasklet_proto;
|
||||
pvcc->wakeup_tasklet.data = (unsigned long) &pvcc->chan;
|
||||
if ((err = ppp_register_channel(&pvcc->chan)) != 0) {
|
||||
err = ppp_register_channel(&pvcc->chan);
|
||||
if (err != 0) {
|
||||
kfree(pvcc);
|
||||
return err;
|
||||
}
|
||||
|
||||
+45
-38
@@ -24,15 +24,15 @@
|
||||
#include <linux/init.h> /* for __init */
|
||||
#include <net/net_namespace.h>
|
||||
#include <net/atmclip.h>
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/param.h> /* for HZ */
|
||||
#include <asm/atomic.h>
|
||||
#include <asm/param.h> /* for HZ */
|
||||
#include "resources.h"
|
||||
#include "common.h" /* atm_proc_init prototype */
|
||||
#include "signaling.h" /* to get sigd - ugly too */
|
||||
|
||||
static ssize_t proc_dev_atm_read(struct file *file,char __user *buf,size_t count,
|
||||
loff_t *pos);
|
||||
static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
|
||||
size_t count, loff_t *pos);
|
||||
|
||||
static const struct file_operations proc_atm_dev_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
@@ -43,9 +43,9 @@ static void add_stats(struct seq_file *seq, const char *aal,
|
||||
const struct k_atm_aal_stats *stats)
|
||||
{
|
||||
seq_printf(seq, "%s ( %d %d %d %d %d )", aal,
|
||||
atomic_read(&stats->tx),atomic_read(&stats->tx_err),
|
||||
atomic_read(&stats->rx),atomic_read(&stats->rx_err),
|
||||
atomic_read(&stats->rx_drop));
|
||||
atomic_read(&stats->tx), atomic_read(&stats->tx_err),
|
||||
atomic_read(&stats->rx), atomic_read(&stats->rx_err),
|
||||
atomic_read(&stats->rx_drop));
|
||||
}
|
||||
|
||||
static void atm_dev_info(struct seq_file *seq, const struct atm_dev *dev)
|
||||
@@ -151,8 +151,8 @@ static void *vcc_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
|
||||
static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
|
||||
{
|
||||
static const char *const class_name[] =
|
||||
{"off","UBR","CBR","VBR","ABR"};
|
||||
static const char *const class_name[] = {
|
||||
"off", "UBR", "CBR", "VBR", "ABR"};
|
||||
static const char *const aal_name[] = {
|
||||
"---", "1", "2", "3/4", /* 0- 3 */
|
||||
"???", "5", "???", "???", /* 4- 7 */
|
||||
@@ -160,11 +160,12 @@ static void pvc_info(struct seq_file *seq, struct atm_vcc *vcc)
|
||||
"???", "0", "???", "???"}; /* 12-15 */
|
||||
|
||||
seq_printf(seq, "%3d %3d %5d %-3s %7d %-5s %7d %-6s",
|
||||
vcc->dev->number,vcc->vpi,vcc->vci,
|
||||
vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" :
|
||||
aal_name[vcc->qos.aal],vcc->qos.rxtp.min_pcr,
|
||||
class_name[vcc->qos.rxtp.traffic_class],vcc->qos.txtp.min_pcr,
|
||||
class_name[vcc->qos.txtp.traffic_class]);
|
||||
vcc->dev->number, vcc->vpi, vcc->vci,
|
||||
vcc->qos.aal >= ARRAY_SIZE(aal_name) ? "err" :
|
||||
aal_name[vcc->qos.aal], vcc->qos.rxtp.min_pcr,
|
||||
class_name[vcc->qos.rxtp.traffic_class],
|
||||
vcc->qos.txtp.min_pcr,
|
||||
class_name[vcc->qos.txtp.traffic_class]);
|
||||
if (test_bit(ATM_VF_IS_CLIP, &vcc->flags)) {
|
||||
struct clip_vcc *clip_vcc = CLIP_VCC(vcc);
|
||||
struct net_device *dev;
|
||||
@@ -195,19 +196,20 @@ static void vcc_info(struct seq_file *seq, struct atm_vcc *vcc)
|
||||
seq_printf(seq, "%3d %3d %5d ", vcc->dev->number, vcc->vpi,
|
||||
vcc->vci);
|
||||
switch (sk->sk_family) {
|
||||
case AF_ATMPVC:
|
||||
seq_printf(seq, "PVC");
|
||||
break;
|
||||
case AF_ATMSVC:
|
||||
seq_printf(seq, "SVC");
|
||||
break;
|
||||
default:
|
||||
seq_printf(seq, "%3d", sk->sk_family);
|
||||
case AF_ATMPVC:
|
||||
seq_printf(seq, "PVC");
|
||||
break;
|
||||
case AF_ATMSVC:
|
||||
seq_printf(seq, "SVC");
|
||||
break;
|
||||
default:
|
||||
seq_printf(seq, "%3d", sk->sk_family);
|
||||
}
|
||||
seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n", vcc->flags, sk->sk_err,
|
||||
sk_wmem_alloc_get(sk), sk->sk_sndbuf,
|
||||
sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
|
||||
atomic_read(&sk->sk_refcnt));
|
||||
seq_printf(seq, " %04lx %5d %7d/%7d %7d/%7d [%d]\n",
|
||||
vcc->flags, sk->sk_err,
|
||||
sk_wmem_alloc_get(sk), sk->sk_sndbuf,
|
||||
sk_rmem_alloc_get(sk), sk->sk_rcvbuf,
|
||||
atomic_read(&sk->sk_refcnt));
|
||||
}
|
||||
|
||||
static void svc_info(struct seq_file *seq, struct atm_vcc *vcc)
|
||||
@@ -236,7 +238,7 @@ static int atm_dev_seq_show(struct seq_file *seq, void *v)
|
||||
"Itf Type ESI/\"MAC\"addr "
|
||||
"AAL(TX,err,RX,err,drop) ... [refcnt]\n";
|
||||
|
||||
if (v == SEQ_START_TOKEN)
|
||||
if (v == &atm_devs)
|
||||
seq_puts(seq, atm_dev_banner);
|
||||
else {
|
||||
struct atm_dev *dev = list_entry(v, struct atm_dev, dev_list);
|
||||
@@ -376,32 +378,35 @@ static ssize_t proc_dev_atm_read(struct file *file, char __user *buf,
|
||||
unsigned long page;
|
||||
int length;
|
||||
|
||||
if (count == 0) return 0;
|
||||
if (count == 0)
|
||||
return 0;
|
||||
page = get_zeroed_page(GFP_KERNEL);
|
||||
if (!page) return -ENOMEM;
|
||||
if (!page)
|
||||
return -ENOMEM;
|
||||
dev = PDE(file->f_path.dentry->d_inode)->data;
|
||||
if (!dev->ops->proc_read)
|
||||
length = -EINVAL;
|
||||
else {
|
||||
length = dev->ops->proc_read(dev,pos,(char *) page);
|
||||
if (length > count) length = -EINVAL;
|
||||
length = dev->ops->proc_read(dev, pos, (char *)page);
|
||||
if (length > count)
|
||||
length = -EINVAL;
|
||||
}
|
||||
if (length >= 0) {
|
||||
if (copy_to_user(buf,(char *) page,length)) length = -EFAULT;
|
||||
if (copy_to_user(buf, (char *)page, length))
|
||||
length = -EFAULT;
|
||||
(*pos)++;
|
||||
}
|
||||
free_page(page);
|
||||
return length;
|
||||
}
|
||||
|
||||
|
||||
struct proc_dir_entry *atm_proc_root;
|
||||
EXPORT_SYMBOL(atm_proc_root);
|
||||
|
||||
|
||||
int atm_proc_dev_register(struct atm_dev *dev)
|
||||
{
|
||||
int digits,num;
|
||||
int digits, num;
|
||||
int error;
|
||||
|
||||
/* No proc info */
|
||||
@@ -410,26 +415,28 @@ int atm_proc_dev_register(struct atm_dev *dev)
|
||||
|
||||
error = -ENOMEM;
|
||||
digits = 0;
|
||||
for (num = dev->number; num; num /= 10) digits++;
|
||||
if (!digits) digits++;
|
||||
for (num = dev->number; num; num /= 10)
|
||||
digits++;
|
||||
if (!digits)
|
||||
digits++;
|
||||
|
||||
dev->proc_name = kmalloc(strlen(dev->type) + digits + 2, GFP_KERNEL);
|
||||
if (!dev->proc_name)
|
||||
goto err_out;
|
||||
sprintf(dev->proc_name,"%s:%d",dev->type, dev->number);
|
||||
sprintf(dev->proc_name, "%s:%d", dev->type, dev->number);
|
||||
|
||||
dev->proc_entry = proc_create_data(dev->proc_name, 0, atm_proc_root,
|
||||
&proc_atm_dev_ops, dev);
|
||||
if (!dev->proc_entry)
|
||||
goto err_free_name;
|
||||
return 0;
|
||||
|
||||
err_free_name:
|
||||
kfree(dev->proc_name);
|
||||
err_out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
void atm_proc_dev_deregister(struct atm_dev *dev)
|
||||
{
|
||||
if (!dev->ops->proc_read)
|
||||
|
||||
+21
-22
@@ -17,32 +17,35 @@
|
||||
#include "common.h" /* common for PVCs and SVCs */
|
||||
|
||||
|
||||
static int pvc_shutdown(struct socket *sock,int how)
|
||||
static int pvc_shutdown(struct socket *sock, int how)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int pvc_bind(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int sockaddr_len)
|
||||
static int pvc_bind(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int sockaddr_len)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct sockaddr_atmpvc *addr;
|
||||
struct atm_vcc *vcc;
|
||||
int error;
|
||||
|
||||
if (sockaddr_len != sizeof(struct sockaddr_atmpvc)) return -EINVAL;
|
||||
addr = (struct sockaddr_atmpvc *) sockaddr;
|
||||
if (addr->sap_family != AF_ATMPVC) return -EAFNOSUPPORT;
|
||||
if (sockaddr_len != sizeof(struct sockaddr_atmpvc))
|
||||
return -EINVAL;
|
||||
addr = (struct sockaddr_atmpvc *)sockaddr;
|
||||
if (addr->sap_family != AF_ATMPVC)
|
||||
return -EAFNOSUPPORT;
|
||||
lock_sock(sk);
|
||||
vcc = ATM_SD(sock);
|
||||
if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
|
||||
error = -EBADFD;
|
||||
goto out;
|
||||
}
|
||||
if (test_bit(ATM_VF_PARTIAL,&vcc->flags)) {
|
||||
if (vcc->vpi != ATM_VPI_UNSPEC) addr->sap_addr.vpi = vcc->vpi;
|
||||
if (vcc->vci != ATM_VCI_UNSPEC) addr->sap_addr.vci = vcc->vci;
|
||||
if (test_bit(ATM_VF_PARTIAL, &vcc->flags)) {
|
||||
if (vcc->vpi != ATM_VPI_UNSPEC)
|
||||
addr->sap_addr.vpi = vcc->vpi;
|
||||
if (vcc->vci != ATM_VCI_UNSPEC)
|
||||
addr->sap_addr.vci = vcc->vci;
|
||||
}
|
||||
error = vcc_connect(sock, addr->sap_addr.itf, addr->sap_addr.vpi,
|
||||
addr->sap_addr.vci);
|
||||
@@ -51,11 +54,10 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int pvc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int sockaddr_len,int flags)
|
||||
static int pvc_connect(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int sockaddr_len, int flags)
|
||||
{
|
||||
return pvc_bind(sock,sockaddr,sockaddr_len);
|
||||
return pvc_bind(sock, sockaddr, sockaddr_len);
|
||||
}
|
||||
|
||||
static int pvc_setsockopt(struct socket *sock, int level, int optname,
|
||||
@@ -70,7 +72,6 @@ static int pvc_setsockopt(struct socket *sock, int level, int optname,
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int pvc_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
@@ -83,16 +84,16 @@ static int pvc_getsockopt(struct socket *sock, int level, int optname,
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int *sockaddr_len,int peer)
|
||||
static int pvc_getname(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int *sockaddr_len, int peer)
|
||||
{
|
||||
struct sockaddr_atmpvc *addr;
|
||||
struct atm_vcc *vcc = ATM_SD(sock);
|
||||
|
||||
if (!vcc->dev || !test_bit(ATM_VF_ADDR,&vcc->flags)) return -ENOTCONN;
|
||||
if (!vcc->dev || !test_bit(ATM_VF_ADDR, &vcc->flags))
|
||||
return -ENOTCONN;
|
||||
*sockaddr_len = sizeof(struct sockaddr_atmpvc);
|
||||
addr = (struct sockaddr_atmpvc *) sockaddr;
|
||||
addr = (struct sockaddr_atmpvc *)sockaddr;
|
||||
addr->sap_family = AF_ATMPVC;
|
||||
addr->sap_addr.itf = vcc->dev->number;
|
||||
addr->sap_addr.vpi = vcc->vpi;
|
||||
@@ -100,7 +101,6 @@ static int pvc_getname(struct socket *sock,struct sockaddr *sockaddr,
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct proto_ops pvc_proto_ops = {
|
||||
.family = PF_ATMPVC,
|
||||
.owner = THIS_MODULE,
|
||||
@@ -137,7 +137,6 @@ static int pvc_create(struct net *net, struct socket *sock, int protocol,
|
||||
return vcc_create(net, sock, protocol, PF_ATMPVC);
|
||||
}
|
||||
|
||||
|
||||
static const struct net_proto_family pvc_family_ops = {
|
||||
.family = PF_ATMPVC,
|
||||
.create = pvc_create,
|
||||
|
||||
+10
-16
@@ -2,6 +2,7 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/module.h>
|
||||
#include <linux/atmdev.h>
|
||||
@@ -17,7 +18,7 @@
|
||||
* SKB == NULL indicates that the link is being closed
|
||||
*/
|
||||
|
||||
static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
static void atm_push_raw(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
if (skb) {
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
@@ -27,36 +28,33 @@ static void atm_push_raw(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void atm_pop_raw(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
static void atm_pop_raw(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
|
||||
pr_debug("APopR (%d) %d -= %d\n", vcc->vci,
|
||||
sk_wmem_alloc_get(sk), skb->truesize);
|
||||
pr_debug("(%d) %d -= %d\n",
|
||||
vcc->vci, sk_wmem_alloc_get(sk), skb->truesize);
|
||||
atomic_sub(skb->truesize, &sk->sk_wmem_alloc);
|
||||
dev_kfree_skb_any(skb);
|
||||
sk->sk_write_space(sk);
|
||||
}
|
||||
|
||||
|
||||
static int atm_send_aal0(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
static int atm_send_aal0(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
/*
|
||||
* Note that if vpi/vci are _ANY or _UNSPEC the below will
|
||||
* still work
|
||||
*/
|
||||
if (!capable(CAP_NET_ADMIN) &&
|
||||
(((u32 *) skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
|
||||
((vcc->vpi << ATM_HDR_VPI_SHIFT) | (vcc->vci << ATM_HDR_VCI_SHIFT)))
|
||||
{
|
||||
(((u32 *)skb->data)[0] & (ATM_HDR_VPI_MASK | ATM_HDR_VCI_MASK)) !=
|
||||
((vcc->vpi << ATM_HDR_VPI_SHIFT) |
|
||||
(vcc->vci << ATM_HDR_VCI_SHIFT))) {
|
||||
kfree_skb(skb);
|
||||
return -EADDRNOTAVAIL;
|
||||
}
|
||||
return vcc->dev->ops->send(vcc,skb);
|
||||
return vcc->dev->ops->send(vcc, skb);
|
||||
}
|
||||
|
||||
|
||||
int atm_init_aal0(struct atm_vcc *vcc)
|
||||
{
|
||||
vcc->push = atm_push_raw;
|
||||
@@ -66,7 +64,6 @@ int atm_init_aal0(struct atm_vcc *vcc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int atm_init_aal34(struct atm_vcc *vcc)
|
||||
{
|
||||
vcc->push = atm_push_raw;
|
||||
@@ -76,7 +73,6 @@ int atm_init_aal34(struct atm_vcc *vcc)
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int atm_init_aal5(struct atm_vcc *vcc)
|
||||
{
|
||||
vcc->push = atm_push_raw;
|
||||
@@ -85,6 +81,4 @@ int atm_init_aal5(struct atm_vcc *vcc)
|
||||
vcc->send = vcc->dev->ops->send;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(atm_init_aal5);
|
||||
|
||||
+205
-229
@@ -7,6 +7,7 @@
|
||||
* 2002/01 - don't free the whole struct sock on sk->destruct time,
|
||||
* use the default destruct function initialized by sock_init_data */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/ctype.h>
|
||||
#include <linux/string.h>
|
||||
@@ -70,7 +71,7 @@ struct atm_dev *atm_dev_lookup(int number)
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
return dev;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(atm_dev_lookup);
|
||||
|
||||
struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
|
||||
int number, unsigned long *flags)
|
||||
@@ -79,13 +80,13 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
|
||||
|
||||
dev = __alloc_atm_dev(type);
|
||||
if (!dev) {
|
||||
printk(KERN_ERR "atm_dev_register: no space for dev %s\n",
|
||||
type);
|
||||
pr_err("no space for dev %s\n", type);
|
||||
return NULL;
|
||||
}
|
||||
mutex_lock(&atm_dev_mutex);
|
||||
if (number != -1) {
|
||||
if ((inuse = __atm_dev_lookup(number))) {
|
||||
inuse = __atm_dev_lookup(number);
|
||||
if (inuse) {
|
||||
atm_dev_put(inuse);
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
kfree(dev);
|
||||
@@ -109,16 +110,12 @@ struct atm_dev *atm_dev_register(const char *type, const struct atmdev_ops *ops,
|
||||
atomic_set(&dev->refcnt, 1);
|
||||
|
||||
if (atm_proc_dev_register(dev) < 0) {
|
||||
printk(KERN_ERR "atm_dev_register: "
|
||||
"atm_proc_dev_register failed for dev %s\n",
|
||||
type);
|
||||
pr_err("atm_proc_dev_register failed for dev %s\n", type);
|
||||
goto out_fail;
|
||||
}
|
||||
|
||||
if (atm_register_sysfs(dev) < 0) {
|
||||
printk(KERN_ERR "atm_dev_register: "
|
||||
"atm_register_sysfs failed for dev %s\n",
|
||||
type);
|
||||
pr_err("atm_register_sysfs failed for dev %s\n", type);
|
||||
atm_proc_dev_deregister(dev);
|
||||
goto out_fail;
|
||||
}
|
||||
@@ -134,7 +131,7 @@ out_fail:
|
||||
dev = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(atm_dev_register);
|
||||
|
||||
void atm_dev_deregister(struct atm_dev *dev)
|
||||
{
|
||||
@@ -156,7 +153,7 @@ void atm_dev_deregister(struct atm_dev *dev)
|
||||
|
||||
atm_dev_put(dev);
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(atm_dev_deregister);
|
||||
|
||||
static void copy_aal_stats(struct k_atm_aal_stats *from,
|
||||
struct atm_aal_stats *to)
|
||||
@@ -166,7 +163,6 @@ static void copy_aal_stats(struct k_atm_aal_stats *from,
|
||||
#undef __HANDLE_ITEM
|
||||
}
|
||||
|
||||
|
||||
static void subtract_aal_stats(struct k_atm_aal_stats *from,
|
||||
struct atm_aal_stats *to)
|
||||
{
|
||||
@@ -175,8 +171,8 @@ static void subtract_aal_stats(struct k_atm_aal_stats *from,
|
||||
#undef __HANDLE_ITEM
|
||||
}
|
||||
|
||||
|
||||
static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, int zero)
|
||||
static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg,
|
||||
int zero)
|
||||
{
|
||||
struct atm_dev_stats tmp;
|
||||
int error = 0;
|
||||
@@ -194,7 +190,6 @@ static int fetch_stats(struct atm_dev *dev, struct atm_dev_stats __user *arg, in
|
||||
return error ? -EFAULT : 0;
|
||||
}
|
||||
|
||||
|
||||
int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
|
||||
{
|
||||
void __user *buf;
|
||||
@@ -210,50 +205,49 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
|
||||
#endif
|
||||
|
||||
switch (cmd) {
|
||||
case ATM_GETNAMES:
|
||||
|
||||
if (compat) {
|
||||
case ATM_GETNAMES:
|
||||
if (compat) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_atm_iobuf __user *ciobuf = arg;
|
||||
compat_uptr_t cbuf;
|
||||
iobuf_len = &ciobuf->length;
|
||||
if (get_user(cbuf, &ciobuf->buffer))
|
||||
return -EFAULT;
|
||||
buf = compat_ptr(cbuf);
|
||||
#endif
|
||||
} else {
|
||||
struct atm_iobuf __user *iobuf = arg;
|
||||
iobuf_len = &iobuf->length;
|
||||
if (get_user(buf, &iobuf->buffer))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (get_user(len, iobuf_len))
|
||||
struct compat_atm_iobuf __user *ciobuf = arg;
|
||||
compat_uptr_t cbuf;
|
||||
iobuf_len = &ciobuf->length;
|
||||
if (get_user(cbuf, &ciobuf->buffer))
|
||||
return -EFAULT;
|
||||
mutex_lock(&atm_dev_mutex);
|
||||
list_for_each(p, &atm_devs)
|
||||
size += sizeof(int);
|
||||
if (size > len) {
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
return -E2BIG;
|
||||
}
|
||||
tmp_buf = kmalloc(size, GFP_ATOMIC);
|
||||
if (!tmp_buf) {
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
tmp_p = tmp_buf;
|
||||
list_for_each(p, &atm_devs) {
|
||||
dev = list_entry(p, struct atm_dev, dev_list);
|
||||
*tmp_p++ = dev->number;
|
||||
}
|
||||
buf = compat_ptr(cbuf);
|
||||
#endif
|
||||
} else {
|
||||
struct atm_iobuf __user *iobuf = arg;
|
||||
iobuf_len = &iobuf->length;
|
||||
if (get_user(buf, &iobuf->buffer))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (get_user(len, iobuf_len))
|
||||
return -EFAULT;
|
||||
mutex_lock(&atm_dev_mutex);
|
||||
list_for_each(p, &atm_devs)
|
||||
size += sizeof(int);
|
||||
if (size > len) {
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
error = ((copy_to_user(buf, tmp_buf, size)) ||
|
||||
put_user(size, iobuf_len))
|
||||
? -EFAULT : 0;
|
||||
kfree(tmp_buf);
|
||||
return error;
|
||||
default:
|
||||
break;
|
||||
return -E2BIG;
|
||||
}
|
||||
tmp_buf = kmalloc(size, GFP_ATOMIC);
|
||||
if (!tmp_buf) {
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
return -ENOMEM;
|
||||
}
|
||||
tmp_p = tmp_buf;
|
||||
list_for_each(p, &atm_devs) {
|
||||
dev = list_entry(p, struct atm_dev, dev_list);
|
||||
*tmp_p++ = dev->number;
|
||||
}
|
||||
mutex_unlock(&atm_dev_mutex);
|
||||
error = ((copy_to_user(buf, tmp_buf, size)) ||
|
||||
put_user(size, iobuf_len))
|
||||
? -EFAULT : 0;
|
||||
kfree(tmp_buf);
|
||||
return error;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (compat) {
|
||||
@@ -282,166 +276,167 @@ int atm_dev_ioctl(unsigned int cmd, void __user *arg, int compat)
|
||||
if (get_user(number, &sioc->number))
|
||||
return -EFAULT;
|
||||
}
|
||||
if (!(dev = try_then_request_module(atm_dev_lookup(number),
|
||||
"atm-device-%d", number)))
|
||||
|
||||
dev = try_then_request_module(atm_dev_lookup(number), "atm-device-%d",
|
||||
number);
|
||||
if (!dev)
|
||||
return -ENODEV;
|
||||
|
||||
switch (cmd) {
|
||||
case ATM_GETTYPE:
|
||||
size = strlen(dev->type) + 1;
|
||||
if (copy_to_user(buf, dev->type, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_GETESI:
|
||||
size = ESI_LEN;
|
||||
if (copy_to_user(buf, dev->esi, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_SETESI:
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ESI_LEN; i++)
|
||||
if (dev->esi[i]) {
|
||||
error = -EEXIST;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_SETESIF:
|
||||
{
|
||||
unsigned char esi[ESI_LEN];
|
||||
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
if (copy_from_user(esi, buf, ESI_LEN)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
memcpy(dev->esi, esi, ESI_LEN);
|
||||
error = ESI_LEN;
|
||||
goto done;
|
||||
}
|
||||
case ATM_GETSTATZ:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_GETSTAT:
|
||||
size = sizeof(struct atm_dev_stats);
|
||||
error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
|
||||
if (error)
|
||||
goto done;
|
||||
break;
|
||||
case ATM_GETCIRANGE:
|
||||
size = sizeof(struct atm_cirange);
|
||||
if (copy_to_user(buf, &dev->ci_range, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_GETLINKRATE:
|
||||
size = sizeof(int);
|
||||
if (copy_to_user(buf, &dev->link_rate, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_RSTADDR:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
atm_reset_addr(dev, ATM_ADDR_LOCAL);
|
||||
break;
|
||||
case ATM_ADDADDR:
|
||||
case ATM_DELADDR:
|
||||
case ATM_ADDLECSADDR:
|
||||
case ATM_DELLECSADDR:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
{
|
||||
struct sockaddr_atmsvc addr;
|
||||
|
||||
if (copy_from_user(&addr, buf, sizeof(addr))) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
|
||||
error = atm_add_addr(dev, &addr,
|
||||
(cmd == ATM_ADDADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
else
|
||||
error = atm_del_addr(dev, &addr,
|
||||
(cmd == ATM_DELADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
goto done;
|
||||
}
|
||||
case ATM_GETADDR:
|
||||
case ATM_GETLECSADDR:
|
||||
error = atm_get_addr(dev, buf, len,
|
||||
(cmd == ATM_GETADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
if (error < 0)
|
||||
goto done;
|
||||
size = error;
|
||||
/* may return 0, but later on size == 0 means "don't
|
||||
write the length" */
|
||||
error = put_user(size, sioc_len)
|
||||
? -EFAULT : 0;
|
||||
case ATM_GETTYPE:
|
||||
size = strlen(dev->type) + 1;
|
||||
if (copy_to_user(buf, dev->type, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
case ATM_SETLOOP:
|
||||
if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
|
||||
__ATM_LM_XTLOC((int) (unsigned long) buf) >
|
||||
__ATM_LM_XTRMT((int) (unsigned long) buf)) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_SETCIRANGE:
|
||||
case SONET_GETSTATZ:
|
||||
case SONET_SETDIAG:
|
||||
case SONET_CLRDIAG:
|
||||
case SONET_SETFRAMING:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (compat) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (!dev->ops->compat_ioctl) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
size = dev->ops->compat_ioctl(dev, cmd, buf);
|
||||
#endif
|
||||
} else {
|
||||
if (!dev->ops->ioctl) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
size = dev->ops->ioctl(dev, cmd, buf);
|
||||
}
|
||||
if (size < 0) {
|
||||
error = (size == -ENOIOCTLCMD ? -EINVAL : size);
|
||||
}
|
||||
break;
|
||||
case ATM_GETESI:
|
||||
size = ESI_LEN;
|
||||
if (copy_to_user(buf, dev->esi, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_SETESI:
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < ESI_LEN; i++)
|
||||
if (dev->esi[i]) {
|
||||
error = -EEXIST;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_SETESIF:
|
||||
{
|
||||
unsigned char esi[ESI_LEN];
|
||||
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
if (copy_from_user(esi, buf, ESI_LEN)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
memcpy(dev->esi, esi, ESI_LEN);
|
||||
error = ESI_LEN;
|
||||
goto done;
|
||||
}
|
||||
case ATM_GETSTATZ:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_GETSTAT:
|
||||
size = sizeof(struct atm_dev_stats);
|
||||
error = fetch_stats(dev, buf, cmd == ATM_GETSTATZ);
|
||||
if (error)
|
||||
goto done;
|
||||
break;
|
||||
case ATM_GETCIRANGE:
|
||||
size = sizeof(struct atm_cirange);
|
||||
if (copy_to_user(buf, &dev->ci_range, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_GETLINKRATE:
|
||||
size = sizeof(int);
|
||||
if (copy_to_user(buf, &dev->link_rate, size)) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ATM_RSTADDR:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
atm_reset_addr(dev, ATM_ADDR_LOCAL);
|
||||
break;
|
||||
case ATM_ADDADDR:
|
||||
case ATM_DELADDR:
|
||||
case ATM_ADDLECSADDR:
|
||||
case ATM_DELLECSADDR:
|
||||
{
|
||||
struct sockaddr_atmsvc addr;
|
||||
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (copy_from_user(&addr, buf, sizeof(addr))) {
|
||||
error = -EFAULT;
|
||||
goto done;
|
||||
}
|
||||
if (cmd == ATM_ADDADDR || cmd == ATM_ADDLECSADDR)
|
||||
error = atm_add_addr(dev, &addr,
|
||||
(cmd == ATM_ADDADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
else
|
||||
error = atm_del_addr(dev, &addr,
|
||||
(cmd == ATM_DELADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
goto done;
|
||||
}
|
||||
case ATM_GETADDR:
|
||||
case ATM_GETLECSADDR:
|
||||
error = atm_get_addr(dev, buf, len,
|
||||
(cmd == ATM_GETADDR ?
|
||||
ATM_ADDR_LOCAL : ATM_ADDR_LECS));
|
||||
if (error < 0)
|
||||
goto done;
|
||||
size = error;
|
||||
/* may return 0, but later on size == 0 means "don't
|
||||
write the length" */
|
||||
error = put_user(size, sioc_len) ? -EFAULT : 0;
|
||||
goto done;
|
||||
case ATM_SETLOOP:
|
||||
if (__ATM_LM_XTRMT((int) (unsigned long) buf) &&
|
||||
__ATM_LM_XTLOC((int) (unsigned long) buf) >
|
||||
__ATM_LM_XTRMT((int) (unsigned long) buf)) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
case ATM_SETCIRANGE:
|
||||
case SONET_GETSTATZ:
|
||||
case SONET_SETDIAG:
|
||||
case SONET_CLRDIAG:
|
||||
case SONET_SETFRAMING:
|
||||
if (!capable(CAP_NET_ADMIN)) {
|
||||
error = -EPERM;
|
||||
goto done;
|
||||
}
|
||||
/* fall through */
|
||||
default:
|
||||
if (compat) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (!dev->ops->compat_ioctl) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
size = dev->ops->compat_ioctl(dev, cmd, buf);
|
||||
#endif
|
||||
} else {
|
||||
if (!dev->ops->ioctl) {
|
||||
error = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
size = dev->ops->ioctl(dev, cmd, buf);
|
||||
}
|
||||
if (size < 0) {
|
||||
error = (size == -ENOIOCTLCMD ? -EINVAL : size);
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
||||
if (size)
|
||||
error = put_user(size, sioc_len)
|
||||
? -EFAULT : 0;
|
||||
error = put_user(size, sioc_len) ? -EFAULT : 0;
|
||||
else
|
||||
error = 0;
|
||||
done:
|
||||
@@ -449,21 +444,10 @@ done:
|
||||
return error;
|
||||
}
|
||||
|
||||
static __inline__ void *dev_get_idx(loff_t left)
|
||||
{
|
||||
struct list_head *p;
|
||||
|
||||
list_for_each(p, &atm_devs) {
|
||||
if (!--left)
|
||||
break;
|
||||
}
|
||||
return (p != &atm_devs) ? p : NULL;
|
||||
}
|
||||
|
||||
void *atm_dev_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
mutex_lock(&atm_dev_mutex);
|
||||
return *pos ? dev_get_idx(*pos) : SEQ_START_TOKEN;
|
||||
return seq_list_start_head(&atm_devs, *pos);
|
||||
}
|
||||
|
||||
void atm_dev_seq_stop(struct seq_file *seq, void *v)
|
||||
@@ -473,13 +457,5 @@ void atm_dev_seq_stop(struct seq_file *seq, void *v)
|
||||
|
||||
void *atm_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
v = (v == SEQ_START_TOKEN)
|
||||
? atm_devs.next : ((struct list_head *)v)->next;
|
||||
return (v == &atm_devs) ? NULL : v;
|
||||
return seq_list_next(v, &atm_devs, pos);
|
||||
}
|
||||
|
||||
|
||||
EXPORT_SYMBOL(atm_dev_register);
|
||||
EXPORT_SYMBOL(atm_dev_deregister);
|
||||
EXPORT_SYMBOL(atm_dev_lookup);
|
||||
|
||||
+109
-110
@@ -2,6 +2,7 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/errno.h> /* error codes */
|
||||
#include <linux/kernel.h> /* printk */
|
||||
@@ -17,7 +18,6 @@
|
||||
#include "resources.h"
|
||||
#include "signaling.h"
|
||||
|
||||
|
||||
#undef WAIT_FOR_DEMON /* #define this if system calls on SVC sockets
|
||||
should block until the demon runs.
|
||||
Danger: may cause nasty hangs if the demon
|
||||
@@ -28,60 +28,59 @@ struct atm_vcc *sigd = NULL;
|
||||
static DECLARE_WAIT_QUEUE_HEAD(sigd_sleep);
|
||||
#endif
|
||||
|
||||
|
||||
static void sigd_put_skb(struct sk_buff *skb)
|
||||
{
|
||||
#ifdef WAIT_FOR_DEMON
|
||||
DECLARE_WAITQUEUE(wait,current);
|
||||
DECLARE_WAITQUEUE(wait, current);
|
||||
|
||||
add_wait_queue(&sigd_sleep,&wait);
|
||||
add_wait_queue(&sigd_sleep, &wait);
|
||||
while (!sigd) {
|
||||
set_current_state(TASK_UNINTERRUPTIBLE);
|
||||
pr_debug("atmsvc: waiting for signaling demon...\n");
|
||||
pr_debug("atmsvc: waiting for signaling daemon...\n");
|
||||
schedule();
|
||||
}
|
||||
current->state = TASK_RUNNING;
|
||||
remove_wait_queue(&sigd_sleep,&wait);
|
||||
remove_wait_queue(&sigd_sleep, &wait);
|
||||
#else
|
||||
if (!sigd) {
|
||||
pr_debug("atmsvc: no signaling demon\n");
|
||||
pr_debug("atmsvc: no signaling daemon\n");
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
atm_force_charge(sigd,skb->truesize);
|
||||
skb_queue_tail(&sk_atm(sigd)->sk_receive_queue,skb);
|
||||
atm_force_charge(sigd, skb->truesize);
|
||||
skb_queue_tail(&sk_atm(sigd)->sk_receive_queue, skb);
|
||||
sk_atm(sigd)->sk_data_ready(sk_atm(sigd), skb->len);
|
||||
}
|
||||
|
||||
|
||||
static void modify_qos(struct atm_vcc *vcc,struct atmsvc_msg *msg)
|
||||
static void modify_qos(struct atm_vcc *vcc, struct atmsvc_msg *msg)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
|
||||
if (test_bit(ATM_VF_RELEASED,&vcc->flags) ||
|
||||
!test_bit(ATM_VF_READY,&vcc->flags))
|
||||
if (test_bit(ATM_VF_RELEASED, &vcc->flags) ||
|
||||
!test_bit(ATM_VF_READY, &vcc->flags))
|
||||
return;
|
||||
msg->type = as_error;
|
||||
if (!vcc->dev->ops->change_qos) msg->reply = -EOPNOTSUPP;
|
||||
if (!vcc->dev->ops->change_qos)
|
||||
msg->reply = -EOPNOTSUPP;
|
||||
else {
|
||||
/* should lock VCC */
|
||||
msg->reply = vcc->dev->ops->change_qos(vcc,&msg->qos,
|
||||
msg->reply);
|
||||
if (!msg->reply) msg->type = as_okay;
|
||||
msg->reply = vcc->dev->ops->change_qos(vcc, &msg->qos,
|
||||
msg->reply);
|
||||
if (!msg->reply)
|
||||
msg->type = as_okay;
|
||||
}
|
||||
/*
|
||||
* Should probably just turn around the old skb. But the, the buffer
|
||||
* space accounting needs to follow the change too. Maybe later.
|
||||
*/
|
||||
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL)))
|
||||
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
|
||||
schedule();
|
||||
*(struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg)) = *msg;
|
||||
*(struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg)) = *msg;
|
||||
sigd_put_skb(skb);
|
||||
}
|
||||
|
||||
|
||||
static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
static int sigd_send(struct atm_vcc *vcc, struct sk_buff *skb)
|
||||
{
|
||||
struct atmsvc_msg *msg;
|
||||
struct atm_vcc *session_vcc;
|
||||
@@ -90,69 +89,68 @@ static int sigd_send(struct atm_vcc *vcc,struct sk_buff *skb)
|
||||
msg = (struct atmsvc_msg *) skb->data;
|
||||
atomic_sub(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
|
||||
vcc = *(struct atm_vcc **) &msg->vcc;
|
||||
pr_debug("sigd_send %d (0x%lx)\n",(int) msg->type,
|
||||
(unsigned long) vcc);
|
||||
pr_debug("%d (0x%lx)\n", (int)msg->type, (unsigned long)vcc);
|
||||
sk = sk_atm(vcc);
|
||||
|
||||
switch (msg->type) {
|
||||
case as_okay:
|
||||
sk->sk_err = -msg->reply;
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
if (!*vcc->local.sas_addr.prv &&
|
||||
!*vcc->local.sas_addr.pub) {
|
||||
vcc->local.sas_family = AF_ATMSVC;
|
||||
memcpy(vcc->local.sas_addr.prv,
|
||||
msg->local.sas_addr.prv,ATM_ESA_LEN);
|
||||
memcpy(vcc->local.sas_addr.pub,
|
||||
msg->local.sas_addr.pub,ATM_E164_LEN+1);
|
||||
}
|
||||
session_vcc = vcc->session ? vcc->session : vcc;
|
||||
if (session_vcc->vpi || session_vcc->vci) break;
|
||||
session_vcc->itf = msg->pvc.sap_addr.itf;
|
||||
session_vcc->vpi = msg->pvc.sap_addr.vpi;
|
||||
session_vcc->vci = msg->pvc.sap_addr.vci;
|
||||
if (session_vcc->vpi || session_vcc->vci)
|
||||
session_vcc->qos = msg->qos;
|
||||
case as_okay:
|
||||
sk->sk_err = -msg->reply;
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
if (!*vcc->local.sas_addr.prv && !*vcc->local.sas_addr.pub) {
|
||||
vcc->local.sas_family = AF_ATMSVC;
|
||||
memcpy(vcc->local.sas_addr.prv,
|
||||
msg->local.sas_addr.prv, ATM_ESA_LEN);
|
||||
memcpy(vcc->local.sas_addr.pub,
|
||||
msg->local.sas_addr.pub, ATM_E164_LEN + 1);
|
||||
}
|
||||
session_vcc = vcc->session ? vcc->session : vcc;
|
||||
if (session_vcc->vpi || session_vcc->vci)
|
||||
break;
|
||||
case as_error:
|
||||
clear_bit(ATM_VF_REGIS,&vcc->flags);
|
||||
clear_bit(ATM_VF_READY,&vcc->flags);
|
||||
sk->sk_err = -msg->reply;
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
break;
|
||||
case as_indicate:
|
||||
vcc = *(struct atm_vcc **) &msg->listen_vcc;
|
||||
sk = sk_atm(vcc);
|
||||
pr_debug("as_indicate!!!\n");
|
||||
lock_sock(sk);
|
||||
if (sk_acceptq_is_full(sk)) {
|
||||
sigd_enq(NULL,as_reject,vcc,NULL,NULL);
|
||||
dev_kfree_skb(skb);
|
||||
goto as_indicate_complete;
|
||||
}
|
||||
sk->sk_ack_backlog++;
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb);
|
||||
pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
|
||||
sk->sk_state_change(sk);
|
||||
session_vcc->itf = msg->pvc.sap_addr.itf;
|
||||
session_vcc->vpi = msg->pvc.sap_addr.vpi;
|
||||
session_vcc->vci = msg->pvc.sap_addr.vci;
|
||||
if (session_vcc->vpi || session_vcc->vci)
|
||||
session_vcc->qos = msg->qos;
|
||||
break;
|
||||
case as_error:
|
||||
clear_bit(ATM_VF_REGIS, &vcc->flags);
|
||||
clear_bit(ATM_VF_READY, &vcc->flags);
|
||||
sk->sk_err = -msg->reply;
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
break;
|
||||
case as_indicate:
|
||||
vcc = *(struct atm_vcc **)&msg->listen_vcc;
|
||||
sk = sk_atm(vcc);
|
||||
pr_debug("as_indicate!!!\n");
|
||||
lock_sock(sk);
|
||||
if (sk_acceptq_is_full(sk)) {
|
||||
sigd_enq(NULL, as_reject, vcc, NULL, NULL);
|
||||
dev_kfree_skb(skb);
|
||||
goto as_indicate_complete;
|
||||
}
|
||||
sk->sk_ack_backlog++;
|
||||
skb_queue_tail(&sk->sk_receive_queue, skb);
|
||||
pr_debug("waking sk->sk_sleep 0x%p\n", sk->sk_sleep);
|
||||
sk->sk_state_change(sk);
|
||||
as_indicate_complete:
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
case as_close:
|
||||
set_bit(ATM_VF_RELEASED,&vcc->flags);
|
||||
vcc_release_async(vcc, msg->reply);
|
||||
goto out;
|
||||
case as_modify:
|
||||
modify_qos(vcc,msg);
|
||||
break;
|
||||
case as_addparty:
|
||||
case as_dropparty:
|
||||
sk->sk_err_soft = msg->reply; /* < 0 failure, otherwise ep_ref */
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ALERT "sigd_send: bad message type %d\n",
|
||||
(int) msg->type);
|
||||
return -EINVAL;
|
||||
release_sock(sk);
|
||||
return 0;
|
||||
case as_close:
|
||||
set_bit(ATM_VF_RELEASED, &vcc->flags);
|
||||
vcc_release_async(vcc, msg->reply);
|
||||
goto out;
|
||||
case as_modify:
|
||||
modify_qos(vcc, msg);
|
||||
break;
|
||||
case as_addparty:
|
||||
case as_dropparty:
|
||||
sk->sk_err_soft = msg->reply;
|
||||
/* < 0 failure, otherwise ep_ref */
|
||||
clear_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
break;
|
||||
default:
|
||||
pr_alert("bad message type %d\n", (int)msg->type);
|
||||
return -EINVAL;
|
||||
}
|
||||
sk->sk_state_change(sk);
|
||||
out:
|
||||
@@ -160,48 +158,52 @@ out:
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void sigd_enq2(struct atm_vcc *vcc,enum atmsvc_msg_type type,
|
||||
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
|
||||
const struct sockaddr_atmsvc *svc,const struct atm_qos *qos,int reply)
|
||||
void sigd_enq2(struct atm_vcc *vcc, enum atmsvc_msg_type type,
|
||||
struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
|
||||
const struct sockaddr_atmsvc *svc, const struct atm_qos *qos,
|
||||
int reply)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
struct atmsvc_msg *msg;
|
||||
static unsigned session = 0;
|
||||
|
||||
pr_debug("sigd_enq %d (0x%p)\n",(int) type,vcc);
|
||||
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg),GFP_KERNEL)))
|
||||
pr_debug("%d (0x%p)\n", (int)type, vcc);
|
||||
while (!(skb = alloc_skb(sizeof(struct atmsvc_msg), GFP_KERNEL)))
|
||||
schedule();
|
||||
msg = (struct atmsvc_msg *) skb_put(skb,sizeof(struct atmsvc_msg));
|
||||
memset(msg,0,sizeof(*msg));
|
||||
msg = (struct atmsvc_msg *)skb_put(skb, sizeof(struct atmsvc_msg));
|
||||
memset(msg, 0, sizeof(*msg));
|
||||
msg->type = type;
|
||||
*(struct atm_vcc **) &msg->vcc = vcc;
|
||||
*(struct atm_vcc **) &msg->listen_vcc = listen_vcc;
|
||||
msg->reply = reply;
|
||||
if (qos) msg->qos = *qos;
|
||||
if (vcc) msg->sap = vcc->sap;
|
||||
if (svc) msg->svc = *svc;
|
||||
if (vcc) msg->local = vcc->local;
|
||||
if (pvc) msg->pvc = *pvc;
|
||||
if (qos)
|
||||
msg->qos = *qos;
|
||||
if (vcc)
|
||||
msg->sap = vcc->sap;
|
||||
if (svc)
|
||||
msg->svc = *svc;
|
||||
if (vcc)
|
||||
msg->local = vcc->local;
|
||||
if (pvc)
|
||||
msg->pvc = *pvc;
|
||||
if (vcc) {
|
||||
if (type == as_connect && test_bit(ATM_VF_SESSION, &vcc->flags))
|
||||
msg->session = ++session;
|
||||
/* every new pmp connect gets the next session number */
|
||||
}
|
||||
sigd_put_skb(skb);
|
||||
if (vcc) set_bit(ATM_VF_REGIS,&vcc->flags);
|
||||
if (vcc)
|
||||
set_bit(ATM_VF_REGIS, &vcc->flags);
|
||||
}
|
||||
|
||||
|
||||
void sigd_enq(struct atm_vcc *vcc,enum atmsvc_msg_type type,
|
||||
struct atm_vcc *listen_vcc,const struct sockaddr_atmpvc *pvc,
|
||||
const struct sockaddr_atmsvc *svc)
|
||||
void sigd_enq(struct atm_vcc *vcc, enum atmsvc_msg_type type,
|
||||
struct atm_vcc *listen_vcc, const struct sockaddr_atmpvc *pvc,
|
||||
const struct sockaddr_atmsvc *svc)
|
||||
{
|
||||
sigd_enq2(vcc,type,listen_vcc,pvc,svc,vcc ? &vcc->qos : NULL,0);
|
||||
sigd_enq2(vcc, type, listen_vcc, pvc, svc, vcc ? &vcc->qos : NULL, 0);
|
||||
/* other ISP applications may use "reply" */
|
||||
}
|
||||
|
||||
|
||||
static void purge_vcc(struct atm_vcc *vcc)
|
||||
{
|
||||
if (sk_atm(vcc)->sk_family == PF_ATMSVC &&
|
||||
@@ -212,21 +214,20 @@ static void purge_vcc(struct atm_vcc *vcc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void sigd_close(struct atm_vcc *vcc)
|
||||
{
|
||||
struct hlist_node *node;
|
||||
struct sock *s;
|
||||
int i;
|
||||
|
||||
pr_debug("sigd_close\n");
|
||||
pr_debug("\n");
|
||||
sigd = NULL;
|
||||
if (skb_peek(&sk_atm(vcc)->sk_receive_queue))
|
||||
printk(KERN_ERR "sigd_close: closing with requests pending\n");
|
||||
pr_err("closing with requests pending\n");
|
||||
skb_queue_purge(&sk_atm(vcc)->sk_receive_queue);
|
||||
|
||||
read_lock(&vcc_sklist_lock);
|
||||
for(i = 0; i < VCC_HTABLE_SIZE; ++i) {
|
||||
for (i = 0; i < VCC_HTABLE_SIZE; ++i) {
|
||||
struct hlist_head *head = &vcc_hash[i];
|
||||
|
||||
sk_for_each(s, node, head) {
|
||||
@@ -238,13 +239,11 @@ static void sigd_close(struct atm_vcc *vcc)
|
||||
read_unlock(&vcc_sklist_lock);
|
||||
}
|
||||
|
||||
|
||||
static struct atmdev_ops sigd_dev_ops = {
|
||||
.close = sigd_close,
|
||||
.send = sigd_send
|
||||
};
|
||||
|
||||
|
||||
static struct atm_dev sigd_dev = {
|
||||
.ops = &sigd_dev_ops,
|
||||
.type = "sig",
|
||||
@@ -252,16 +251,16 @@ static struct atm_dev sigd_dev = {
|
||||
.lock = __SPIN_LOCK_UNLOCKED(sigd_dev.lock)
|
||||
};
|
||||
|
||||
|
||||
int sigd_attach(struct atm_vcc *vcc)
|
||||
{
|
||||
if (sigd) return -EADDRINUSE;
|
||||
pr_debug("sigd_attach\n");
|
||||
if (sigd)
|
||||
return -EADDRINUSE;
|
||||
pr_debug("\n");
|
||||
sigd = vcc;
|
||||
vcc->dev = &sigd_dev;
|
||||
vcc_insert_socket(sk_atm(vcc));
|
||||
set_bit(ATM_VF_META,&vcc->flags);
|
||||
set_bit(ATM_VF_READY,&vcc->flags);
|
||||
set_bit(ATM_VF_META, &vcc->flags);
|
||||
set_bit(ATM_VF_READY, &vcc->flags);
|
||||
#ifdef WAIT_FOR_DEMON
|
||||
wake_up(&sigd_sleep);
|
||||
#endif
|
||||
|
||||
+130
-128
@@ -2,6 +2,7 @@
|
||||
|
||||
/* Written 1995-2000 by Werner Almesberger, EPFL LRC/ICA */
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
|
||||
|
||||
#include <linux/string.h>
|
||||
#include <linux/net.h> /* struct socket, struct proto_ops */
|
||||
@@ -18,14 +19,15 @@
|
||||
#include <linux/atmdev.h>
|
||||
#include <linux/bitops.h>
|
||||
#include <net/sock.h> /* for sock_no_* */
|
||||
#include <asm/uaccess.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include "resources.h"
|
||||
#include "common.h" /* common for PVCs and SVCs */
|
||||
#include "signaling.h"
|
||||
#include "addr.h"
|
||||
|
||||
static int svc_create(struct net *net, struct socket *sock, int protocol, int kern);
|
||||
static int svc_create(struct net *net, struct socket *sock, int protocol,
|
||||
int kern);
|
||||
|
||||
/*
|
||||
* Note: since all this is still nicely synchronized with the signaling demon,
|
||||
@@ -34,25 +36,25 @@ static int svc_create(struct net *net, struct socket *sock, int protocol, int ke
|
||||
*/
|
||||
|
||||
|
||||
static int svc_shutdown(struct socket *sock,int how)
|
||||
static int svc_shutdown(struct socket *sock, int how)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void svc_disconnect(struct atm_vcc *vcc)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct sk_buff *skb;
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
|
||||
pr_debug("svc_disconnect %p\n",vcc);
|
||||
if (test_bit(ATM_VF_REGIS,&vcc->flags)) {
|
||||
pr_debug("%p\n", vcc);
|
||||
if (test_bit(ATM_VF_REGIS, &vcc->flags)) {
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq(vcc,as_close,NULL,NULL,NULL);
|
||||
while (!test_bit(ATM_VF_RELEASED,&vcc->flags) && sigd) {
|
||||
sigd_enq(vcc, as_close, NULL, NULL, NULL);
|
||||
while (!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
prepare_to_wait(sk->sk_sleep, &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
finish_wait(sk->sk_sleep, &wait);
|
||||
}
|
||||
@@ -61,35 +63,35 @@ static void svc_disconnect(struct atm_vcc *vcc)
|
||||
while ((skb = skb_dequeue(&sk->sk_receive_queue)) != NULL) {
|
||||
atm_return(vcc, skb->truesize);
|
||||
pr_debug("LISTEN REL\n");
|
||||
sigd_enq2(NULL,as_reject,vcc,NULL,NULL,&vcc->qos,0);
|
||||
sigd_enq2(NULL, as_reject, vcc, NULL, NULL, &vcc->qos, 0);
|
||||
dev_kfree_skb(skb);
|
||||
}
|
||||
clear_bit(ATM_VF_REGIS, &vcc->flags);
|
||||
/* ... may retry later */
|
||||
}
|
||||
|
||||
|
||||
static int svc_release(struct socket *sock)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct atm_vcc *vcc;
|
||||
|
||||
if (sk) {
|
||||
if (sk) {
|
||||
vcc = ATM_SD(sock);
|
||||
pr_debug("svc_release %p\n", vcc);
|
||||
pr_debug("%p\n", vcc);
|
||||
clear_bit(ATM_VF_READY, &vcc->flags);
|
||||
/* VCC pointer is used as a reference, so we must not free it
|
||||
(thereby subjecting it to re-use) before all pending connections
|
||||
are closed */
|
||||
/*
|
||||
* VCC pointer is used as a reference,
|
||||
* so we must not free it (thereby subjecting it to re-use)
|
||||
* before all pending connections are closed
|
||||
*/
|
||||
svc_disconnect(vcc);
|
||||
vcc_release(sock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int sockaddr_len)
|
||||
static int svc_bind(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int sockaddr_len)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -114,38 +116,37 @@ static int svc_bind(struct socket *sock,struct sockaddr *sockaddr,
|
||||
error = -EAFNOSUPPORT;
|
||||
goto out;
|
||||
}
|
||||
clear_bit(ATM_VF_BOUND,&vcc->flags);
|
||||
clear_bit(ATM_VF_BOUND, &vcc->flags);
|
||||
/* failing rebind will kill old binding */
|
||||
/* @@@ check memory (de)allocation on rebind */
|
||||
if (!test_bit(ATM_VF_HASQOS,&vcc->flags)) {
|
||||
if (!test_bit(ATM_VF_HASQOS, &vcc->flags)) {
|
||||
error = -EBADFD;
|
||||
goto out;
|
||||
}
|
||||
vcc->local = *addr;
|
||||
set_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq(vcc,as_bind,NULL,NULL,&vcc->local);
|
||||
sigd_enq(vcc, as_bind, NULL, NULL, &vcc->local);
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
finish_wait(sk->sk_sleep, &wait);
|
||||
clear_bit(ATM_VF_REGIS,&vcc->flags); /* doesn't count */
|
||||
clear_bit(ATM_VF_REGIS, &vcc->flags); /* doesn't count */
|
||||
if (!sigd) {
|
||||
error = -EUNATCH;
|
||||
goto out;
|
||||
}
|
||||
if (!sk->sk_err)
|
||||
set_bit(ATM_VF_BOUND,&vcc->flags);
|
||||
set_bit(ATM_VF_BOUND, &vcc->flags);
|
||||
error = -sk->sk_err;
|
||||
out:
|
||||
release_sock(sk);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int sockaddr_len,int flags)
|
||||
static int svc_connect(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int sockaddr_len, int flags)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct sock *sk = sock->sk;
|
||||
@@ -153,7 +154,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
struct atm_vcc *vcc = ATM_SD(sock);
|
||||
int error;
|
||||
|
||||
pr_debug("svc_connect %p\n",vcc);
|
||||
pr_debug("%p\n", vcc);
|
||||
lock_sock(sk);
|
||||
if (sockaddr_len != sizeof(struct sockaddr_atmsvc)) {
|
||||
error = -EINVAL;
|
||||
@@ -201,7 +202,7 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
vcc->remote = *addr;
|
||||
set_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
sigd_enq(vcc,as_connect,NULL,NULL,&vcc->remote);
|
||||
sigd_enq(vcc, as_connect, NULL, NULL, &vcc->remote);
|
||||
if (flags & O_NONBLOCK) {
|
||||
finish_wait(sk->sk_sleep, &wait);
|
||||
sock->state = SS_CONNECTING;
|
||||
@@ -212,7 +213,8 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
if (!signal_pending(current)) {
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
prepare_to_wait(sk->sk_sleep, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
continue;
|
||||
}
|
||||
pr_debug("*ABORT*\n");
|
||||
@@ -228,20 +230,22 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
* Kernel <--okay---- Demon
|
||||
* Kernel <--close--- Demon
|
||||
*/
|
||||
sigd_enq(vcc,as_close,NULL,NULL,NULL);
|
||||
sigd_enq(vcc, as_close, NULL, NULL, NULL);
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
prepare_to_wait(sk->sk_sleep, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
}
|
||||
if (!sk->sk_err)
|
||||
while (!test_bit(ATM_VF_RELEASED,&vcc->flags)
|
||||
&& sigd) {
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
while (!test_bit(ATM_VF_RELEASED, &vcc->flags) &&
|
||||
sigd) {
|
||||
prepare_to_wait(sk->sk_sleep, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
schedule();
|
||||
}
|
||||
clear_bit(ATM_VF_REGIS,&vcc->flags);
|
||||
clear_bit(ATM_VF_RELEASED,&vcc->flags);
|
||||
clear_bit(ATM_VF_CLOSE,&vcc->flags);
|
||||
clear_bit(ATM_VF_REGIS, &vcc->flags);
|
||||
clear_bit(ATM_VF_RELEASED, &vcc->flags);
|
||||
clear_bit(ATM_VF_CLOSE, &vcc->flags);
|
||||
/* we're gone now but may connect later */
|
||||
error = -EINTR;
|
||||
break;
|
||||
@@ -269,37 +273,37 @@ static int svc_connect(struct socket *sock,struct sockaddr *sockaddr,
|
||||
/*
|
||||
* #endif
|
||||
*/
|
||||
if (!(error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci)))
|
||||
error = vcc_connect(sock, vcc->itf, vcc->vpi, vcc->vci);
|
||||
if (!error)
|
||||
sock->state = SS_CONNECTED;
|
||||
else
|
||||
(void) svc_disconnect(vcc);
|
||||
(void)svc_disconnect(vcc);
|
||||
out:
|
||||
release_sock(sk);
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_listen(struct socket *sock,int backlog)
|
||||
static int svc_listen(struct socket *sock, int backlog)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
struct sock *sk = sock->sk;
|
||||
struct atm_vcc *vcc = ATM_SD(sock);
|
||||
int error;
|
||||
|
||||
pr_debug("svc_listen %p\n",vcc);
|
||||
pr_debug("%p\n", vcc);
|
||||
lock_sock(sk);
|
||||
/* let server handle listen on unbound sockets */
|
||||
if (test_bit(ATM_VF_SESSION,&vcc->flags)) {
|
||||
if (test_bit(ATM_VF_SESSION, &vcc->flags)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (test_bit(ATM_VF_LISTEN, &vcc->flags)) {
|
||||
error = -EADDRINUSE;
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
set_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq(vcc,as_listen,NULL,NULL,&vcc->local);
|
||||
sigd_enq(vcc, as_listen, NULL, NULL, &vcc->local);
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
@@ -309,7 +313,7 @@ static int svc_listen(struct socket *sock,int backlog)
|
||||
error = -EUNATCH;
|
||||
goto out;
|
||||
}
|
||||
set_bit(ATM_VF_LISTEN,&vcc->flags);
|
||||
set_bit(ATM_VF_LISTEN, &vcc->flags);
|
||||
vcc_insert_socket(sk);
|
||||
sk->sk_max_ack_backlog = backlog > 0 ? backlog : ATM_BACKLOG_DEFAULT;
|
||||
error = -sk->sk_err;
|
||||
@@ -318,8 +322,7 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
|
||||
static int svc_accept(struct socket *sock, struct socket *newsock, int flags)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
struct sk_buff *skb;
|
||||
@@ -336,15 +339,16 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
|
||||
|
||||
new_vcc = ATM_SD(newsock);
|
||||
|
||||
pr_debug("svc_accept %p -> %p\n",old_vcc,new_vcc);
|
||||
pr_debug("%p -> %p\n", old_vcc, new_vcc);
|
||||
while (1) {
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
while (!(skb = skb_dequeue(&sk->sk_receive_queue)) &&
|
||||
sigd) {
|
||||
if (test_bit(ATM_VF_RELEASED,&old_vcc->flags)) break;
|
||||
if (test_bit(ATM_VF_CLOSE,&old_vcc->flags)) {
|
||||
if (test_bit(ATM_VF_RELEASED, &old_vcc->flags))
|
||||
break;
|
||||
if (test_bit(ATM_VF_CLOSE, &old_vcc->flags)) {
|
||||
error = -sk->sk_err;
|
||||
break;
|
||||
}
|
||||
@@ -359,7 +363,8 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
|
||||
error = -ERESTARTSYS;
|
||||
break;
|
||||
}
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
prepare_to_wait(sk->sk_sleep, &wait,
|
||||
TASK_INTERRUPTIBLE);
|
||||
}
|
||||
finish_wait(sk->sk_sleep, &wait);
|
||||
if (error)
|
||||
@@ -368,31 +373,34 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags)
|
||||
error = -EUNATCH;
|
||||
goto out;
|
||||
}
|
||||
msg = (struct atmsvc_msg *) skb->data;
|
||||
msg = (struct atmsvc_msg *)skb->data;
|
||||
new_vcc->qos = msg->qos;
|
||||
set_bit(ATM_VF_HASQOS,&new_vcc->flags);
|
||||
set_bit(ATM_VF_HASQOS, &new_vcc->flags);
|
||||
new_vcc->remote = msg->svc;
|
||||
new_vcc->local = msg->local;
|
||||
new_vcc->sap = msg->sap;
|
||||
error = vcc_connect(newsock, msg->pvc.sap_addr.itf,
|
||||
msg->pvc.sap_addr.vpi, msg->pvc.sap_addr.vci);
|
||||
msg->pvc.sap_addr.vpi,
|
||||
msg->pvc.sap_addr.vci);
|
||||
dev_kfree_skb(skb);
|
||||
sk->sk_ack_backlog--;
|
||||
if (error) {
|
||||
sigd_enq2(NULL,as_reject,old_vcc,NULL,NULL,
|
||||
&old_vcc->qos,error);
|
||||
sigd_enq2(NULL, as_reject, old_vcc, NULL, NULL,
|
||||
&old_vcc->qos, error);
|
||||
error = error == -EAGAIN ? -EBUSY : error;
|
||||
goto out;
|
||||
}
|
||||
/* wait should be short, so we ignore the non-blocking flag */
|
||||
set_bit(ATM_VF_WAITING, &new_vcc->flags);
|
||||
prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq(new_vcc,as_accept,old_vcc,NULL,NULL);
|
||||
prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq(new_vcc, as_accept, old_vcc, NULL, NULL);
|
||||
while (test_bit(ATM_VF_WAITING, &new_vcc->flags) && sigd) {
|
||||
release_sock(sk);
|
||||
schedule();
|
||||
lock_sock(sk);
|
||||
prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
prepare_to_wait(sk_atm(new_vcc)->sk_sleep, &wait,
|
||||
TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
finish_wait(sk_atm(new_vcc)->sk_sleep, &wait);
|
||||
if (!sigd) {
|
||||
@@ -412,39 +420,37 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_getname(struct socket *sock,struct sockaddr *sockaddr,
|
||||
int *sockaddr_len,int peer)
|
||||
static int svc_getname(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int *sockaddr_len, int peer)
|
||||
{
|
||||
struct sockaddr_atmsvc *addr;
|
||||
|
||||
*sockaddr_len = sizeof(struct sockaddr_atmsvc);
|
||||
addr = (struct sockaddr_atmsvc *) sockaddr;
|
||||
memcpy(addr,peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
|
||||
sizeof(struct sockaddr_atmsvc));
|
||||
memcpy(addr, peer ? &ATM_SD(sock)->remote : &ATM_SD(sock)->local,
|
||||
sizeof(struct sockaddr_atmsvc));
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int svc_change_qos(struct atm_vcc *vcc,struct atm_qos *qos)
|
||||
int svc_change_qos(struct atm_vcc *vcc, struct atm_qos *qos)
|
||||
{
|
||||
struct sock *sk = sk_atm(vcc);
|
||||
DEFINE_WAIT(wait);
|
||||
|
||||
set_bit(ATM_VF_WAITING, &vcc->flags);
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
sigd_enq2(vcc,as_modify,NULL,NULL,&vcc->local,qos,0);
|
||||
sigd_enq2(vcc, as_modify, NULL, NULL, &vcc->local, qos, 0);
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) &&
|
||||
!test_bit(ATM_VF_RELEASED, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_UNINTERRUPTIBLE);
|
||||
}
|
||||
finish_wait(sk->sk_sleep, &wait);
|
||||
if (!sigd) return -EUNATCH;
|
||||
if (!sigd)
|
||||
return -EUNATCH;
|
||||
return -sk->sk_err;
|
||||
}
|
||||
|
||||
|
||||
static int svc_setsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, unsigned int optlen)
|
||||
{
|
||||
@@ -454,37 +460,35 @@ static int svc_setsockopt(struct socket *sock, int level, int optname,
|
||||
|
||||
lock_sock(sk);
|
||||
switch (optname) {
|
||||
case SO_ATMSAP:
|
||||
if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(&vcc->sap, optval, optlen)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
set_bit(ATM_VF_HASSAP, &vcc->flags);
|
||||
break;
|
||||
case SO_MULTIPOINT:
|
||||
if (level != SOL_ATM || optlen != sizeof(int)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (get_user(value, (int __user *) optval)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (value == 1) {
|
||||
set_bit(ATM_VF_SESSION, &vcc->flags);
|
||||
} else if (value == 0) {
|
||||
clear_bit(ATM_VF_SESSION, &vcc->flags);
|
||||
} else {
|
||||
error = -EINVAL;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
error = vcc_setsockopt(sock, level, optname,
|
||||
optval, optlen);
|
||||
case SO_ATMSAP:
|
||||
if (level != SOL_ATM || optlen != sizeof(struct atm_sap)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (copy_from_user(&vcc->sap, optval, optlen)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
set_bit(ATM_VF_HASSAP, &vcc->flags);
|
||||
break;
|
||||
case SO_MULTIPOINT:
|
||||
if (level != SOL_ATM || optlen != sizeof(int)) {
|
||||
error = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
if (get_user(value, (int __user *)optval)) {
|
||||
error = -EFAULT;
|
||||
goto out;
|
||||
}
|
||||
if (value == 1)
|
||||
set_bit(ATM_VF_SESSION, &vcc->flags);
|
||||
else if (value == 0)
|
||||
clear_bit(ATM_VF_SESSION, &vcc->flags);
|
||||
else
|
||||
error = -EINVAL;
|
||||
break;
|
||||
default:
|
||||
error = vcc_setsockopt(sock, level, optname, optval, optlen);
|
||||
}
|
||||
|
||||
out:
|
||||
@@ -492,9 +496,8 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_getsockopt(struct socket *sock,int level,int optname,
|
||||
char __user *optval,int __user *optlen)
|
||||
static int svc_getsockopt(struct socket *sock, int level, int optname,
|
||||
char __user *optval, int __user *optlen)
|
||||
{
|
||||
struct sock *sk = sock->sk;
|
||||
int error = 0, len;
|
||||
@@ -521,7 +524,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
|
||||
int sockaddr_len, int flags)
|
||||
{
|
||||
@@ -540,7 +542,7 @@ static int svc_addparty(struct socket *sock, struct sockaddr *sockaddr,
|
||||
error = -EINPROGRESS;
|
||||
goto out;
|
||||
}
|
||||
pr_debug("svc_addparty added wait queue\n");
|
||||
pr_debug("added wait queue\n");
|
||||
while (test_bit(ATM_VF_WAITING, &vcc->flags) && sigd) {
|
||||
schedule();
|
||||
prepare_to_wait(sk->sk_sleep, &wait, TASK_INTERRUPTIBLE);
|
||||
@@ -552,7 +554,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_dropparty(struct socket *sock, int ep_ref)
|
||||
{
|
||||
DEFINE_WAIT(wait);
|
||||
@@ -579,7 +580,6 @@ out:
|
||||
return error;
|
||||
}
|
||||
|
||||
|
||||
static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
{
|
||||
int error, ep_ref;
|
||||
@@ -587,29 +587,31 @@ static int svc_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
struct atm_vcc *vcc = ATM_SD(sock);
|
||||
|
||||
switch (cmd) {
|
||||
case ATM_ADDPARTY:
|
||||
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
|
||||
return -EFAULT;
|
||||
error = svc_addparty(sock, (struct sockaddr *) &sa, sizeof(sa), 0);
|
||||
break;
|
||||
case ATM_DROPPARTY:
|
||||
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
error = svc_dropparty(sock, ep_ref);
|
||||
break;
|
||||
default:
|
||||
error = vcc_ioctl(sock, cmd, arg);
|
||||
case ATM_ADDPARTY:
|
||||
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&sa, (void __user *) arg, sizeof(sa)))
|
||||
return -EFAULT;
|
||||
error = svc_addparty(sock, (struct sockaddr *)&sa, sizeof(sa),
|
||||
0);
|
||||
break;
|
||||
case ATM_DROPPARTY:
|
||||
if (!test_bit(ATM_VF_SESSION, &vcc->flags))
|
||||
return -EINVAL;
|
||||
if (copy_from_user(&ep_ref, (void __user *) arg, sizeof(int)))
|
||||
return -EFAULT;
|
||||
error = svc_dropparty(sock, ep_ref);
|
||||
break;
|
||||
default:
|
||||
error = vcc_ioctl(sock, cmd, arg);
|
||||
}
|
||||
|
||||
return error;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
static int svc_compat_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
static int svc_compat_ioctl(struct socket *sock, unsigned int cmd,
|
||||
unsigned long arg)
|
||||
{
|
||||
/* The definition of ATM_ADDPARTY uses the size of struct atm_iobuf.
|
||||
But actually it takes a struct sockaddr_atmsvc, which doesn't need
|
||||
@@ -660,13 +662,13 @@ static int svc_create(struct net *net, struct socket *sock, int protocol,
|
||||
|
||||
sock->ops = &svc_proto_ops;
|
||||
error = vcc_create(net, sock, protocol, AF_ATMSVC);
|
||||
if (error) return error;
|
||||
if (error)
|
||||
return error;
|
||||
ATM_SD(sock)->local.sas_family = AF_ATMSVC;
|
||||
ATM_SD(sock)->remote.sas_family = AF_ATMSVC;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const struct net_proto_family svc_family_ops = {
|
||||
.family = PF_ATMSVC,
|
||||
.create = svc_create,
|
||||
|
||||
+3
-15
@@ -1863,25 +1863,13 @@ static int ax25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
||||
static void *ax25_info_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(ax25_list_lock)
|
||||
{
|
||||
struct ax25_cb *ax25;
|
||||
struct hlist_node *node;
|
||||
int i = 0;
|
||||
|
||||
spin_lock_bh(&ax25_list_lock);
|
||||
ax25_for_each(ax25, node, &ax25_list) {
|
||||
if (i == *pos)
|
||||
return ax25;
|
||||
++i;
|
||||
}
|
||||
return NULL;
|
||||
return seq_hlist_start(&ax25_list, *pos);
|
||||
}
|
||||
|
||||
static void *ax25_info_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
|
||||
return hlist_entry( ((struct ax25_cb *)v)->ax25_node.next,
|
||||
struct ax25_cb, ax25_node);
|
||||
return seq_hlist_next(v, &ax25_list, pos);
|
||||
}
|
||||
|
||||
static void ax25_info_stop(struct seq_file *seq, void *v)
|
||||
@@ -1892,7 +1880,7 @@ static void ax25_info_stop(struct seq_file *seq, void *v)
|
||||
|
||||
static int ax25_info_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
ax25_cb *ax25 = v;
|
||||
ax25_cb *ax25 = hlist_entry(v, struct ax25_cb, ax25_node);
|
||||
char buf[11];
|
||||
int k;
|
||||
|
||||
|
||||
+4
-21
@@ -146,31 +146,13 @@ int ax25_uid_ioctl(int cmd, struct sockaddr_ax25 *sax)
|
||||
static void *ax25_uid_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
__acquires(ax25_uid_lock)
|
||||
{
|
||||
struct ax25_uid_assoc *pt;
|
||||
struct hlist_node *node;
|
||||
int i = 1;
|
||||
|
||||
read_lock(&ax25_uid_lock);
|
||||
|
||||
if (*pos == 0)
|
||||
return SEQ_START_TOKEN;
|
||||
|
||||
ax25_uid_for_each(pt, node, &ax25_uid_list) {
|
||||
if (i == *pos)
|
||||
return pt;
|
||||
++i;
|
||||
}
|
||||
return NULL;
|
||||
return seq_hlist_start_head(&ax25_uid_list, *pos);
|
||||
}
|
||||
|
||||
static void *ax25_uid_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
++*pos;
|
||||
if (v == SEQ_START_TOKEN)
|
||||
return ax25_uid_list.first;
|
||||
else
|
||||
return hlist_entry(((ax25_uid_assoc *)v)->uid_node.next,
|
||||
ax25_uid_assoc, uid_node);
|
||||
return seq_hlist_next(v, &ax25_uid_list, pos);
|
||||
}
|
||||
|
||||
static void ax25_uid_seq_stop(struct seq_file *seq, void *v)
|
||||
@@ -186,8 +168,9 @@ static int ax25_uid_seq_show(struct seq_file *seq, void *v)
|
||||
if (v == SEQ_START_TOKEN)
|
||||
seq_printf(seq, "Policy: %d\n", ax25_uid_policy);
|
||||
else {
|
||||
struct ax25_uid_assoc *pt = v;
|
||||
struct ax25_uid_assoc *pt;
|
||||
|
||||
pt = hlist_entry(v, struct ax25_uid_assoc, uid_node);
|
||||
seq_printf(seq, "%6d %s\n", pt->uid, ax2asc(buf, &pt->call));
|
||||
}
|
||||
return 0;
|
||||
|
||||
@@ -64,7 +64,7 @@ static void bnep_net_set_mc_list(struct net_device *dev)
|
||||
struct sk_buff *skb;
|
||||
int size;
|
||||
|
||||
BT_DBG("%s mc_count %d", dev->name, dev->mc_count);
|
||||
BT_DBG("%s mc_count %d", dev->name, netdev_mc_count(dev));
|
||||
|
||||
size = sizeof(*r) + (BNEP_MAX_MULTICAST_FILTERS + 1) * ETH_ALEN * 2;
|
||||
skb = alloc_skb(size, GFP_ATOMIC);
|
||||
@@ -97,7 +97,9 @@ static void bnep_net_set_mc_list(struct net_device *dev)
|
||||
|
||||
/* FIXME: We should group addresses here. */
|
||||
|
||||
for (i = 0; i < dev->mc_count && i < BNEP_MAX_MULTICAST_FILTERS; i++) {
|
||||
for (i = 0;
|
||||
i < netdev_mc_count(dev) && i < BNEP_MAX_MULTICAST_FILTERS;
|
||||
i++) {
|
||||
memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
|
||||
memcpy(__skb_put(skb, ETH_ALEN), dmi->dmi_addr, ETH_ALEN);
|
||||
dmi = dmi->next;
|
||||
|
||||
+22
-17
@@ -21,7 +21,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/kernel.h>
|
||||
@@ -516,33 +517,37 @@ static char *cmtp_procinfo(struct capi_ctr *ctrl)
|
||||
return "CAPI Message Transport Protocol";
|
||||
}
|
||||
|
||||
static int cmtp_ctr_read_proc(char *page, char **start, off_t off, int count, int *eof, struct capi_ctr *ctrl)
|
||||
static int cmtp_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct capi_ctr *ctrl = m->private;
|
||||
struct cmtp_session *session = ctrl->driverdata;
|
||||
struct cmtp_application *app;
|
||||
struct list_head *p, *n;
|
||||
int len = 0;
|
||||
|
||||
len += sprintf(page + len, "%s\n\n", cmtp_procinfo(ctrl));
|
||||
len += sprintf(page + len, "addr %s\n", session->name);
|
||||
len += sprintf(page + len, "ctrl %d\n", session->num);
|
||||
seq_printf(m, "%s\n\n", cmtp_procinfo(ctrl));
|
||||
seq_printf(m, "addr %s\n", session->name);
|
||||
seq_printf(m, "ctrl %d\n", session->num);
|
||||
|
||||
list_for_each_safe(p, n, &session->applications) {
|
||||
app = list_entry(p, struct cmtp_application, list);
|
||||
len += sprintf(page + len, "appl %d -> %d\n", app->appl, app->mapping);
|
||||
seq_printf(m, "appl %d -> %d\n", app->appl, app->mapping);
|
||||
}
|
||||
|
||||
if (off + count >= len)
|
||||
*eof = 1;
|
||||
|
||||
if (len < off)
|
||||
return 0;
|
||||
|
||||
*start = page + off;
|
||||
|
||||
return ((count < len - off) ? count : len - off);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cmtp_proc_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return single_open(file, cmtp_proc_show, PDE(inode)->data);
|
||||
}
|
||||
|
||||
static const struct file_operations cmtp_proc_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = cmtp_proc_open,
|
||||
.read = seq_read,
|
||||
.llseek = seq_lseek,
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
int cmtp_attach_device(struct cmtp_session *session)
|
||||
{
|
||||
@@ -582,7 +587,7 @@ int cmtp_attach_device(struct cmtp_session *session)
|
||||
session->ctrl.send_message = cmtp_send_message;
|
||||
|
||||
session->ctrl.procinfo = cmtp_procinfo;
|
||||
session->ctrl.ctr_read_proc = cmtp_ctr_read_proc;
|
||||
session->ctrl.proc_fops = &cmtp_proc_fops;
|
||||
|
||||
if (attach_capi_ctr(&session->ctrl) < 0) {
|
||||
BT_ERR("Can't attach new controller");
|
||||
|
||||
@@ -377,6 +377,9 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
|
||||
|
||||
if (acl->state == BT_CONNECTED &&
|
||||
(sco->state == BT_OPEN || sco->state == BT_CLOSED)) {
|
||||
acl->power_save = 1;
|
||||
hci_conn_enter_active_mode(acl);
|
||||
|
||||
if (lmp_esco_capable(hdev))
|
||||
hci_setup_sync(sco, acl->handle);
|
||||
else
|
||||
|
||||
@@ -491,6 +491,10 @@ int hci_dev_open(__u16 dev)
|
||||
if (test_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks))
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
/* Treat all non BR/EDR controllers as raw devices for now */
|
||||
if (hdev->dev_type != HCI_BREDR)
|
||||
set_bit(HCI_RAW, &hdev->flags);
|
||||
|
||||
if (hdev->open(hdev)) {
|
||||
ret = -EIO;
|
||||
goto done;
|
||||
@@ -797,7 +801,7 @@ int hci_get_dev_info(void __user *arg)
|
||||
|
||||
strcpy(di.name, hdev->name);
|
||||
di.bdaddr = hdev->bdaddr;
|
||||
di.type = hdev->type;
|
||||
di.type = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
|
||||
di.flags = hdev->flags;
|
||||
di.pkt_type = hdev->pkt_type;
|
||||
di.acl_mtu = hdev->acl_mtu;
|
||||
@@ -869,8 +873,8 @@ int hci_register_dev(struct hci_dev *hdev)
|
||||
struct list_head *head = &hci_dev_list, *p;
|
||||
int i, id = 0;
|
||||
|
||||
BT_DBG("%p name %s type %d owner %p", hdev, hdev->name,
|
||||
hdev->type, hdev->owner);
|
||||
BT_DBG("%p name %s bus %d owner %p", hdev, hdev->name,
|
||||
hdev->bus, hdev->owner);
|
||||
|
||||
if (!hdev->open || !hdev->close || !hdev->destruct)
|
||||
return -EINVAL;
|
||||
@@ -946,7 +950,7 @@ int hci_unregister_dev(struct hci_dev *hdev)
|
||||
{
|
||||
int i;
|
||||
|
||||
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
|
||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||
|
||||
write_lock_bh(&hci_dev_list_lock);
|
||||
list_del(&hdev->list);
|
||||
|
||||
@@ -1698,7 +1698,9 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
|
||||
hci_conn_add_sysfs(conn);
|
||||
break;
|
||||
|
||||
case 0x11: /* Unsupported Feature or Parameter Value */
|
||||
case 0x1c: /* SCO interval rejected */
|
||||
case 0x1a: /* Unsupported Remote Feature */
|
||||
case 0x1f: /* Unspecified error */
|
||||
if (conn->out && conn->attempt < 2) {
|
||||
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
|
||||
|
||||
@@ -329,6 +329,9 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
|
||||
}
|
||||
|
||||
if (mask & HCI_CMSG_TSTAMP) {
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_timeval ctv;
|
||||
#endif
|
||||
struct timeval tv;
|
||||
void *data;
|
||||
int len;
|
||||
@@ -339,7 +342,6 @@ static inline void hci_sock_cmsg(struct sock *sk, struct msghdr *msg, struct sk_
|
||||
len = sizeof(tv);
|
||||
#ifdef CONFIG_COMPAT
|
||||
if (msg->msg_flags & MSG_CMSG_COMPAT) {
|
||||
struct compat_timeval ctv;
|
||||
ctv.tv_sec = tv.tv_sec;
|
||||
ctv.tv_usec = tv.tv_usec;
|
||||
data = &ctv;
|
||||
|
||||
+87
-35
@@ -2,6 +2,7 @@
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/debugfs.h>
|
||||
|
||||
#include <net/bluetooth/bluetooth.h>
|
||||
#include <net/bluetooth/hci_core.h>
|
||||
@@ -9,6 +10,9 @@
|
||||
struct class *bt_class = NULL;
|
||||
EXPORT_SYMBOL_GPL(bt_class);
|
||||
|
||||
struct dentry *bt_debugfs = NULL;
|
||||
EXPORT_SYMBOL_GPL(bt_debugfs);
|
||||
|
||||
static struct workqueue_struct *bt_workq;
|
||||
|
||||
static inline char *link_typetostr(int type)
|
||||
@@ -166,9 +170,9 @@ void hci_conn_del_sysfs(struct hci_conn *conn)
|
||||
queue_work(bt_workq, &conn->work_del);
|
||||
}
|
||||
|
||||
static inline char *host_typetostr(int type)
|
||||
static inline char *host_bustostr(int bus)
|
||||
{
|
||||
switch (type) {
|
||||
switch (bus) {
|
||||
case HCI_VIRTUAL:
|
||||
return "VIRTUAL";
|
||||
case HCI_USB:
|
||||
@@ -188,10 +192,28 @@ static inline char *host_typetostr(int type)
|
||||
}
|
||||
}
|
||||
|
||||
static inline char *host_typetostr(int type)
|
||||
{
|
||||
switch (type) {
|
||||
case HCI_BREDR:
|
||||
return "BR/EDR";
|
||||
case HCI_80211:
|
||||
return "802.11";
|
||||
default:
|
||||
return "UNKNOWN";
|
||||
}
|
||||
}
|
||||
|
||||
static ssize_t show_bus(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%s\n", host_bustostr(hdev->bus));
|
||||
}
|
||||
|
||||
static ssize_t show_type(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
return sprintf(buf, "%s\n", host_typetostr(hdev->type));
|
||||
return sprintf(buf, "%s\n", host_typetostr(hdev->dev_type));
|
||||
}
|
||||
|
||||
static ssize_t show_name(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
@@ -251,32 +273,6 @@ static ssize_t show_hci_revision(struct device *dev, struct device_attribute *at
|
||||
return sprintf(buf, "%d\n", hdev->hci_rev);
|
||||
}
|
||||
|
||||
static ssize_t show_inquiry_cache(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
struct inquiry_cache *cache = &hdev->inq_cache;
|
||||
struct inquiry_entry *e;
|
||||
int n = 0;
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
for (e = cache->list; e; e = e->next) {
|
||||
struct inquiry_data *data = &e->data;
|
||||
bdaddr_t bdaddr;
|
||||
baswap(&bdaddr, &data->bdaddr);
|
||||
n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
|
||||
batostr(&bdaddr),
|
||||
data->pscan_rep_mode, data->pscan_period_mode,
|
||||
data->pscan_mode, data->dev_class[2],
|
||||
data->dev_class[1], data->dev_class[0],
|
||||
__le16_to_cpu(data->clock_offset),
|
||||
data->rssi, data->ssp_mode, e->timestamp);
|
||||
}
|
||||
|
||||
hci_dev_unlock_bh(hdev);
|
||||
return n;
|
||||
}
|
||||
|
||||
static ssize_t show_idle_timeout(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct hci_dev *hdev = dev_get_drvdata(dev);
|
||||
@@ -355,6 +351,7 @@ static ssize_t store_sniff_min_interval(struct device *dev, struct device_attrib
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(bus, S_IRUGO, show_bus, NULL);
|
||||
static DEVICE_ATTR(type, S_IRUGO, show_type, NULL);
|
||||
static DEVICE_ATTR(name, S_IRUGO, show_name, NULL);
|
||||
static DEVICE_ATTR(class, S_IRUGO, show_class, NULL);
|
||||
@@ -363,7 +360,6 @@ static DEVICE_ATTR(features, S_IRUGO, show_features, NULL);
|
||||
static DEVICE_ATTR(manufacturer, S_IRUGO, show_manufacturer, NULL);
|
||||
static DEVICE_ATTR(hci_version, S_IRUGO, show_hci_version, NULL);
|
||||
static DEVICE_ATTR(hci_revision, S_IRUGO, show_hci_revision, NULL);
|
||||
static DEVICE_ATTR(inquiry_cache, S_IRUGO, show_inquiry_cache, NULL);
|
||||
|
||||
static DEVICE_ATTR(idle_timeout, S_IRUGO | S_IWUSR,
|
||||
show_idle_timeout, store_idle_timeout);
|
||||
@@ -373,6 +369,7 @@ static DEVICE_ATTR(sniff_min_interval, S_IRUGO | S_IWUSR,
|
||||
show_sniff_min_interval, store_sniff_min_interval);
|
||||
|
||||
static struct attribute *bt_host_attrs[] = {
|
||||
&dev_attr_bus.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_class.attr,
|
||||
@@ -381,7 +378,6 @@ static struct attribute *bt_host_attrs[] = {
|
||||
&dev_attr_manufacturer.attr,
|
||||
&dev_attr_hci_version.attr,
|
||||
&dev_attr_hci_revision.attr,
|
||||
&dev_attr_inquiry_cache.attr,
|
||||
&dev_attr_idle_timeout.attr,
|
||||
&dev_attr_sniff_max_interval.attr,
|
||||
&dev_attr_sniff_min_interval.attr,
|
||||
@@ -409,12 +405,52 @@ static struct device_type bt_host = {
|
||||
.release = bt_host_release,
|
||||
};
|
||||
|
||||
static int inquiry_cache_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
file->private_data = inode->i_private;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t inquiry_cache_read(struct file *file, char __user *userbuf,
|
||||
size_t count, loff_t *ppos)
|
||||
{
|
||||
struct hci_dev *hdev = file->private_data;
|
||||
struct inquiry_cache *cache = &hdev->inq_cache;
|
||||
struct inquiry_entry *e;
|
||||
char buf[4096];
|
||||
int n = 0;
|
||||
|
||||
hci_dev_lock_bh(hdev);
|
||||
|
||||
for (e = cache->list; e; e = e->next) {
|
||||
struct inquiry_data *data = &e->data;
|
||||
bdaddr_t bdaddr;
|
||||
baswap(&bdaddr, &data->bdaddr);
|
||||
n += sprintf(buf + n, "%s %d %d %d 0x%.2x%.2x%.2x 0x%.4x %d %d %u\n",
|
||||
batostr(&bdaddr),
|
||||
data->pscan_rep_mode, data->pscan_period_mode,
|
||||
data->pscan_mode, data->dev_class[2],
|
||||
data->dev_class[1], data->dev_class[0],
|
||||
__le16_to_cpu(data->clock_offset),
|
||||
data->rssi, data->ssp_mode, e->timestamp);
|
||||
}
|
||||
|
||||
hci_dev_unlock_bh(hdev);
|
||||
|
||||
return simple_read_from_buffer(userbuf, count, ppos, buf, n);
|
||||
}
|
||||
|
||||
static const struct file_operations inquiry_cache_fops = {
|
||||
.open = inquiry_cache_open,
|
||||
.read = inquiry_cache_read,
|
||||
};
|
||||
|
||||
int hci_register_sysfs(struct hci_dev *hdev)
|
||||
{
|
||||
struct device *dev = &hdev->dev;
|
||||
int err;
|
||||
|
||||
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
|
||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||
|
||||
dev->type = &bt_host;
|
||||
dev->class = bt_class;
|
||||
@@ -428,12 +464,24 @@ int hci_register_sysfs(struct hci_dev *hdev)
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
if (!bt_debugfs)
|
||||
return 0;
|
||||
|
||||
hdev->debugfs = debugfs_create_dir(hdev->name, bt_debugfs);
|
||||
if (!hdev->debugfs)
|
||||
return 0;
|
||||
|
||||
debugfs_create_file("inquiry_cache", 0444, hdev->debugfs,
|
||||
hdev, &inquiry_cache_fops);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hci_unregister_sysfs(struct hci_dev *hdev)
|
||||
{
|
||||
BT_DBG("%p name %s type %d", hdev, hdev->name, hdev->type);
|
||||
BT_DBG("%p name %s bus %d", hdev, hdev->name, hdev->bus);
|
||||
|
||||
debugfs_remove_recursive(hdev->debugfs);
|
||||
|
||||
device_del(&hdev->dev);
|
||||
}
|
||||
@@ -444,6 +492,8 @@ int __init bt_sysfs_init(void)
|
||||
if (!bt_workq)
|
||||
return -ENOMEM;
|
||||
|
||||
bt_debugfs = debugfs_create_dir("bluetooth", NULL);
|
||||
|
||||
bt_class = class_create(THIS_MODULE, "bluetooth");
|
||||
if (IS_ERR(bt_class)) {
|
||||
destroy_workqueue(bt_workq);
|
||||
@@ -455,7 +505,9 @@ int __init bt_sysfs_init(void)
|
||||
|
||||
void bt_sysfs_cleanup(void)
|
||||
{
|
||||
destroy_workqueue(bt_workq);
|
||||
|
||||
class_destroy(bt_class);
|
||||
|
||||
debugfs_remove_recursive(bt_debugfs);
|
||||
|
||||
destroy_workqueue(bt_workq);
|
||||
}
|
||||
|
||||
+38
-28
@@ -313,10 +313,21 @@ static int hidp_send_report(struct hidp_session *session, struct hid_report *rep
|
||||
return hidp_queue_report(session, buf, rsize);
|
||||
}
|
||||
|
||||
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count)
|
||||
static int hidp_output_raw_report(struct hid_device *hid, unsigned char *data, size_t count,
|
||||
unsigned char report_type)
|
||||
{
|
||||
if (hidp_send_ctrl_message(hid->driver_data,
|
||||
HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE,
|
||||
switch (report_type) {
|
||||
case HID_FEATURE_REPORT:
|
||||
report_type = HIDP_TRANS_SET_REPORT | HIDP_DATA_RTYPE_FEATURE;
|
||||
break;
|
||||
case HID_OUTPUT_REPORT:
|
||||
report_type = HIDP_TRANS_DATA | HIDP_DATA_RTYPE_OUPUT;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (hidp_send_ctrl_message(hid->driver_data, report_type,
|
||||
data, count))
|
||||
return -ENOMEM;
|
||||
return count;
|
||||
@@ -703,29 +714,9 @@ static void hidp_close(struct hid_device *hid)
|
||||
static int hidp_parse(struct hid_device *hid)
|
||||
{
|
||||
struct hidp_session *session = hid->driver_data;
|
||||
struct hidp_connadd_req *req = session->req;
|
||||
unsigned char *buf;
|
||||
int ret;
|
||||
|
||||
buf = kmalloc(req->rd_size, GFP_KERNEL);
|
||||
if (!buf)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(buf, req->rd_data, req->rd_size)) {
|
||||
kfree(buf);
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
ret = hid_parse_report(session->hid, buf, req->rd_size);
|
||||
|
||||
kfree(buf);
|
||||
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
session->req = NULL;
|
||||
|
||||
return 0;
|
||||
return hid_parse_report(session->hid, session->rd_data,
|
||||
session->rd_size);
|
||||
}
|
||||
|
||||
static int hidp_start(struct hid_device *hid)
|
||||
@@ -770,12 +761,24 @@ static int hidp_setup_hid(struct hidp_session *session,
|
||||
bdaddr_t src, dst;
|
||||
int err;
|
||||
|
||||
session->rd_data = kzalloc(req->rd_size, GFP_KERNEL);
|
||||
if (!session->rd_data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (copy_from_user(session->rd_data, req->rd_data, req->rd_size)) {
|
||||
err = -EFAULT;
|
||||
goto fault;
|
||||
}
|
||||
session->rd_size = req->rd_size;
|
||||
|
||||
hid = hid_allocate_device();
|
||||
if (IS_ERR(hid))
|
||||
return PTR_ERR(hid);
|
||||
if (IS_ERR(hid)) {
|
||||
err = PTR_ERR(hid);
|
||||
goto fault;
|
||||
}
|
||||
|
||||
session->hid = hid;
|
||||
session->req = req;
|
||||
|
||||
hid->driver_data = session;
|
||||
|
||||
baswap(&src, &bt_sk(session->ctrl_sock->sk)->src);
|
||||
@@ -806,6 +809,10 @@ failed:
|
||||
hid_destroy_device(hid);
|
||||
session->hid = NULL;
|
||||
|
||||
fault:
|
||||
kfree(session->rd_data);
|
||||
session->rd_data = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
@@ -900,6 +907,9 @@ unlink:
|
||||
session->hid = NULL;
|
||||
}
|
||||
|
||||
kfree(session->rd_data);
|
||||
session->rd_data = NULL;
|
||||
|
||||
purge:
|
||||
skb_queue_purge(&session->ctrl_transmit);
|
||||
skb_queue_purge(&session->intr_transmit);
|
||||
|
||||
@@ -154,7 +154,9 @@ struct hidp_session {
|
||||
struct sk_buff_head ctrl_transmit;
|
||||
struct sk_buff_head intr_transmit;
|
||||
|
||||
struct hidp_connadd_req *req;
|
||||
/* Report descriptor */
|
||||
__u8 *rd_data;
|
||||
uint rd_size;
|
||||
};
|
||||
|
||||
static inline void hidp_schedule(struct hidp_session *session)
|
||||
|
||||
@@ -252,7 +252,6 @@ static void rfcomm_session_timeout(unsigned long arg)
|
||||
BT_DBG("session %p state %ld", s, s->state);
|
||||
|
||||
set_bit(RFCOMM_TIMED_OUT, &s->flags);
|
||||
rfcomm_session_put(s);
|
||||
rfcomm_schedule(RFCOMM_SCHED_TIMEO);
|
||||
}
|
||||
|
||||
@@ -1151,7 +1150,11 @@ static int rfcomm_recv_ua(struct rfcomm_session *s, u8 dlci)
|
||||
break;
|
||||
|
||||
case BT_DISCONN:
|
||||
rfcomm_session_put(s);
|
||||
/* When socket is closed and we are not RFCOMM
|
||||
* initiator rfcomm_process_rx already calls
|
||||
* rfcomm_session_put() */
|
||||
if (s->sock->sk->sk_state != BT_CLOSED)
|
||||
rfcomm_session_put(s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1920,6 +1923,7 @@ static inline void rfcomm_process_sessions(void)
|
||||
if (test_and_clear_bit(RFCOMM_TIMED_OUT, &s->flags)) {
|
||||
s->state = BT_DISCONN;
|
||||
rfcomm_send_disc(s, 0);
|
||||
rfcomm_session_put(s);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@@ -31,3 +31,16 @@ config BRIDGE
|
||||
will be called bridge.
|
||||
|
||||
If unsure, say N.
|
||||
|
||||
config BRIDGE_IGMP_SNOOPING
|
||||
bool "IGMP snooping"
|
||||
depends on BRIDGE
|
||||
default y
|
||||
---help---
|
||||
If you say Y here, then the Ethernet bridge will be able selectively
|
||||
forward multicast traffic based on IGMP traffic received from each
|
||||
port.
|
||||
|
||||
Say N to exclude this support and reduce the binary size.
|
||||
|
||||
If unsure, say Y.
|
||||
|
||||
@@ -12,4 +12,6 @@ bridge-$(CONFIG_SYSFS) += br_sysfs_if.o br_sysfs_br.o
|
||||
|
||||
bridge-$(CONFIG_BRIDGE_NETFILTER) += br_netfilter.o
|
||||
|
||||
bridge-$(CONFIG_BRIDGE_IGMP_SNOOPING) += br_multicast.o
|
||||
|
||||
obj-$(CONFIG_BRIDGE_NF_EBTABLES) += netfilter/
|
||||
|
||||
+19
-4
@@ -25,6 +25,9 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
const unsigned char *dest = skb->data;
|
||||
struct net_bridge_fdb_entry *dst;
|
||||
struct net_bridge_mdb_entry *mdst;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->brdev = dev;
|
||||
|
||||
dev->stats.tx_packets++;
|
||||
dev->stats.tx_bytes += skb->len;
|
||||
@@ -32,13 +35,21 @@ netdev_tx_t br_dev_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
skb_reset_mac_header(skb);
|
||||
skb_pull(skb, ETH_HLEN);
|
||||
|
||||
if (dest[0] & 1)
|
||||
br_flood_deliver(br, skb);
|
||||
else if ((dst = __br_fdb_get(br, dest)) != NULL)
|
||||
if (dest[0] & 1) {
|
||||
if (br_multicast_rcv(br, NULL, skb))
|
||||
goto out;
|
||||
|
||||
mdst = br_mdb_get(br, skb);
|
||||
if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only)
|
||||
br_multicast_deliver(mdst, skb);
|
||||
else
|
||||
br_flood_deliver(br, skb);
|
||||
} else if ((dst = __br_fdb_get(br, dest)) != NULL)
|
||||
br_deliver(dst->dst, skb);
|
||||
else
|
||||
br_flood_deliver(br, skb);
|
||||
|
||||
out:
|
||||
return NETDEV_TX_OK;
|
||||
}
|
||||
|
||||
@@ -49,6 +60,7 @@ static int br_dev_open(struct net_device *dev)
|
||||
br_features_recompute(br);
|
||||
netif_start_queue(dev);
|
||||
br_stp_enable_bridge(br);
|
||||
br_multicast_open(br);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -59,7 +71,10 @@ static void br_dev_set_multicast_list(struct net_device *dev)
|
||||
|
||||
static int br_dev_stop(struct net_device *dev)
|
||||
{
|
||||
br_stp_disable_bridge(netdev_priv(dev));
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
|
||||
br_stp_disable_bridge(br);
|
||||
br_multicast_stop(br);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
|
||||
|
||||
+126
-24
@@ -11,6 +11,7 @@
|
||||
* 2 of the License, or (at your option) any later version.
|
||||
*/
|
||||
|
||||
#include <linux/err.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/skbuff.h>
|
||||
@@ -103,10 +104,49 @@ void br_forward(const struct net_bridge_port *to, struct sk_buff *skb)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
static int deliver_clone(struct net_bridge_port *prev, struct sk_buff *skb,
|
||||
void (*__packet_hook)(const struct net_bridge_port *p,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
skb = skb_clone(skb, GFP_ATOMIC);
|
||||
if (!skb) {
|
||||
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
|
||||
dev->stats.tx_dropped++;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
__packet_hook(prev, skb);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct net_bridge_port *maybe_deliver(
|
||||
struct net_bridge_port *prev, struct net_bridge_port *p,
|
||||
struct sk_buff *skb,
|
||||
void (*__packet_hook)(const struct net_bridge_port *p,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
int err;
|
||||
|
||||
if (!should_deliver(p, skb))
|
||||
return prev;
|
||||
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
err = deliver_clone(prev, skb, __packet_hook);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
out:
|
||||
return p;
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
static void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
struct sk_buff *skb0,
|
||||
void (*__packet_hook)(const struct net_bridge_port *p,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
struct net_bridge_port *p;
|
||||
struct net_bridge_port *prev;
|
||||
@@ -114,40 +154,102 @@ static void br_flood(struct net_bridge *br, struct sk_buff *skb,
|
||||
prev = NULL;
|
||||
|
||||
list_for_each_entry_rcu(p, &br->port_list, list) {
|
||||
if (should_deliver(p, skb)) {
|
||||
if (prev != NULL) {
|
||||
struct sk_buff *skb2;
|
||||
|
||||
if ((skb2 = skb_clone(skb, GFP_ATOMIC)) == NULL) {
|
||||
br->dev->stats.tx_dropped++;
|
||||
kfree_skb(skb);
|
||||
return;
|
||||
}
|
||||
|
||||
__packet_hook(prev, skb2);
|
||||
}
|
||||
|
||||
prev = p;
|
||||
}
|
||||
prev = maybe_deliver(prev, p, skb, __packet_hook);
|
||||
if (IS_ERR(prev))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (prev != NULL) {
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
if (skb0)
|
||||
deliver_clone(prev, skb, __packet_hook);
|
||||
else
|
||||
__packet_hook(prev, skb);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
kfree_skb(skb);
|
||||
out:
|
||||
if (!skb0)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
|
||||
/* called with rcu_read_lock */
|
||||
void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb)
|
||||
{
|
||||
br_flood(br, skb, __br_deliver);
|
||||
br_flood(br, skb, NULL, __br_deliver);
|
||||
}
|
||||
|
||||
/* called under bridge lock */
|
||||
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb)
|
||||
void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
|
||||
struct sk_buff *skb2)
|
||||
{
|
||||
br_flood(br, skb, __br_forward);
|
||||
br_flood(br, skb, skb2, __br_forward);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
/* called with rcu_read_lock */
|
||||
static void br_multicast_flood(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb, struct sk_buff *skb0,
|
||||
void (*__packet_hook)(
|
||||
const struct net_bridge_port *p,
|
||||
struct sk_buff *skb))
|
||||
{
|
||||
struct net_device *dev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
struct net_bridge *br = netdev_priv(dev);
|
||||
struct net_bridge_port *port;
|
||||
struct net_bridge_port *lport, *rport;
|
||||
struct net_bridge_port *prev;
|
||||
struct net_bridge_port_group *p;
|
||||
struct hlist_node *rp;
|
||||
|
||||
prev = NULL;
|
||||
|
||||
rp = br->router_list.first;
|
||||
p = mdst ? mdst->ports : NULL;
|
||||
while (p || rp) {
|
||||
lport = p ? p->port : NULL;
|
||||
rport = rp ? hlist_entry(rp, struct net_bridge_port, rlist) :
|
||||
NULL;
|
||||
|
||||
port = (unsigned long)lport > (unsigned long)rport ?
|
||||
lport : rport;
|
||||
|
||||
prev = maybe_deliver(prev, port, skb, __packet_hook);
|
||||
if (IS_ERR(prev))
|
||||
goto out;
|
||||
|
||||
if ((unsigned long)lport >= (unsigned long)port)
|
||||
p = p->next;
|
||||
if ((unsigned long)rport >= (unsigned long)port)
|
||||
rp = rp->next;
|
||||
}
|
||||
|
||||
if (!prev)
|
||||
goto out;
|
||||
|
||||
if (skb0)
|
||||
deliver_clone(prev, skb, __packet_hook);
|
||||
else
|
||||
__packet_hook(prev, skb);
|
||||
return;
|
||||
|
||||
out:
|
||||
if (!skb0)
|
||||
kfree_skb(skb);
|
||||
}
|
||||
|
||||
/* called with rcu_read_lock */
|
||||
void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
br_multicast_flood(mdst, skb, NULL, __br_deliver);
|
||||
}
|
||||
|
||||
/* called with rcu_read_lock */
|
||||
void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb, struct sk_buff *skb2)
|
||||
{
|
||||
br_multicast_flood(mdst, skb, skb2, __br_forward);
|
||||
}
|
||||
#endif
|
||||
|
||||
+5
-3
@@ -147,6 +147,8 @@ static void del_nbp(struct net_bridge_port *p)
|
||||
|
||||
rcu_assign_pointer(dev->br_port, NULL);
|
||||
|
||||
br_multicast_del_port(p);
|
||||
|
||||
kobject_uevent(&p->kobj, KOBJ_REMOVE);
|
||||
kobject_del(&p->kobj);
|
||||
|
||||
@@ -206,9 +208,8 @@ static struct net_device *new_bridge_dev(struct net *net, const char *name)
|
||||
|
||||
br_netfilter_rtable_init(br);
|
||||
|
||||
INIT_LIST_HEAD(&br->age_list);
|
||||
|
||||
br_stp_timer_init(br);
|
||||
br_multicast_init(br);
|
||||
|
||||
return dev;
|
||||
}
|
||||
@@ -260,6 +261,7 @@ static struct net_bridge_port *new_nbp(struct net_bridge *br,
|
||||
br_init_port(p);
|
||||
p->state = BR_STATE_DISABLED;
|
||||
br_stp_port_timer_init(p);
|
||||
br_multicast_add_port(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
@@ -467,7 +469,7 @@ int br_del_if(struct net_bridge *br, struct net_device *dev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
void br_net_exit(struct net *net)
|
||||
void __net_exit br_net_exit(struct net *net)
|
||||
{
|
||||
struct net_device *dev;
|
||||
LIST_HEAD(list);
|
||||
|
||||
+27
-12
@@ -20,9 +20,9 @@
|
||||
/* Bridge group multicast address 802.1d (pg 51). */
|
||||
const u8 br_group_address[ETH_ALEN] = { 0x01, 0x80, 0xc2, 0x00, 0x00, 0x00 };
|
||||
|
||||
static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
|
||||
static int br_pass_frame_up(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *indev, *brdev = br->dev;
|
||||
struct net_device *indev, *brdev = BR_INPUT_SKB_CB(skb)->brdev;
|
||||
|
||||
brdev->stats.rx_packets++;
|
||||
brdev->stats.rx_bytes += skb->len;
|
||||
@@ -30,8 +30,8 @@ static void br_pass_frame_up(struct net_bridge *br, struct sk_buff *skb)
|
||||
indev = skb->dev;
|
||||
skb->dev = brdev;
|
||||
|
||||
NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
|
||||
netif_receive_skb);
|
||||
return NF_HOOK(PF_BRIDGE, NF_BR_LOCAL_IN, skb, indev, NULL,
|
||||
netif_receive_skb);
|
||||
}
|
||||
|
||||
/* note: already called with rcu_read_lock (preempt_disabled) */
|
||||
@@ -41,6 +41,7 @@ int br_handle_frame_finish(struct sk_buff *skb)
|
||||
struct net_bridge_port *p = rcu_dereference(skb->dev->br_port);
|
||||
struct net_bridge *br;
|
||||
struct net_bridge_fdb_entry *dst;
|
||||
struct net_bridge_mdb_entry *mdst;
|
||||
struct sk_buff *skb2;
|
||||
|
||||
if (!p || p->state == BR_STATE_DISABLED)
|
||||
@@ -50,9 +51,15 @@ int br_handle_frame_finish(struct sk_buff *skb)
|
||||
br = p->br;
|
||||
br_fdb_update(br, p, eth_hdr(skb)->h_source);
|
||||
|
||||
if (is_multicast_ether_addr(dest) &&
|
||||
br_multicast_rcv(br, p, skb))
|
||||
goto drop;
|
||||
|
||||
if (p->state == BR_STATE_LEARNING)
|
||||
goto drop;
|
||||
|
||||
BR_INPUT_SKB_CB(skb)->brdev = br->dev;
|
||||
|
||||
/* The packet skb2 goes to the local host (NULL to skip). */
|
||||
skb2 = NULL;
|
||||
|
||||
@@ -62,27 +69,35 @@ int br_handle_frame_finish(struct sk_buff *skb)
|
||||
dst = NULL;
|
||||
|
||||
if (is_multicast_ether_addr(dest)) {
|
||||
mdst = br_mdb_get(br, skb);
|
||||
if (mdst || BR_INPUT_SKB_CB(skb)->mrouters_only) {
|
||||
if ((mdst && !hlist_unhashed(&mdst->mglist)) ||
|
||||
br_multicast_is_router(br))
|
||||
skb2 = skb;
|
||||
br_multicast_forward(mdst, skb, skb2);
|
||||
skb = NULL;
|
||||
if (!skb2)
|
||||
goto out;
|
||||
} else
|
||||
skb2 = skb;
|
||||
|
||||
br->dev->stats.multicast++;
|
||||
skb2 = skb;
|
||||
} else if ((dst = __br_fdb_get(br, dest)) && dst->is_local) {
|
||||
skb2 = skb;
|
||||
/* Do not forward the packet since it's local. */
|
||||
skb = NULL;
|
||||
}
|
||||
|
||||
if (skb2 == skb)
|
||||
skb2 = skb_clone(skb, GFP_ATOMIC);
|
||||
|
||||
if (skb2)
|
||||
br_pass_frame_up(br, skb2);
|
||||
|
||||
if (skb) {
|
||||
if (dst)
|
||||
br_forward(dst->dst, skb);
|
||||
else
|
||||
br_flood_forward(br, skb);
|
||||
br_flood_forward(br, skb, skb2);
|
||||
}
|
||||
|
||||
if (skb2)
|
||||
return br_pass_frame_up(skb2);
|
||||
|
||||
out:
|
||||
return 0;
|
||||
drop:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+171
-2
@@ -57,6 +57,41 @@ struct net_bridge_fdb_entry
|
||||
unsigned char is_static;
|
||||
};
|
||||
|
||||
struct net_bridge_port_group {
|
||||
struct net_bridge_port *port;
|
||||
struct net_bridge_port_group *next;
|
||||
struct hlist_node mglist;
|
||||
struct rcu_head rcu;
|
||||
struct timer_list timer;
|
||||
struct timer_list query_timer;
|
||||
__be32 addr;
|
||||
u32 queries_sent;
|
||||
};
|
||||
|
||||
struct net_bridge_mdb_entry
|
||||
{
|
||||
struct hlist_node hlist[2];
|
||||
struct hlist_node mglist;
|
||||
struct net_bridge *br;
|
||||
struct net_bridge_port_group *ports;
|
||||
struct rcu_head rcu;
|
||||
struct timer_list timer;
|
||||
struct timer_list query_timer;
|
||||
__be32 addr;
|
||||
u32 queries_sent;
|
||||
};
|
||||
|
||||
struct net_bridge_mdb_htable
|
||||
{
|
||||
struct hlist_head *mhash;
|
||||
struct rcu_head rcu;
|
||||
struct net_bridge_mdb_htable *old;
|
||||
u32 size;
|
||||
u32 max;
|
||||
u32 secret;
|
||||
u32 ver;
|
||||
};
|
||||
|
||||
struct net_bridge_port
|
||||
{
|
||||
struct net_bridge *br;
|
||||
@@ -84,6 +119,15 @@ struct net_bridge_port
|
||||
|
||||
unsigned long flags;
|
||||
#define BR_HAIRPIN_MODE 0x00000001
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
u32 multicast_startup_queries_sent;
|
||||
unsigned char multicast_router;
|
||||
struct timer_list multicast_router_timer;
|
||||
struct timer_list multicast_query_timer;
|
||||
struct hlist_head mglist;
|
||||
struct hlist_node rlist;
|
||||
#endif
|
||||
};
|
||||
|
||||
struct net_bridge
|
||||
@@ -93,7 +137,6 @@ struct net_bridge
|
||||
struct net_device *dev;
|
||||
spinlock_t hash_lock;
|
||||
struct hlist_head hash[BR_HASH_SIZE];
|
||||
struct list_head age_list;
|
||||
unsigned long feature_mask;
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
struct rtable fake_rtable;
|
||||
@@ -125,6 +168,35 @@ struct net_bridge
|
||||
unsigned char topology_change;
|
||||
unsigned char topology_change_detected;
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
unsigned char multicast_router;
|
||||
|
||||
u8 multicast_disabled:1;
|
||||
|
||||
u32 hash_elasticity;
|
||||
u32 hash_max;
|
||||
|
||||
u32 multicast_last_member_count;
|
||||
u32 multicast_startup_queries_sent;
|
||||
u32 multicast_startup_query_count;
|
||||
|
||||
unsigned long multicast_last_member_interval;
|
||||
unsigned long multicast_membership_interval;
|
||||
unsigned long multicast_querier_interval;
|
||||
unsigned long multicast_query_interval;
|
||||
unsigned long multicast_query_response_interval;
|
||||
unsigned long multicast_startup_query_interval;
|
||||
|
||||
spinlock_t multicast_lock;
|
||||
struct net_bridge_mdb_htable *mdb;
|
||||
struct hlist_head router_list;
|
||||
struct hlist_head mglist;
|
||||
|
||||
struct timer_list multicast_router_timer;
|
||||
struct timer_list multicast_querier_timer;
|
||||
struct timer_list multicast_query_timer;
|
||||
#endif
|
||||
|
||||
struct timer_list hello_timer;
|
||||
struct timer_list tcn_timer;
|
||||
struct timer_list topology_change_timer;
|
||||
@@ -132,6 +204,14 @@ struct net_bridge
|
||||
struct kobject *ifobj;
|
||||
};
|
||||
|
||||
struct br_input_skb_cb {
|
||||
struct net_device *brdev;
|
||||
int igmp;
|
||||
int mrouters_only;
|
||||
};
|
||||
|
||||
#define BR_INPUT_SKB_CB(__skb) ((struct br_input_skb_cb *)(__skb)->cb)
|
||||
|
||||
extern struct notifier_block br_device_notifier;
|
||||
extern const u8 br_group_address[ETH_ALEN];
|
||||
|
||||
@@ -175,7 +255,8 @@ extern void br_forward(const struct net_bridge_port *to,
|
||||
struct sk_buff *skb);
|
||||
extern int br_forward_finish(struct sk_buff *skb);
|
||||
extern void br_flood_deliver(struct net_bridge *br, struct sk_buff *skb);
|
||||
extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb);
|
||||
extern void br_flood_forward(struct net_bridge *br, struct sk_buff *skb,
|
||||
struct sk_buff *skb2);
|
||||
|
||||
/* br_if.c */
|
||||
extern void br_port_carrier_check(struct net_bridge_port *p);
|
||||
@@ -198,6 +279,94 @@ extern struct sk_buff *br_handle_frame(struct net_bridge_port *p,
|
||||
extern int br_dev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
|
||||
extern int br_ioctl_deviceless_stub(struct net *net, unsigned int cmd, void __user *arg);
|
||||
|
||||
/* br_multicast.c */
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
extern int br_multicast_rcv(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
struct sk_buff *skb);
|
||||
extern struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
|
||||
struct sk_buff *skb);
|
||||
extern void br_multicast_add_port(struct net_bridge_port *port);
|
||||
extern void br_multicast_del_port(struct net_bridge_port *port);
|
||||
extern void br_multicast_enable_port(struct net_bridge_port *port);
|
||||
extern void br_multicast_disable_port(struct net_bridge_port *port);
|
||||
extern void br_multicast_init(struct net_bridge *br);
|
||||
extern void br_multicast_open(struct net_bridge *br);
|
||||
extern void br_multicast_stop(struct net_bridge *br);
|
||||
extern void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb);
|
||||
extern void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb, struct sk_buff *skb2);
|
||||
extern int br_multicast_set_router(struct net_bridge *br, unsigned long val);
|
||||
extern int br_multicast_set_port_router(struct net_bridge_port *p,
|
||||
unsigned long val);
|
||||
extern int br_multicast_toggle(struct net_bridge *br, unsigned long val);
|
||||
extern int br_multicast_set_hash_max(struct net_bridge *br, unsigned long val);
|
||||
|
||||
static inline bool br_multicast_is_router(struct net_bridge *br)
|
||||
{
|
||||
return br->multicast_router == 2 ||
|
||||
(br->multicast_router == 1 &&
|
||||
timer_pending(&br->multicast_router_timer));
|
||||
}
|
||||
#else
|
||||
static inline int br_multicast_rcv(struct net_bridge *br,
|
||||
struct net_bridge_port *port,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline struct net_bridge_mdb_entry *br_mdb_get(struct net_bridge *br,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static inline void br_multicast_add_port(struct net_bridge_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_del_port(struct net_bridge_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_enable_port(struct net_bridge_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_disable_port(struct net_bridge_port *port)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_init(struct net_bridge *br)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_open(struct net_bridge *br)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_stop(struct net_bridge *br)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_deliver(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void br_multicast_forward(struct net_bridge_mdb_entry *mdst,
|
||||
struct sk_buff *skb,
|
||||
struct sk_buff *skb2)
|
||||
{
|
||||
}
|
||||
static inline bool br_multicast_is_router(struct net_bridge *br)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* br_netfilter.c */
|
||||
#ifdef CONFIG_BRIDGE_NETFILTER
|
||||
extern int br_netfilter_init(void);
|
||||
|
||||
@@ -386,6 +386,8 @@ static void br_make_forwarding(struct net_bridge_port *p)
|
||||
else
|
||||
p->state = BR_STATE_LEARNING;
|
||||
|
||||
br_multicast_enable_port(p);
|
||||
|
||||
br_log_state(p);
|
||||
|
||||
if (br->forward_delay != 0)
|
||||
|
||||
@@ -108,6 +108,7 @@ void br_stp_disable_port(struct net_bridge_port *p)
|
||||
del_timer(&p->hold_timer);
|
||||
|
||||
br_fdb_delete_by_port(br, p, 0);
|
||||
br_multicast_disable_port(p);
|
||||
|
||||
br_configuration_update(br);
|
||||
|
||||
|
||||
@@ -345,6 +345,273 @@ static ssize_t store_flush(struct device *d,
|
||||
}
|
||||
static DEVICE_ATTR(flush, S_IWUSR, NULL, store_flush);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%d\n", br->multicast_router);
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_router(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, br_multicast_set_router);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
|
||||
store_multicast_router);
|
||||
|
||||
static ssize_t show_multicast_snooping(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%d\n", !br->multicast_disabled);
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_snooping(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, br_multicast_toggle);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_snooping, S_IRUGO | S_IWUSR,
|
||||
show_multicast_snooping, store_multicast_snooping);
|
||||
|
||||
static ssize_t show_hash_elasticity(struct device *d,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%u\n", br->hash_elasticity);
|
||||
}
|
||||
|
||||
static int set_elasticity(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->hash_elasticity = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_hash_elasticity(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_elasticity);
|
||||
}
|
||||
static DEVICE_ATTR(hash_elasticity, S_IRUGO | S_IWUSR, show_hash_elasticity,
|
||||
store_hash_elasticity);
|
||||
|
||||
static ssize_t show_hash_max(struct device *d, struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%u\n", br->hash_max);
|
||||
}
|
||||
|
||||
static ssize_t store_hash_max(struct device *d, struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, br_multicast_set_hash_max);
|
||||
}
|
||||
static DEVICE_ATTR(hash_max, S_IRUGO | S_IWUSR, show_hash_max,
|
||||
store_hash_max);
|
||||
|
||||
static ssize_t show_multicast_last_member_count(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%u\n", br->multicast_last_member_count);
|
||||
}
|
||||
|
||||
static int set_last_member_count(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_last_member_count = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_last_member_count(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_last_member_count);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_last_member_count, S_IRUGO | S_IWUSR,
|
||||
show_multicast_last_member_count,
|
||||
store_multicast_last_member_count);
|
||||
|
||||
static ssize_t show_multicast_startup_query_count(
|
||||
struct device *d, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%u\n", br->multicast_startup_query_count);
|
||||
}
|
||||
|
||||
static int set_startup_query_count(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_startup_query_count = val;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_startup_query_count(
|
||||
struct device *d, struct device_attribute *attr, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_startup_query_count);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_startup_query_count, S_IRUGO | S_IWUSR,
|
||||
show_multicast_startup_query_count,
|
||||
store_multicast_startup_query_count);
|
||||
|
||||
static ssize_t show_multicast_last_member_interval(
|
||||
struct device *d, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_last_member_interval));
|
||||
}
|
||||
|
||||
static int set_last_member_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_last_member_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_last_member_interval(
|
||||
struct device *d, struct device_attribute *attr, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_last_member_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_last_member_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_last_member_interval,
|
||||
store_multicast_last_member_interval);
|
||||
|
||||
static ssize_t show_multicast_membership_interval(
|
||||
struct device *d, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_membership_interval));
|
||||
}
|
||||
|
||||
static int set_membership_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_membership_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_membership_interval(
|
||||
struct device *d, struct device_attribute *attr, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_membership_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_membership_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_membership_interval,
|
||||
store_multicast_membership_interval);
|
||||
|
||||
static ssize_t show_multicast_querier_interval(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_querier_interval));
|
||||
}
|
||||
|
||||
static int set_querier_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_querier_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_querier_interval(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_querier_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_querier_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_querier_interval,
|
||||
store_multicast_querier_interval);
|
||||
|
||||
static ssize_t show_multicast_query_interval(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_query_interval));
|
||||
}
|
||||
|
||||
static int set_query_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_query_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_query_interval(struct device *d,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_query_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_query_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_query_interval,
|
||||
store_multicast_query_interval);
|
||||
|
||||
static ssize_t show_multicast_query_response_interval(
|
||||
struct device *d, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(
|
||||
buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_query_response_interval));
|
||||
}
|
||||
|
||||
static int set_query_response_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_query_response_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_query_response_interval(
|
||||
struct device *d, struct device_attribute *attr, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_query_response_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_query_response_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_query_response_interval,
|
||||
store_multicast_query_response_interval);
|
||||
|
||||
static ssize_t show_multicast_startup_query_interval(
|
||||
struct device *d, struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct net_bridge *br = to_bridge(d);
|
||||
return sprintf(
|
||||
buf, "%lu\n",
|
||||
jiffies_to_clock_t(br->multicast_startup_query_interval));
|
||||
}
|
||||
|
||||
static int set_startup_query_interval(struct net_bridge *br, unsigned long val)
|
||||
{
|
||||
br->multicast_startup_query_interval = clock_t_to_jiffies(val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_startup_query_interval(
|
||||
struct device *d, struct device_attribute *attr, const char *buf,
|
||||
size_t len)
|
||||
{
|
||||
return store_bridge_parm(d, buf, len, set_startup_query_interval);
|
||||
}
|
||||
static DEVICE_ATTR(multicast_startup_query_interval, S_IRUGO | S_IWUSR,
|
||||
show_multicast_startup_query_interval,
|
||||
store_multicast_startup_query_interval);
|
||||
#endif
|
||||
|
||||
static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_forward_delay.attr,
|
||||
&dev_attr_hello_time.attr,
|
||||
@@ -364,6 +631,20 @@ static struct attribute *bridge_attrs[] = {
|
||||
&dev_attr_gc_timer.attr,
|
||||
&dev_attr_group_addr.attr,
|
||||
&dev_attr_flush.attr,
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
&dev_attr_multicast_router.attr,
|
||||
&dev_attr_multicast_snooping.attr,
|
||||
&dev_attr_hash_elasticity.attr,
|
||||
&dev_attr_hash_max.attr,
|
||||
&dev_attr_multicast_last_member_count.attr,
|
||||
&dev_attr_multicast_startup_query_count.attr,
|
||||
&dev_attr_multicast_last_member_interval.attr,
|
||||
&dev_attr_multicast_membership_interval.attr,
|
||||
&dev_attr_multicast_querier_interval.attr,
|
||||
&dev_attr_multicast_query_interval.attr,
|
||||
&dev_attr_multicast_query_response_interval.attr,
|
||||
&dev_attr_multicast_startup_query_interval.attr,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -159,6 +159,21 @@ static ssize_t store_hairpin_mode(struct net_bridge_port *p, unsigned long v)
|
||||
static BRPORT_ATTR(hairpin_mode, S_IRUGO | S_IWUSR,
|
||||
show_hairpin_mode, store_hairpin_mode);
|
||||
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
static ssize_t show_multicast_router(struct net_bridge_port *p, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", p->multicast_router);
|
||||
}
|
||||
|
||||
static ssize_t store_multicast_router(struct net_bridge_port *p,
|
||||
unsigned long v)
|
||||
{
|
||||
return br_multicast_set_port_router(p, v);
|
||||
}
|
||||
static BRPORT_ATTR(multicast_router, S_IRUGO | S_IWUSR, show_multicast_router,
|
||||
store_multicast_router);
|
||||
#endif
|
||||
|
||||
static struct brport_attribute *brport_attrs[] = {
|
||||
&brport_attr_path_cost,
|
||||
&brport_attr_priority,
|
||||
@@ -176,6 +191,9 @@ static struct brport_attribute *brport_attrs[] = {
|
||||
&brport_attr_hold_timer,
|
||||
&brport_attr_flush,
|
||||
&brport_attr_hairpin_mode,
|
||||
#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
|
||||
&brport_attr_multicast_router,
|
||||
#endif
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
@@ -52,7 +52,7 @@ static struct xt_match ebt_802_3_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_802_3_mt,
|
||||
.checkentry = ebt_802_3_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_802_3_info)),
|
||||
.matchsize = sizeof(struct ebt_802_3_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -120,7 +120,7 @@ static struct xt_match ebt_arp_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_arp_mt,
|
||||
.checkentry = ebt_arp_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_arp_info)),
|
||||
.matchsize = sizeof(struct ebt_arp_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -78,7 +78,7 @@ static struct xt_target ebt_arpreply_tg_reg __read_mostly = {
|
||||
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_PRE_ROUTING),
|
||||
.target = ebt_arpreply_tg,
|
||||
.checkentry = ebt_arpreply_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_arpreply_info)),
|
||||
.targetsize = sizeof(struct ebt_arpreply_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ static struct xt_target ebt_dnat_tg_reg __read_mostly = {
|
||||
(1 << NF_BR_LOCAL_OUT) | (1 << NF_BR_BROUTING),
|
||||
.target = ebt_dnat_tg,
|
||||
.checkentry = ebt_dnat_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
|
||||
.targetsize = sizeof(struct ebt_nat_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -110,7 +110,7 @@ static struct xt_match ebt_ip_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_ip_mt,
|
||||
.checkentry = ebt_ip_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_ip_info)),
|
||||
.matchsize = sizeof(struct ebt_ip_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -122,7 +122,7 @@ static struct xt_match ebt_ip6_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_ip6_mt,
|
||||
.checkentry = ebt_ip6_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_ip6_info)),
|
||||
.matchsize = sizeof(struct ebt_ip6_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -84,13 +84,29 @@ static bool ebt_limit_mt_check(const struct xt_mtchk_param *par)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
/*
|
||||
* no conversion function needed --
|
||||
* only avg/burst have meaningful values in userspace.
|
||||
*/
|
||||
struct ebt_compat_limit_info {
|
||||
compat_uint_t avg, burst;
|
||||
compat_ulong_t prev;
|
||||
compat_uint_t credit, credit_cap, cost;
|
||||
};
|
||||
#endif
|
||||
|
||||
static struct xt_match ebt_limit_mt_reg __read_mostly = {
|
||||
.name = "limit",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_limit_mt,
|
||||
.checkentry = ebt_limit_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_limit_info)),
|
||||
.matchsize = sizeof(struct ebt_limit_info),
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compatsize = sizeof(struct ebt_compat_limit_info),
|
||||
#endif
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -195,7 +195,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.target = ebt_log_tg,
|
||||
.checkentry = ebt_log_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_log_info)),
|
||||
.targetsize = sizeof(struct ebt_log_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -52,6 +52,32 @@ static bool ebt_mark_tg_check(const struct xt_tgchk_param *par)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_ebt_mark_t_info {
|
||||
compat_ulong_t mark;
|
||||
compat_uint_t target;
|
||||
};
|
||||
|
||||
static void mark_tg_compat_from_user(void *dst, const void *src)
|
||||
{
|
||||
const struct compat_ebt_mark_t_info *user = src;
|
||||
struct ebt_mark_t_info *kern = dst;
|
||||
|
||||
kern->mark = user->mark;
|
||||
kern->target = user->target;
|
||||
}
|
||||
|
||||
static int mark_tg_compat_to_user(void __user *dst, const void *src)
|
||||
{
|
||||
struct compat_ebt_mark_t_info __user *user = dst;
|
||||
const struct ebt_mark_t_info *kern = src;
|
||||
|
||||
if (put_user(kern->mark, &user->mark) ||
|
||||
put_user(kern->target, &user->target))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct xt_target ebt_mark_tg_reg __read_mostly = {
|
||||
.name = "mark",
|
||||
@@ -59,7 +85,12 @@ static struct xt_target ebt_mark_tg_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.target = ebt_mark_tg,
|
||||
.checkentry = ebt_mark_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_mark_t_info)),
|
||||
.targetsize = sizeof(struct ebt_mark_t_info),
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compatsize = sizeof(struct compat_ebt_mark_t_info),
|
||||
.compat_from_user = mark_tg_compat_from_user,
|
||||
.compat_to_user = mark_tg_compat_to_user,
|
||||
#endif
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -35,13 +35,50 @@ static bool ebt_mark_mt_check(const struct xt_mtchk_param *par)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
struct compat_ebt_mark_m_info {
|
||||
compat_ulong_t mark, mask;
|
||||
uint8_t invert, bitmask;
|
||||
};
|
||||
|
||||
static void mark_mt_compat_from_user(void *dst, const void *src)
|
||||
{
|
||||
const struct compat_ebt_mark_m_info *user = src;
|
||||
struct ebt_mark_m_info *kern = dst;
|
||||
|
||||
kern->mark = user->mark;
|
||||
kern->mask = user->mask;
|
||||
kern->invert = user->invert;
|
||||
kern->bitmask = user->bitmask;
|
||||
}
|
||||
|
||||
static int mark_mt_compat_to_user(void __user *dst, const void *src)
|
||||
{
|
||||
struct compat_ebt_mark_m_info __user *user = dst;
|
||||
const struct ebt_mark_m_info *kern = src;
|
||||
|
||||
if (put_user(kern->mark, &user->mark) ||
|
||||
put_user(kern->mask, &user->mask) ||
|
||||
put_user(kern->invert, &user->invert) ||
|
||||
put_user(kern->bitmask, &user->bitmask))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct xt_match ebt_mark_mt_reg __read_mostly = {
|
||||
.name = "mark_m",
|
||||
.revision = 0,
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_mark_mt,
|
||||
.checkentry = ebt_mark_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_mark_m_info)),
|
||||
.matchsize = sizeof(struct ebt_mark_m_info),
|
||||
#ifdef CONFIG_COMPAT
|
||||
.compatsize = sizeof(struct compat_ebt_mark_m_info),
|
||||
.compat_from_user = mark_mt_compat_from_user,
|
||||
.compat_to_user = mark_mt_compat_to_user,
|
||||
#endif
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ static struct xt_target ebt_nflog_tg_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.target = ebt_nflog_tg,
|
||||
.checkentry = ebt_nflog_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_nflog_info)),
|
||||
.targetsize = sizeof(struct ebt_nflog_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ static struct xt_match ebt_pkttype_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_pkttype_mt,
|
||||
.checkentry = ebt_pkttype_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_pkttype_info)),
|
||||
.matchsize = sizeof(struct ebt_pkttype_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -59,7 +59,7 @@ static struct xt_target ebt_redirect_tg_reg __read_mostly = {
|
||||
(1 << NF_BR_BROUTING),
|
||||
.target = ebt_redirect_tg,
|
||||
.checkentry = ebt_redirect_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_redirect_info)),
|
||||
.targetsize = sizeof(struct ebt_redirect_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -67,7 +67,7 @@ static struct xt_target ebt_snat_tg_reg __read_mostly = {
|
||||
.hooks = (1 << NF_BR_NUMHOOKS) | (1 << NF_BR_POST_ROUTING),
|
||||
.target = ebt_snat_tg,
|
||||
.checkentry = ebt_snat_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_nat_info)),
|
||||
.targetsize = sizeof(struct ebt_nat_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -177,7 +177,7 @@ static struct xt_match ebt_stp_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_stp_mt,
|
||||
.checkentry = ebt_stp_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_stp_info)),
|
||||
.matchsize = sizeof(struct ebt_stp_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -275,7 +275,7 @@ static struct xt_target ebt_ulog_tg_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.target = ebt_ulog_tg,
|
||||
.checkentry = ebt_ulog_tg_check,
|
||||
.targetsize = XT_ALIGN(sizeof(struct ebt_ulog_info)),
|
||||
.targetsize = sizeof(struct ebt_ulog_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -163,7 +163,7 @@ static struct xt_match ebt_vlan_mt_reg __read_mostly = {
|
||||
.family = NFPROTO_BRIDGE,
|
||||
.match = ebt_vlan_mt,
|
||||
.checkentry = ebt_vlan_mt_check,
|
||||
.matchsize = XT_ALIGN(sizeof(struct ebt_vlan_info)),
|
||||
.matchsize = sizeof(struct ebt_vlan_info),
|
||||
.me = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
@@ -71,7 +71,7 @@ static int __net_init broute_net_init(struct net *net)
|
||||
|
||||
static void __net_exit broute_net_exit(struct net *net)
|
||||
{
|
||||
ebt_unregister_table(net->xt.broute_table);
|
||||
ebt_unregister_table(net, net->xt.broute_table);
|
||||
}
|
||||
|
||||
static struct pernet_operations broute_net_ops = {
|
||||
|
||||
@@ -107,7 +107,7 @@ static int __net_init frame_filter_net_init(struct net *net)
|
||||
|
||||
static void __net_exit frame_filter_net_exit(struct net *net)
|
||||
{
|
||||
ebt_unregister_table(net->xt.frame_filter);
|
||||
ebt_unregister_table(net, net->xt.frame_filter);
|
||||
}
|
||||
|
||||
static struct pernet_operations frame_filter_net_ops = {
|
||||
|
||||
@@ -107,7 +107,7 @@ static int __net_init frame_nat_net_init(struct net *net)
|
||||
|
||||
static void __net_exit frame_nat_net_exit(struct net *net)
|
||||
{
|
||||
ebt_unregister_table(net->xt.frame_nat);
|
||||
ebt_unregister_table(net, net->xt.frame_nat);
|
||||
}
|
||||
|
||||
static struct pernet_operations frame_nat_net_ops = {
|
||||
|
||||
+1127
-192
File diff suppressed because it is too large
Load Diff
+40
-84
@@ -77,8 +77,8 @@ static int stats_timer __read_mostly = 1;
|
||||
module_param(stats_timer, int, S_IRUGO);
|
||||
MODULE_PARM_DESC(stats_timer, "enable timer for statistics (default:on)");
|
||||
|
||||
HLIST_HEAD(can_rx_dev_list);
|
||||
static struct dev_rcv_lists can_rx_alldev_list;
|
||||
/* receive filters subscribed for 'all' CAN devices */
|
||||
struct dev_rcv_lists can_rx_alldev_list;
|
||||
static DEFINE_SPINLOCK(can_rcvlists_lock);
|
||||
|
||||
static struct kmem_cache *rcv_cache __read_mostly;
|
||||
@@ -292,28 +292,10 @@ EXPORT_SYMBOL(can_send);
|
||||
|
||||
static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
|
||||
{
|
||||
struct dev_rcv_lists *d = NULL;
|
||||
struct hlist_node *n;
|
||||
|
||||
/*
|
||||
* find receive list for this device
|
||||
*
|
||||
* The hlist_for_each_entry*() macros curse through the list
|
||||
* using the pointer variable n and set d to the containing
|
||||
* struct in each list iteration. Therefore, after list
|
||||
* iteration, d is unmodified when the list is empty, and it
|
||||
* points to last list element, when the list is non-empty
|
||||
* but no match in the loop body is found. I.e. d is *not*
|
||||
* NULL when no match is found. We can, however, use the
|
||||
* cursor variable n to decide if a match was found.
|
||||
*/
|
||||
|
||||
hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
|
||||
if (d->dev == dev)
|
||||
break;
|
||||
}
|
||||
|
||||
return n ? d : NULL;
|
||||
if (!dev)
|
||||
return &can_rx_alldev_list;
|
||||
else
|
||||
return (struct dev_rcv_lists *)dev->ml_priv;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -433,6 +415,9 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
|
||||
/* insert new receiver (dev,canid,mask) -> (func,data) */
|
||||
|
||||
if (dev && dev->type != ARPHRD_CAN)
|
||||
return -ENODEV;
|
||||
|
||||
r = kmem_cache_alloc(rcv_cache, GFP_KERNEL);
|
||||
if (!r)
|
||||
return -ENOMEM;
|
||||
@@ -467,16 +452,6 @@ int can_rx_register(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
}
|
||||
EXPORT_SYMBOL(can_rx_register);
|
||||
|
||||
/*
|
||||
* can_rx_delete_device - rcu callback for dev_rcv_lists structure removal
|
||||
*/
|
||||
static void can_rx_delete_device(struct rcu_head *rp)
|
||||
{
|
||||
struct dev_rcv_lists *d = container_of(rp, struct dev_rcv_lists, rcu);
|
||||
|
||||
kfree(d);
|
||||
}
|
||||
|
||||
/*
|
||||
* can_rx_delete_receiver - rcu callback for single receiver entry removal
|
||||
*/
|
||||
@@ -506,6 +481,9 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
struct hlist_node *next;
|
||||
struct dev_rcv_lists *d;
|
||||
|
||||
if (dev && dev->type != ARPHRD_CAN)
|
||||
return;
|
||||
|
||||
spin_lock(&can_rcvlists_lock);
|
||||
|
||||
d = find_dev_rcv_lists(dev);
|
||||
@@ -541,7 +519,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
"dev %s, id %03X, mask %03X\n",
|
||||
DNAME(dev), can_id, mask);
|
||||
r = NULL;
|
||||
d = NULL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
@@ -552,10 +529,10 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
can_pstats.rcv_entries--;
|
||||
|
||||
/* remove device structure requested by NETDEV_UNREGISTER */
|
||||
if (d->remove_on_zero_entries && !d->entries)
|
||||
hlist_del_rcu(&d->list);
|
||||
else
|
||||
d = NULL;
|
||||
if (d->remove_on_zero_entries && !d->entries) {
|
||||
kfree(d);
|
||||
dev->ml_priv = NULL;
|
||||
}
|
||||
|
||||
out:
|
||||
spin_unlock(&can_rcvlists_lock);
|
||||
@@ -563,10 +540,6 @@ void can_rx_unregister(struct net_device *dev, canid_t can_id, canid_t mask,
|
||||
/* schedule the receiver item for deletion */
|
||||
if (r)
|
||||
call_rcu(&r->rcu, can_rx_delete_receiver);
|
||||
|
||||
/* schedule the device structure for deletion */
|
||||
if (d)
|
||||
call_rcu(&d->rcu, can_rx_delete_device);
|
||||
}
|
||||
EXPORT_SYMBOL(can_rx_unregister);
|
||||
|
||||
@@ -780,48 +753,35 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
|
||||
|
||||
case NETDEV_REGISTER:
|
||||
|
||||
/*
|
||||
* create new dev_rcv_lists for this device
|
||||
*
|
||||
* N.B. zeroing the struct is the correct initialization
|
||||
* for the embedded hlist_head structs.
|
||||
* Another list type, e.g. list_head, would require
|
||||
* explicit initialization.
|
||||
*/
|
||||
|
||||
/* create new dev_rcv_lists for this device */
|
||||
d = kzalloc(sizeof(*d), GFP_KERNEL);
|
||||
if (!d) {
|
||||
printk(KERN_ERR
|
||||
"can: allocation of receive list failed\n");
|
||||
return NOTIFY_DONE;
|
||||
}
|
||||
d->dev = dev;
|
||||
|
||||
spin_lock(&can_rcvlists_lock);
|
||||
hlist_add_head_rcu(&d->list, &can_rx_dev_list);
|
||||
spin_unlock(&can_rcvlists_lock);
|
||||
BUG_ON(dev->ml_priv);
|
||||
dev->ml_priv = d;
|
||||
|
||||
break;
|
||||
|
||||
case NETDEV_UNREGISTER:
|
||||
spin_lock(&can_rcvlists_lock);
|
||||
|
||||
d = find_dev_rcv_lists(dev);
|
||||
d = dev->ml_priv;
|
||||
if (d) {
|
||||
if (d->entries) {
|
||||
if (d->entries)
|
||||
d->remove_on_zero_entries = 1;
|
||||
d = NULL;
|
||||
} else
|
||||
hlist_del_rcu(&d->list);
|
||||
else {
|
||||
kfree(d);
|
||||
dev->ml_priv = NULL;
|
||||
}
|
||||
} else
|
||||
printk(KERN_ERR "can: notifier: receive list not "
|
||||
"found for dev %s\n", dev->name);
|
||||
|
||||
spin_unlock(&can_rcvlists_lock);
|
||||
|
||||
if (d)
|
||||
call_rcu(&d->rcu, can_rx_delete_device);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -853,21 +813,13 @@ static __init int can_init(void)
|
||||
{
|
||||
printk(banner);
|
||||
|
||||
memset(&can_rx_alldev_list, 0, sizeof(can_rx_alldev_list));
|
||||
|
||||
rcv_cache = kmem_cache_create("can_receiver", sizeof(struct receiver),
|
||||
0, 0, NULL);
|
||||
if (!rcv_cache)
|
||||
return -ENOMEM;
|
||||
|
||||
/*
|
||||
* Insert can_rx_alldev_list for reception on all devices.
|
||||
* This struct is zero initialized which is correct for the
|
||||
* embedded hlist heads, the dev pointer, and the entries counter.
|
||||
*/
|
||||
|
||||
spin_lock(&can_rcvlists_lock);
|
||||
hlist_add_head_rcu(&can_rx_alldev_list.list, &can_rx_dev_list);
|
||||
spin_unlock(&can_rcvlists_lock);
|
||||
|
||||
if (stats_timer) {
|
||||
/* the statistics are updated every second (timer triggered) */
|
||||
setup_timer(&can_stattimer, can_stat_update, 0);
|
||||
@@ -887,8 +839,7 @@ static __init int can_init(void)
|
||||
|
||||
static __exit void can_exit(void)
|
||||
{
|
||||
struct dev_rcv_lists *d;
|
||||
struct hlist_node *n, *next;
|
||||
struct net_device *dev;
|
||||
|
||||
if (stats_timer)
|
||||
del_timer(&can_stattimer);
|
||||
@@ -900,14 +851,19 @@ static __exit void can_exit(void)
|
||||
unregister_netdevice_notifier(&can_netdev_notifier);
|
||||
sock_unregister(PF_CAN);
|
||||
|
||||
/* remove can_rx_dev_list */
|
||||
spin_lock(&can_rcvlists_lock);
|
||||
hlist_del(&can_rx_alldev_list.list);
|
||||
hlist_for_each_entry_safe(d, n, next, &can_rx_dev_list, list) {
|
||||
hlist_del(&d->list);
|
||||
kfree(d);
|
||||
/* remove created dev_rcv_lists from still registered CAN devices */
|
||||
rcu_read_lock();
|
||||
for_each_netdev_rcu(&init_net, dev) {
|
||||
if (dev->type == ARPHRD_CAN && dev->ml_priv){
|
||||
|
||||
struct dev_rcv_lists *d = dev->ml_priv;
|
||||
|
||||
BUG_ON(d->entries);
|
||||
kfree(d);
|
||||
dev->ml_priv = NULL;
|
||||
}
|
||||
}
|
||||
spin_unlock(&can_rcvlists_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
rcu_barrier(); /* Wait for completion of call_rcu()'s */
|
||||
|
||||
|
||||
+1
-3
@@ -63,10 +63,8 @@ struct receiver {
|
||||
|
||||
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX };
|
||||
|
||||
/* per device receive filters linked at dev->ml_priv */
|
||||
struct dev_rcv_lists {
|
||||
struct hlist_node list;
|
||||
struct rcu_head rcu;
|
||||
struct net_device *dev;
|
||||
struct hlist_head rx[RX_MAX];
|
||||
struct hlist_head rx_sff[0x800];
|
||||
int remove_on_zero_entries;
|
||||
|
||||
+60
-31
@@ -45,6 +45,7 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/list.h>
|
||||
#include <linux/rcupdate.h>
|
||||
#include <linux/if_arp.h>
|
||||
#include <linux/can/core.h>
|
||||
|
||||
#include "af_can.h"
|
||||
@@ -84,6 +85,9 @@ static const char rx_list_name[][8] = {
|
||||
[RX_EFF] = "rx_eff",
|
||||
};
|
||||
|
||||
/* receive filters subscribed for 'all' CAN devices */
|
||||
extern struct dev_rcv_lists can_rx_alldev_list;
|
||||
|
||||
/*
|
||||
* af_can statistics stuff
|
||||
*/
|
||||
@@ -190,10 +194,6 @@ void can_stat_update(unsigned long data)
|
||||
|
||||
/*
|
||||
* proc read functions
|
||||
*
|
||||
* From known use-cases we expect about 10 entries in a receive list to be
|
||||
* printed in the proc_fs. So PAGE_SIZE is definitely enough space here.
|
||||
*
|
||||
*/
|
||||
|
||||
static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
|
||||
@@ -202,7 +202,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
|
||||
struct receiver *r;
|
||||
struct hlist_node *n;
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(r, n, rx_list, list) {
|
||||
char *fmt = (r->can_id & CAN_EFF_FLAG)?
|
||||
" %-5s %08X %08x %08x %08x %8ld %s\n" :
|
||||
@@ -212,7 +211,6 @@ static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
|
||||
(unsigned long)r->func, (unsigned long)r->data,
|
||||
r->matches, r->ident);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
}
|
||||
|
||||
static void can_print_recv_banner(struct seq_file *m)
|
||||
@@ -346,24 +344,39 @@ static const struct file_operations can_version_proc_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
|
||||
struct net_device *dev,
|
||||
struct dev_rcv_lists *d)
|
||||
{
|
||||
if (!hlist_empty(&d->rx[idx])) {
|
||||
can_print_recv_banner(m);
|
||||
can_print_rcvlist(m, &d->rx[idx], dev);
|
||||
} else
|
||||
seq_printf(m, " (%s: no entry)\n", DNAME(dev));
|
||||
|
||||
}
|
||||
|
||||
static int can_rcvlist_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
/* double cast to prevent GCC warning */
|
||||
int idx = (int)(long)m->private;
|
||||
struct net_device *dev;
|
||||
struct dev_rcv_lists *d;
|
||||
struct hlist_node *n;
|
||||
|
||||
seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
|
||||
|
||||
if (!hlist_empty(&d->rx[idx])) {
|
||||
can_print_recv_banner(m);
|
||||
can_print_rcvlist(m, &d->rx[idx], d->dev);
|
||||
} else
|
||||
seq_printf(m, " (%s: no entry)\n", DNAME(d->dev));
|
||||
/* receive list for 'all' CAN devices (dev == NULL) */
|
||||
d = &can_rx_alldev_list;
|
||||
can_rcvlist_proc_show_one(m, idx, NULL, d);
|
||||
|
||||
/* receive list for registered CAN devices */
|
||||
for_each_netdev_rcu(&init_net, dev) {
|
||||
if (dev->type == ARPHRD_CAN && dev->ml_priv)
|
||||
can_rcvlist_proc_show_one(m, idx, dev, dev->ml_priv);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_putc(m, '\n');
|
||||
@@ -383,34 +396,50 @@ static const struct file_operations can_rcvlist_proc_fops = {
|
||||
.release = single_release,
|
||||
};
|
||||
|
||||
static inline void can_rcvlist_sff_proc_show_one(struct seq_file *m,
|
||||
struct net_device *dev,
|
||||
struct dev_rcv_lists *d)
|
||||
{
|
||||
int i;
|
||||
int all_empty = 1;
|
||||
|
||||
/* check wether at least one list is non-empty */
|
||||
for (i = 0; i < 0x800; i++)
|
||||
if (!hlist_empty(&d->rx_sff[i])) {
|
||||
all_empty = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!all_empty) {
|
||||
can_print_recv_banner(m);
|
||||
for (i = 0; i < 0x800; i++) {
|
||||
if (!hlist_empty(&d->rx_sff[i]))
|
||||
can_print_rcvlist(m, &d->rx_sff[i], dev);
|
||||
}
|
||||
} else
|
||||
seq_printf(m, " (%s: no entry)\n", DNAME(dev));
|
||||
}
|
||||
|
||||
static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
|
||||
{
|
||||
struct net_device *dev;
|
||||
struct dev_rcv_lists *d;
|
||||
struct hlist_node *n;
|
||||
|
||||
/* RX_SFF */
|
||||
seq_puts(m, "\nreceive list 'rx_sff':\n");
|
||||
|
||||
rcu_read_lock();
|
||||
hlist_for_each_entry_rcu(d, n, &can_rx_dev_list, list) {
|
||||
int i, all_empty = 1;
|
||||
/* check wether at least one list is non-empty */
|
||||
for (i = 0; i < 0x800; i++)
|
||||
if (!hlist_empty(&d->rx_sff[i])) {
|
||||
all_empty = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!all_empty) {
|
||||
can_print_recv_banner(m);
|
||||
for (i = 0; i < 0x800; i++) {
|
||||
if (!hlist_empty(&d->rx_sff[i]))
|
||||
can_print_rcvlist(m, &d->rx_sff[i],
|
||||
d->dev);
|
||||
}
|
||||
} else
|
||||
seq_printf(m, " (%s: no entry)\n", DNAME(d->dev));
|
||||
/* sff receive list for 'all' CAN devices (dev == NULL) */
|
||||
d = &can_rx_alldev_list;
|
||||
can_rcvlist_sff_proc_show_one(m, NULL, d);
|
||||
|
||||
/* sff receive list for registered CAN devices */
|
||||
for_each_netdev_rcu(&init_net, dev) {
|
||||
if (dev->type == ARPHRD_CAN && dev->ml_priv)
|
||||
can_rcvlist_sff_proc_show_one(m, dev, dev->ml_priv);
|
||||
}
|
||||
|
||||
rcu_read_unlock();
|
||||
|
||||
seq_putc(m, '\n');
|
||||
|
||||
+201
-93
@@ -1113,32 +1113,13 @@ void dev_load(struct net *net, const char *name)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_load);
|
||||
|
||||
/**
|
||||
* dev_open - prepare an interface for use.
|
||||
* @dev: device to open
|
||||
*
|
||||
* Takes a device from down to up state. The device's private open
|
||||
* function is invoked and then the multicast lists are loaded. Finally
|
||||
* the device is moved into the up state and a %NETDEV_UP message is
|
||||
* sent to the netdev notifier chain.
|
||||
*
|
||||
* Calling this function on an active interface is a nop. On a failure
|
||||
* a negative errno code is returned.
|
||||
*/
|
||||
int dev_open(struct net_device *dev)
|
||||
static int __dev_open(struct net_device *dev)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
int ret;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
/*
|
||||
* Is it already up?
|
||||
*/
|
||||
|
||||
if (dev->flags & IFF_UP)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Is it even present?
|
||||
*/
|
||||
@@ -1187,36 +1168,57 @@ int dev_open(struct net_device *dev)
|
||||
* Wakeup transmit queue engine
|
||||
*/
|
||||
dev_activate(dev);
|
||||
|
||||
/*
|
||||
* ... and announce new interface.
|
||||
*/
|
||||
call_netdevice_notifiers(NETDEV_UP, dev);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_open - prepare an interface for use.
|
||||
* @dev: device to open
|
||||
*
|
||||
* Takes a device from down to up state. The device's private open
|
||||
* function is invoked and then the multicast lists are loaded. Finally
|
||||
* the device is moved into the up state and a %NETDEV_UP message is
|
||||
* sent to the netdev notifier chain.
|
||||
*
|
||||
* Calling this function on an active interface is a nop. On a failure
|
||||
* a negative errno code is returned.
|
||||
*/
|
||||
int dev_open(struct net_device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
/*
|
||||
* Is it already up?
|
||||
*/
|
||||
if (dev->flags & IFF_UP)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Open device
|
||||
*/
|
||||
ret = __dev_open(dev);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
/*
|
||||
* ... and announce new interface.
|
||||
*/
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
|
||||
call_netdevice_notifiers(NETDEV_UP, dev);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dev_open);
|
||||
|
||||
/**
|
||||
* dev_close - shutdown an interface.
|
||||
* @dev: device to shutdown
|
||||
*
|
||||
* This function moves an active device into down state. A
|
||||
* %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
|
||||
* is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
|
||||
* chain.
|
||||
*/
|
||||
int dev_close(struct net_device *dev)
|
||||
static int __dev_close(struct net_device *dev)
|
||||
{
|
||||
const struct net_device_ops *ops = dev->netdev_ops;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
might_sleep();
|
||||
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return 0;
|
||||
|
||||
/*
|
||||
* Tell people we are going down, so that they can
|
||||
* prepare to death, when device is still operating.
|
||||
@@ -1251,11 +1253,6 @@ int dev_close(struct net_device *dev)
|
||||
|
||||
dev->flags &= ~IFF_UP;
|
||||
|
||||
/*
|
||||
* Tell people we are down
|
||||
*/
|
||||
call_netdevice_notifiers(NETDEV_DOWN, dev);
|
||||
|
||||
/*
|
||||
* Shutdown NET_DMA
|
||||
*/
|
||||
@@ -1263,6 +1260,31 @@ int dev_close(struct net_device *dev)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_close - shutdown an interface.
|
||||
* @dev: device to shutdown
|
||||
*
|
||||
* This function moves an active device into down state. A
|
||||
* %NETDEV_GOING_DOWN is sent to the netdev notifier chain. The device
|
||||
* is then deactivated and finally a %NETDEV_DOWN is sent to the notifier
|
||||
* chain.
|
||||
*/
|
||||
int dev_close(struct net_device *dev)
|
||||
{
|
||||
if (!(dev->flags & IFF_UP))
|
||||
return 0;
|
||||
|
||||
__dev_close(dev);
|
||||
|
||||
/*
|
||||
* Tell people we are down
|
||||
*/
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
|
||||
call_netdevice_notifiers(NETDEV_DOWN, dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(dev_close);
|
||||
|
||||
|
||||
@@ -1448,13 +1470,10 @@ int dev_forward_skb(struct net_device *dev, struct sk_buff *skb)
|
||||
if (skb->len > (dev->mtu + dev->hard_header_len))
|
||||
return NET_RX_DROP;
|
||||
|
||||
skb_dst_drop(skb);
|
||||
skb_set_dev(skb, dev);
|
||||
skb->tstamp.tv64 = 0;
|
||||
skb->pkt_type = PACKET_HOST;
|
||||
skb->protocol = eth_type_trans(skb, dev);
|
||||
skb->mark = 0;
|
||||
secpath_reset(skb);
|
||||
nf_reset(skb);
|
||||
return netif_rx(skb);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_forward_skb);
|
||||
@@ -1614,6 +1633,36 @@ static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* skb_dev_set -- assign a new device to a buffer
|
||||
* @skb: buffer for the new device
|
||||
* @dev: network device
|
||||
*
|
||||
* If an skb is owned by a device already, we have to reset
|
||||
* all data private to the namespace a device belongs to
|
||||
* before assigning it a new device.
|
||||
*/
|
||||
#ifdef CONFIG_NET_NS
|
||||
void skb_set_dev(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
skb_dst_drop(skb);
|
||||
if (skb->dev && !net_eq(dev_net(skb->dev), dev_net(dev))) {
|
||||
secpath_reset(skb);
|
||||
nf_reset(skb);
|
||||
skb_init_secmark(skb);
|
||||
skb->mark = 0;
|
||||
skb->priority = 0;
|
||||
skb->nf_trace = 0;
|
||||
skb->ipvs_property = 0;
|
||||
#ifdef CONFIG_NET_SCHED
|
||||
skb->tc_index = 0;
|
||||
#endif
|
||||
}
|
||||
skb->dev = dev;
|
||||
}
|
||||
EXPORT_SYMBOL(skb_set_dev);
|
||||
#endif /* CONFIG_NET_NS */
|
||||
|
||||
/*
|
||||
* Invalidate hardware checksum when packet is to be mangled, and
|
||||
* complete checksum manually on outgoing path.
|
||||
@@ -1853,6 +1902,14 @@ gso:
|
||||
|
||||
skb->next = nskb->next;
|
||||
nskb->next = NULL;
|
||||
|
||||
/*
|
||||
* If device doesnt need nskb->dst, release it right now while
|
||||
* its hot in this cpu cache
|
||||
*/
|
||||
if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
|
||||
skb_dst_drop(nskb);
|
||||
|
||||
rc = ops->ndo_start_xmit(nskb, dev);
|
||||
if (unlikely(rc != NETDEV_TX_OK)) {
|
||||
if (rc & ~NETDEV_TX_MASK)
|
||||
@@ -1974,6 +2031,21 @@ static inline int __dev_xmit_skb(struct sk_buff *skb, struct Qdisc *q,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns true if either:
|
||||
* 1. skb has frag_list and the device doesn't support FRAGLIST, or
|
||||
* 2. skb is fragmented and the device does not support SG, or if
|
||||
* at least one of fragments is in highmem and device does not
|
||||
* support DMA from it.
|
||||
*/
|
||||
static inline int skb_needs_linearize(struct sk_buff *skb,
|
||||
struct net_device *dev)
|
||||
{
|
||||
return (skb_has_frags(skb) && !(dev->features & NETIF_F_FRAGLIST)) ||
|
||||
(skb_shinfo(skb)->nr_frags && (!(dev->features & NETIF_F_SG) ||
|
||||
illegal_highdma(dev, skb)));
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_queue_xmit - transmit a buffer
|
||||
* @skb: buffer to transmit
|
||||
@@ -2010,18 +2082,8 @@ int dev_queue_xmit(struct sk_buff *skb)
|
||||
if (netif_needs_gso(dev, skb))
|
||||
goto gso;
|
||||
|
||||
if (skb_has_frags(skb) &&
|
||||
!(dev->features & NETIF_F_FRAGLIST) &&
|
||||
__skb_linearize(skb))
|
||||
goto out_kfree_skb;
|
||||
|
||||
/* Fragmented skb is linearized if device does not support SG,
|
||||
* or if at least one of fragments is in highmem and device
|
||||
* does not support DMA from it.
|
||||
*/
|
||||
if (skb_shinfo(skb)->nr_frags &&
|
||||
(!(dev->features & NETIF_F_SG) || illegal_highdma(dev, skb)) &&
|
||||
__skb_linearize(skb))
|
||||
/* Convert a paged skb to linear, if required */
|
||||
if (skb_needs_linearize(skb, dev) && __skb_linearize(skb))
|
||||
goto out_kfree_skb;
|
||||
|
||||
/* If packet is not checksummed and device does not support
|
||||
@@ -2041,7 +2103,7 @@ gso:
|
||||
rcu_read_lock_bh();
|
||||
|
||||
txq = dev_pick_tx(dev, skb);
|
||||
q = rcu_dereference(txq->qdisc);
|
||||
q = rcu_dereference_bh(txq->qdisc);
|
||||
|
||||
#ifdef CONFIG_NET_CLS_ACT
|
||||
skb->tc_verd = SET_TC_AT(skb->tc_verd, AT_EGRESS);
|
||||
@@ -2422,6 +2484,7 @@ int netif_receive_skb(struct sk_buff *skb)
|
||||
struct packet_type *ptype, *pt_prev;
|
||||
struct net_device *orig_dev;
|
||||
struct net_device *null_or_orig;
|
||||
struct net_device *null_or_bond;
|
||||
int ret = NET_RX_DROP;
|
||||
__be16 type;
|
||||
|
||||
@@ -2487,12 +2550,24 @@ ncls:
|
||||
if (!skb)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* Make sure frames received on VLAN interfaces stacked on
|
||||
* bonding interfaces still make their way to any base bonding
|
||||
* device that may have registered for a specific ptype. The
|
||||
* handler may have to adjust skb->dev and orig_dev.
|
||||
*/
|
||||
null_or_bond = NULL;
|
||||
if ((skb->dev->priv_flags & IFF_802_1Q_VLAN) &&
|
||||
(vlan_dev_real_dev(skb->dev)->priv_flags & IFF_BONDING)) {
|
||||
null_or_bond = vlan_dev_real_dev(skb->dev);
|
||||
}
|
||||
|
||||
type = skb->protocol;
|
||||
list_for_each_entry_rcu(ptype,
|
||||
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
|
||||
if (ptype->type == type &&
|
||||
(ptype->dev == null_or_orig || ptype->dev == skb->dev ||
|
||||
ptype->dev == orig_dev)) {
|
||||
if (ptype->type == type && (ptype->dev == null_or_orig ||
|
||||
ptype->dev == skb->dev || ptype->dev == orig_dev ||
|
||||
ptype->dev == null_or_bond)) {
|
||||
if (pt_prev)
|
||||
ret = deliver_skb(skb, pt_prev, orig_dev);
|
||||
pt_prev = ptype;
|
||||
@@ -2561,7 +2636,7 @@ out:
|
||||
return netif_receive_skb(skb);
|
||||
}
|
||||
|
||||
void napi_gro_flush(struct napi_struct *napi)
|
||||
static void napi_gro_flush(struct napi_struct *napi)
|
||||
{
|
||||
struct sk_buff *skb, *next;
|
||||
|
||||
@@ -2574,7 +2649,6 @@ void napi_gro_flush(struct napi_struct *napi)
|
||||
napi->gro_count = 0;
|
||||
napi->gro_list = NULL;
|
||||
}
|
||||
EXPORT_SYMBOL(napi_gro_flush);
|
||||
|
||||
enum gro_result dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
|
||||
{
|
||||
@@ -2761,7 +2835,7 @@ gro_result_t napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb,
|
||||
switch (ret) {
|
||||
case GRO_NORMAL:
|
||||
case GRO_HELD:
|
||||
skb->protocol = eth_type_trans(skb, napi->dev);
|
||||
skb->protocol = eth_type_trans(skb, skb->dev);
|
||||
|
||||
if (ret == GRO_HELD)
|
||||
skb_gro_pull(skb, -ETH_HLEN);
|
||||
@@ -2966,7 +3040,7 @@ static void net_rx_action(struct softirq_action *h)
|
||||
* entries to the tail of this list, and only ->poll()
|
||||
* calls can remove this head entry from the list.
|
||||
*/
|
||||
n = list_entry(list->next, struct napi_struct, poll_list);
|
||||
n = list_first_entry(list, struct napi_struct, poll_list);
|
||||
|
||||
have = netpoll_poll_lock(n);
|
||||
|
||||
@@ -3185,7 +3259,7 @@ static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
|
||||
{
|
||||
const struct net_device_stats *stats = dev_get_stats(dev);
|
||||
|
||||
seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
|
||||
seq_printf(seq, "%6s: %7lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu "
|
||||
"%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n",
|
||||
dev->name, stats->rx_bytes, stats->rx_packets,
|
||||
stats->rx_errors,
|
||||
@@ -3640,10 +3714,10 @@ void __dev_set_rx_mode(struct net_device *dev)
|
||||
/* Unicast addresses changes may only happen under the rtnl,
|
||||
* therefore calling __dev_set_promiscuity here is safe.
|
||||
*/
|
||||
if (dev->uc.count > 0 && !dev->uc_promisc) {
|
||||
if (!netdev_uc_empty(dev) && !dev->uc_promisc) {
|
||||
__dev_set_promiscuity(dev, 1);
|
||||
dev->uc_promisc = 1;
|
||||
} else if (dev->uc.count == 0 && dev->uc_promisc) {
|
||||
} else if (netdev_uc_empty(dev) && dev->uc_promisc) {
|
||||
__dev_set_promiscuity(dev, -1);
|
||||
dev->uc_promisc = 0;
|
||||
}
|
||||
@@ -4211,7 +4285,7 @@ static void dev_addr_discard(struct net_device *dev)
|
||||
netif_addr_lock_bh(dev);
|
||||
|
||||
__dev_addr_discard(&dev->mc_list);
|
||||
dev->mc_count = 0;
|
||||
netdev_mc_count(dev) = 0;
|
||||
|
||||
netif_addr_unlock_bh(dev);
|
||||
}
|
||||
@@ -4247,18 +4321,10 @@ unsigned dev_get_flags(const struct net_device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(dev_get_flags);
|
||||
|
||||
/**
|
||||
* dev_change_flags - change device settings
|
||||
* @dev: device
|
||||
* @flags: device state flags
|
||||
*
|
||||
* Change settings on device based state flags. The flags are
|
||||
* in the userspace exported format.
|
||||
*/
|
||||
int dev_change_flags(struct net_device *dev, unsigned flags)
|
||||
int __dev_change_flags(struct net_device *dev, unsigned int flags)
|
||||
{
|
||||
int ret, changes;
|
||||
int old_flags = dev->flags;
|
||||
int ret;
|
||||
|
||||
ASSERT_RTNL();
|
||||
|
||||
@@ -4289,17 +4355,12 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
|
||||
|
||||
ret = 0;
|
||||
if ((old_flags ^ flags) & IFF_UP) { /* Bit is different ? */
|
||||
ret = ((old_flags & IFF_UP) ? dev_close : dev_open)(dev);
|
||||
ret = ((old_flags & IFF_UP) ? __dev_close : __dev_open)(dev);
|
||||
|
||||
if (!ret)
|
||||
dev_set_rx_mode(dev);
|
||||
}
|
||||
|
||||
if (dev->flags & IFF_UP &&
|
||||
((old_flags ^ dev->flags) & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI |
|
||||
IFF_VOLATILE)))
|
||||
call_netdevice_notifiers(NETDEV_CHANGE, dev);
|
||||
|
||||
if ((flags ^ dev->gflags) & IFF_PROMISC) {
|
||||
int inc = (flags & IFF_PROMISC) ? 1 : -1;
|
||||
|
||||
@@ -4318,11 +4379,47 @@ int dev_change_flags(struct net_device *dev, unsigned flags)
|
||||
dev_set_allmulti(dev, inc);
|
||||
}
|
||||
|
||||
/* Exclude state transition flags, already notified */
|
||||
changes = (old_flags ^ dev->flags) & ~(IFF_UP | IFF_RUNNING);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void __dev_notify_flags(struct net_device *dev, unsigned int old_flags)
|
||||
{
|
||||
unsigned int changes = dev->flags ^ old_flags;
|
||||
|
||||
if (changes & IFF_UP) {
|
||||
if (dev->flags & IFF_UP)
|
||||
call_netdevice_notifiers(NETDEV_UP, dev);
|
||||
else
|
||||
call_netdevice_notifiers(NETDEV_DOWN, dev);
|
||||
}
|
||||
|
||||
if (dev->flags & IFF_UP &&
|
||||
(changes & ~(IFF_UP | IFF_PROMISC | IFF_ALLMULTI | IFF_VOLATILE)))
|
||||
call_netdevice_notifiers(NETDEV_CHANGE, dev);
|
||||
}
|
||||
|
||||
/**
|
||||
* dev_change_flags - change device settings
|
||||
* @dev: device
|
||||
* @flags: device state flags
|
||||
*
|
||||
* Change settings on device based state flags. The flags are
|
||||
* in the userspace exported format.
|
||||
*/
|
||||
int dev_change_flags(struct net_device *dev, unsigned flags)
|
||||
{
|
||||
int ret, changes;
|
||||
int old_flags = dev->flags;
|
||||
|
||||
ret = __dev_change_flags(dev, flags);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
changes = old_flags ^ dev->flags;
|
||||
if (changes)
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, changes);
|
||||
|
||||
__dev_notify_flags(dev, old_flags);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(dev_change_flags);
|
||||
@@ -4813,6 +4910,10 @@ static void rollback_registered_many(struct list_head *head)
|
||||
*/
|
||||
call_netdevice_notifiers(NETDEV_UNREGISTER, dev);
|
||||
|
||||
if (!dev->rtnl_link_ops ||
|
||||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
|
||||
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
|
||||
|
||||
/*
|
||||
* Flush the unicast and multicast chains
|
||||
*/
|
||||
@@ -4830,7 +4931,7 @@ static void rollback_registered_many(struct list_head *head)
|
||||
}
|
||||
|
||||
/* Process any work delayed until the end of the batch */
|
||||
dev = list_entry(head->next, struct net_device, unreg_list);
|
||||
dev = list_first_entry(head, struct net_device, unreg_list);
|
||||
call_netdevice_notifiers(NETDEV_UNREGISTER_BATCH, dev);
|
||||
|
||||
synchronize_net();
|
||||
@@ -5039,7 +5140,9 @@ int register_netdevice(struct net_device *dev)
|
||||
* Prevent userspace races by waiting until the network
|
||||
* device is fully setup before sending notifications.
|
||||
*/
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
|
||||
if (!dev->rtnl_link_ops ||
|
||||
dev->rtnl_link_state == RTNL_LINK_INITIALIZED)
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
|
||||
|
||||
out:
|
||||
return ret;
|
||||
@@ -5216,7 +5319,7 @@ void netdev_run_todo(void)
|
||||
|
||||
while (!list_empty(&list)) {
|
||||
struct net_device *dev
|
||||
= list_entry(list.next, struct net_device, todo_list);
|
||||
= list_first_entry(&list, struct net_device, todo_list);
|
||||
list_del(&dev->todo_list);
|
||||
|
||||
if (unlikely(dev->reg_state != NETREG_UNREGISTERING)) {
|
||||
@@ -5367,6 +5470,8 @@ struct net_device *alloc_netdev_mq(int sizeof_priv, const char *name,
|
||||
|
||||
netdev_init_queues(dev);
|
||||
|
||||
INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
|
||||
dev->ethtool_ntuple_list.count = 0;
|
||||
INIT_LIST_HEAD(&dev->napi_list);
|
||||
INIT_LIST_HEAD(&dev->unreg_list);
|
||||
INIT_LIST_HEAD(&dev->link_watch_list);
|
||||
@@ -5403,6 +5508,9 @@ void free_netdev(struct net_device *dev)
|
||||
/* Flush device addresses */
|
||||
dev_addr_flush(dev);
|
||||
|
||||
/* Clear ethtool n-tuple list */
|
||||
ethtool_ntuple_flush(dev);
|
||||
|
||||
list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
|
||||
netif_napi_del(p);
|
||||
|
||||
|
||||
@@ -96,6 +96,8 @@ int dev_mc_add(struct net_device *dev, void *addr, int alen, int glbl)
|
||||
int err;
|
||||
|
||||
netif_addr_lock_bh(dev);
|
||||
if (alen != dev->addr_len)
|
||||
return -EINVAL;
|
||||
err = __dev_addr_add(&dev->mc_list, &dev->mc_count, addr, alen, glbl);
|
||||
if (!err)
|
||||
__dev_set_rx_mode(dev);
|
||||
|
||||
@@ -296,7 +296,6 @@ static int dropmon_net_event(struct notifier_block *ev_block,
|
||||
|
||||
new_stat->dev = dev;
|
||||
new_stat->last_rx = jiffies;
|
||||
INIT_RCU_HEAD(&new_stat->rcu);
|
||||
spin_lock(&trace_state_lock);
|
||||
list_add_rcu(&new_stat->list, &hw_stats_list);
|
||||
spin_unlock(&trace_state_lock);
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/types.h>
|
||||
#include <net/net_namespace.h>
|
||||
#include <linux/sched.h>
|
||||
|
||||
#include <net/dst.h>
|
||||
|
||||
@@ -79,6 +80,7 @@ loop:
|
||||
while ((dst = next) != NULL) {
|
||||
next = dst->next;
|
||||
prefetch(&next->next);
|
||||
cond_resched();
|
||||
if (likely(atomic_read(&dst->__refcnt))) {
|
||||
last->next = dst;
|
||||
last = dst;
|
||||
|
||||
+375
-16
@@ -120,7 +120,7 @@ int ethtool_op_set_ufo(struct net_device *dev, u32 data)
|
||||
* NETIF_F_xxx values in include/linux/netdevice.h
|
||||
*/
|
||||
static const u32 flags_dup_features =
|
||||
ETH_FLAG_LRO;
|
||||
(ETH_FLAG_LRO | ETH_FLAG_NTUPLE);
|
||||
|
||||
u32 ethtool_op_get_flags(struct net_device *dev)
|
||||
{
|
||||
@@ -134,19 +134,44 @@ u32 ethtool_op_get_flags(struct net_device *dev)
|
||||
|
||||
int ethtool_op_set_flags(struct net_device *dev, u32 data)
|
||||
{
|
||||
if (data & ETH_FLAG_LRO)
|
||||
dev->features |= NETIF_F_LRO;
|
||||
else
|
||||
dev->features &= ~NETIF_F_LRO;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
unsigned long features = dev->features;
|
||||
|
||||
if (data & ETH_FLAG_LRO)
|
||||
features |= NETIF_F_LRO;
|
||||
else
|
||||
features &= ~NETIF_F_LRO;
|
||||
|
||||
if (data & ETH_FLAG_NTUPLE) {
|
||||
if (!ops->set_rx_ntuple)
|
||||
return -EOPNOTSUPP;
|
||||
features |= NETIF_F_NTUPLE;
|
||||
} else {
|
||||
/* safe to clear regardless */
|
||||
features &= ~NETIF_F_NTUPLE;
|
||||
}
|
||||
|
||||
dev->features = features;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void ethtool_ntuple_flush(struct net_device *dev)
|
||||
{
|
||||
struct ethtool_rx_ntuple_flow_spec_container *fsc, *f;
|
||||
|
||||
list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) {
|
||||
list_del(&fsc->list);
|
||||
kfree(fsc);
|
||||
}
|
||||
dev->ethtool_ntuple_list.count = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(ethtool_ntuple_flush);
|
||||
|
||||
/* Handlers for each ethtool command */
|
||||
|
||||
static int ethtool_get_settings(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_cmd cmd = { ETHTOOL_GSET };
|
||||
struct ethtool_cmd cmd = { .cmd = ETHTOOL_GSET };
|
||||
int err;
|
||||
|
||||
if (!dev->ethtool_ops->get_settings)
|
||||
@@ -174,7 +199,10 @@ static int ethtool_set_settings(struct net_device *dev, void __user *useraddr)
|
||||
return dev->ethtool_ops->set_settings(dev, &cmd);
|
||||
}
|
||||
|
||||
static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_drvinfo info;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
@@ -209,7 +237,10 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_rxnfc cmd;
|
||||
|
||||
@@ -222,7 +253,10 @@ static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
|
||||
return dev->ethtool_ops->set_rxnfc(dev, &cmd);
|
||||
}
|
||||
|
||||
static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_rxnfc info;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
@@ -266,6 +300,315 @@ err_out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
|
||||
struct ethtool_rx_ntuple_flow_spec *spec,
|
||||
struct ethtool_rx_ntuple_flow_spec_container *fsc)
|
||||
{
|
||||
|
||||
/* don't add filters forever */
|
||||
if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) {
|
||||
/* free the container */
|
||||
kfree(fsc);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Copy the whole filter over */
|
||||
fsc->fs.flow_type = spec->flow_type;
|
||||
memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u));
|
||||
memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u));
|
||||
|
||||
fsc->fs.vlan_tag = spec->vlan_tag;
|
||||
fsc->fs.vlan_tag_mask = spec->vlan_tag_mask;
|
||||
fsc->fs.data = spec->data;
|
||||
fsc->fs.data_mask = spec->data_mask;
|
||||
fsc->fs.action = spec->action;
|
||||
|
||||
/* add to the list */
|
||||
list_add_tail_rcu(&fsc->list, &list->list);
|
||||
list->count++;
|
||||
}
|
||||
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_set_rx_ntuple(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_rx_ntuple cmd;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
|
||||
int ret;
|
||||
|
||||
if (!(dev->features & NETIF_F_NTUPLE))
|
||||
return -EINVAL;
|
||||
|
||||
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
|
||||
return -EFAULT;
|
||||
|
||||
/*
|
||||
* Cache filter in dev struct for GET operation only if
|
||||
* the underlying driver doesn't have its own GET operation, and
|
||||
* only if the filter was added successfully. First make sure we
|
||||
* can allocate the filter, then continue if successful.
|
||||
*/
|
||||
if (!ops->get_rx_ntuple) {
|
||||
fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC);
|
||||
if (!fsc)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
ret = ops->set_rx_ntuple(dev, &cmd);
|
||||
if (ret) {
|
||||
kfree(fsc);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!ops->get_rx_ntuple)
|
||||
__rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_gstrings gstrings;
|
||||
const struct ethtool_ops *ops = dev->ethtool_ops;
|
||||
struct ethtool_rx_ntuple_flow_spec_container *fsc;
|
||||
u8 *data;
|
||||
char *p;
|
||||
int ret, i, num_strings = 0;
|
||||
|
||||
if (!ops->get_sset_count)
|
||||
return -EOPNOTSUPP;
|
||||
|
||||
if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
|
||||
return -EFAULT;
|
||||
|
||||
ret = ops->get_sset_count(dev, gstrings.string_set);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
gstrings.len = ret;
|
||||
|
||||
data = kmalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
|
||||
if (!data)
|
||||
return -ENOMEM;
|
||||
|
||||
if (ops->get_rx_ntuple) {
|
||||
/* driver-specific filter grab */
|
||||
ret = ops->get_rx_ntuple(dev, gstrings.string_set, data);
|
||||
goto copy;
|
||||
}
|
||||
|
||||
/* default ethtool filter grab */
|
||||
i = 0;
|
||||
p = (char *)data;
|
||||
list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) {
|
||||
sprintf(p, "Filter %d:\n", i);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
|
||||
switch (fsc->fs.flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
sprintf(p, "\tFlow Type: TCP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case UDP_V4_FLOW:
|
||||
sprintf(p, "\tFlow Type: UDP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case SCTP_V4_FLOW:
|
||||
sprintf(p, "\tFlow Type: SCTP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case AH_ESP_V4_FLOW:
|
||||
sprintf(p, "\tFlow Type: AH ESP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case ESP_V4_FLOW:
|
||||
sprintf(p, "\tFlow Type: ESP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case IP_USER_FLOW:
|
||||
sprintf(p, "\tFlow Type: Raw IP\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case IPV4_FLOW:
|
||||
sprintf(p, "\tFlow Type: IPv4\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
default:
|
||||
sprintf(p, "\tFlow Type: Unknown\n");
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
goto unknown_filter;
|
||||
};
|
||||
|
||||
/* now the rest of the filters */
|
||||
switch (fsc->fs.flow_type) {
|
||||
case TCP_V4_FLOW:
|
||||
case UDP_V4_FLOW:
|
||||
case SCTP_V4_FLOW:
|
||||
sprintf(p, "\tSrc IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.tcp_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSrc IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.tcp_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.tcp_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.tcp_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.tcp_ip4_spec.psrc,
|
||||
fsc->fs.m_u.tcp_ip4_spec.psrc);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.tcp_ip4_spec.pdst,
|
||||
fsc->fs.m_u.tcp_ip4_spec.pdst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.tcp_ip4_spec.tos,
|
||||
fsc->fs.m_u.tcp_ip4_spec.tos);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case AH_ESP_V4_FLOW:
|
||||
case ESP_V4_FLOW:
|
||||
sprintf(p, "\tSrc IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.ah_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSrc IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.ah_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.ah_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.ah_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSPI: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.ah_ip4_spec.spi,
|
||||
fsc->fs.m_u.ah_ip4_spec.spi);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.ah_ip4_spec.tos,
|
||||
fsc->fs.m_u.ah_ip4_spec.tos);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case IP_USER_FLOW:
|
||||
sprintf(p, "\tSrc IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.raw_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSrc IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.raw_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.raw_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.raw_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
case IPV4_FLOW:
|
||||
sprintf(p, "\tSrc IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tSrc IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.usr_ip4_spec.ip4src);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP addr: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tDest IP mask: 0x%x\n",
|
||||
fsc->fs.m_u.usr_ip4_spec.ip4dst);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
|
||||
fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tTOS: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.tos,
|
||||
fsc->fs.m_u.usr_ip4_spec.tos);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.ip_ver,
|
||||
fsc->fs.m_u.usr_ip4_spec.ip_ver);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
|
||||
fsc->fs.h_u.usr_ip4_spec.proto,
|
||||
fsc->fs.m_u.usr_ip4_spec.proto);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
break;
|
||||
};
|
||||
sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
|
||||
fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
|
||||
sprintf(p, "\tAction: Drop\n");
|
||||
else
|
||||
sprintf(p, "\tAction: Direct to queue %d\n",
|
||||
fsc->fs.action);
|
||||
p += ETH_GSTRING_LEN;
|
||||
num_strings++;
|
||||
unknown_filter:
|
||||
i++;
|
||||
}
|
||||
copy:
|
||||
/* indicate to userspace how many strings we actually have */
|
||||
gstrings.len = num_strings;
|
||||
ret = -EFAULT;
|
||||
if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
|
||||
goto out;
|
||||
useraddr += sizeof(gstrings);
|
||||
if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
|
||||
goto out;
|
||||
ret = 0;
|
||||
|
||||
out:
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_regs regs;
|
||||
@@ -324,7 +667,7 @@ static int ethtool_reset(struct net_device *dev, char __user *useraddr)
|
||||
|
||||
static int ethtool_get_wol(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_wolinfo wol = { ETHTOOL_GWOL };
|
||||
struct ethtool_wolinfo wol = { .cmd = ETHTOOL_GWOL };
|
||||
|
||||
if (!dev->ethtool_ops->get_wol)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -456,9 +799,12 @@ static int ethtool_set_eeprom(struct net_device *dev, void __user *useraddr)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_coalesce coalesce = { ETHTOOL_GCOALESCE };
|
||||
struct ethtool_coalesce coalesce = { .cmd = ETHTOOL_GCOALESCE };
|
||||
|
||||
if (!dev->ethtool_ops->get_coalesce)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -470,7 +816,10 @@ static int ethtool_get_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_coalesce coalesce;
|
||||
|
||||
@@ -485,7 +834,7 @@ static int ethtool_set_coalesce(struct net_device *dev, void __user *useraddr)
|
||||
|
||||
static int ethtool_get_ringparam(struct net_device *dev, void __user *useraddr)
|
||||
{
|
||||
struct ethtool_ringparam ringparam = { ETHTOOL_GRINGPARAM };
|
||||
struct ethtool_ringparam ringparam = { .cmd = ETHTOOL_GRINGPARAM };
|
||||
|
||||
if (!dev->ethtool_ops->get_ringparam)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -839,7 +1188,7 @@ static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
|
||||
static int ethtool_get_value(struct net_device *dev, char __user *useraddr,
|
||||
u32 cmd, u32 (*actor)(struct net_device *))
|
||||
{
|
||||
struct ethtool_value edata = { cmd };
|
||||
struct ethtool_value edata = { .cmd = cmd };
|
||||
|
||||
if (!actor)
|
||||
return -EOPNOTSUPP;
|
||||
@@ -880,7 +1229,10 @@ static int ethtool_set_value(struct net_device *dev, char __user *useraddr,
|
||||
return actor(dev, edata.data);
|
||||
}
|
||||
|
||||
static int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
|
||||
/*
|
||||
* noinline attribute so that gcc doesnt use too much stack in dev_ethtool()
|
||||
*/
|
||||
static noinline int ethtool_flash_device(struct net_device *dev, char __user *useraddr)
|
||||
{
|
||||
struct ethtool_flash efl;
|
||||
|
||||
@@ -927,6 +1279,7 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
||||
case ETHTOOL_GPERMADDR:
|
||||
case ETHTOOL_GUFO:
|
||||
case ETHTOOL_GGSO:
|
||||
case ETHTOOL_GGRO:
|
||||
case ETHTOOL_GFLAGS:
|
||||
case ETHTOOL_GPFLAGS:
|
||||
case ETHTOOL_GRXFH:
|
||||
@@ -1112,6 +1465,12 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
|
||||
case ETHTOOL_RESET:
|
||||
rc = ethtool_reset(dev, useraddr);
|
||||
break;
|
||||
case ETHTOOL_SRXNTUPLE:
|
||||
rc = ethtool_set_rx_ntuple(dev, useraddr);
|
||||
break;
|
||||
case ETHTOOL_GRXNTUPLE:
|
||||
rc = ethtool_get_rx_ntuple(dev, useraddr);
|
||||
break;
|
||||
default:
|
||||
rc = -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
@@ -708,7 +708,7 @@ static struct notifier_block fib_rules_notifier = {
|
||||
.notifier_call = fib_rules_event,
|
||||
};
|
||||
|
||||
static int fib_rules_net_init(struct net *net)
|
||||
static int __net_init fib_rules_net_init(struct net *net)
|
||||
{
|
||||
INIT_LIST_HEAD(&net->rules_ops);
|
||||
spin_lock_init(&net->rules_mod_lock);
|
||||
|
||||
+5
-3
@@ -86,7 +86,7 @@ int sk_filter(struct sock *sk, struct sk_buff *skb)
|
||||
return err;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
filter = rcu_dereference(sk->sk_filter);
|
||||
filter = rcu_dereference_bh(sk->sk_filter);
|
||||
if (filter) {
|
||||
unsigned int pkt_len = sk_run_filter(skb, filter->insns,
|
||||
filter->len);
|
||||
@@ -521,7 +521,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
|
||||
}
|
||||
|
||||
rcu_read_lock_bh();
|
||||
old_fp = rcu_dereference(sk->sk_filter);
|
||||
old_fp = rcu_dereference_bh(sk->sk_filter);
|
||||
rcu_assign_pointer(sk->sk_filter, fp);
|
||||
rcu_read_unlock_bh();
|
||||
|
||||
@@ -529,6 +529,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
|
||||
sk_filter_delayed_uncharge(sk, old_fp);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sk_attach_filter);
|
||||
|
||||
int sk_detach_filter(struct sock *sk)
|
||||
{
|
||||
@@ -536,7 +537,7 @@ int sk_detach_filter(struct sock *sk)
|
||||
struct sk_filter *filter;
|
||||
|
||||
rcu_read_lock_bh();
|
||||
filter = rcu_dereference(sk->sk_filter);
|
||||
filter = rcu_dereference_bh(sk->sk_filter);
|
||||
if (filter) {
|
||||
rcu_assign_pointer(sk->sk_filter, NULL);
|
||||
sk_filter_delayed_uncharge(sk, filter);
|
||||
@@ -545,3 +546,4 @@ int sk_detach_filter(struct sock *sk)
|
||||
rcu_read_unlock_bh();
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sk_detach_filter);
|
||||
|
||||
+8
-10
@@ -2417,8 +2417,7 @@ EXPORT_SYMBOL(neigh_seq_stop);
|
||||
|
||||
static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
{
|
||||
struct proc_dir_entry *pde = seq->private;
|
||||
struct neigh_table *tbl = pde->data;
|
||||
struct neigh_table *tbl = seq->private;
|
||||
int cpu;
|
||||
|
||||
if (*pos == 0)
|
||||
@@ -2435,8 +2434,7 @@ static void *neigh_stat_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
|
||||
static void *neigh_stat_seq_next(struct seq_file *seq, void *v, loff_t *pos)
|
||||
{
|
||||
struct proc_dir_entry *pde = seq->private;
|
||||
struct neigh_table *tbl = pde->data;
|
||||
struct neigh_table *tbl = seq->private;
|
||||
int cpu;
|
||||
|
||||
for (cpu = *pos; cpu < nr_cpu_ids; ++cpu) {
|
||||
@@ -2455,8 +2453,7 @@ static void neigh_stat_seq_stop(struct seq_file *seq, void *v)
|
||||
|
||||
static int neigh_stat_seq_show(struct seq_file *seq, void *v)
|
||||
{
|
||||
struct proc_dir_entry *pde = seq->private;
|
||||
struct neigh_table *tbl = pde->data;
|
||||
struct neigh_table *tbl = seq->private;
|
||||
struct neigh_statistics *st = v;
|
||||
|
||||
if (v == SEQ_START_TOKEN) {
|
||||
@@ -2501,7 +2498,7 @@ static int neigh_stat_seq_open(struct inode *inode, struct file *file)
|
||||
|
||||
if (!ret) {
|
||||
struct seq_file *sf = file->private_data;
|
||||
sf->private = PDE(inode);
|
||||
sf->private = PDE(inode)->data;
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
@@ -2559,9 +2556,11 @@ EXPORT_SYMBOL(neigh_app_ns);
|
||||
|
||||
#ifdef CONFIG_SYSCTL
|
||||
|
||||
#define NEIGH_VARS_MAX 19
|
||||
|
||||
static struct neigh_sysctl_table {
|
||||
struct ctl_table_header *sysctl_header;
|
||||
struct ctl_table neigh_vars[__NET_NEIGH_MAX];
|
||||
struct ctl_table neigh_vars[NEIGH_VARS_MAX];
|
||||
char *dev_name;
|
||||
} neigh_sysctl_template __read_mostly = {
|
||||
.neigh_vars = {
|
||||
@@ -2678,8 +2677,7 @@ static struct neigh_sysctl_table {
|
||||
};
|
||||
|
||||
int neigh_sysctl_register(struct net_device *dev, struct neigh_parms *p,
|
||||
int p_id, int pdev_id, char *p_name,
|
||||
proc_handler *handler)
|
||||
char *p_name, proc_handler *handler)
|
||||
{
|
||||
struct neigh_sysctl_table *t;
|
||||
const char *dev_name_source = NULL;
|
||||
|
||||
@@ -410,7 +410,8 @@ static ssize_t wireless_show(struct device *d, char *buf,
|
||||
const struct iw_statistics *iw;
|
||||
ssize_t ret = -EINVAL;
|
||||
|
||||
rtnl_lock();
|
||||
if (!rtnl_trylock())
|
||||
return restart_syscall();
|
||||
if (dev_isalive(dev)) {
|
||||
iw = get_wireless_stats(dev);
|
||||
if (iw)
|
||||
|
||||
+108
-65
@@ -407,11 +407,24 @@ static void arp_reply(struct sk_buff *skb)
|
||||
__be32 sip, tip;
|
||||
unsigned char *sha;
|
||||
struct sk_buff *send_skb;
|
||||
struct netpoll *np = NULL;
|
||||
struct netpoll *np, *tmp;
|
||||
unsigned long flags;
|
||||
int hits = 0;
|
||||
|
||||
if (npinfo->rx_np && npinfo->rx_np->dev == skb->dev)
|
||||
np = npinfo->rx_np;
|
||||
if (!np)
|
||||
if (list_empty(&npinfo->rx_np))
|
||||
return;
|
||||
|
||||
/* Before checking the packet, we do some early
|
||||
inspection whether this is interesting at all */
|
||||
spin_lock_irqsave(&npinfo->rx_lock, flags);
|
||||
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
|
||||
if (np->dev == skb->dev)
|
||||
hits++;
|
||||
}
|
||||
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
|
||||
|
||||
/* No netpoll struct is using this dev */
|
||||
if (!hits)
|
||||
return;
|
||||
|
||||
/* No arp on this interface */
|
||||
@@ -437,77 +450,91 @@ static void arp_reply(struct sk_buff *skb)
|
||||
arp_ptr += skb->dev->addr_len;
|
||||
memcpy(&sip, arp_ptr, 4);
|
||||
arp_ptr += 4;
|
||||
/* if we actually cared about dst hw addr, it would get copied here */
|
||||
/* 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? */
|
||||
if (tip != np->local_ip ||
|
||||
ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
|
||||
if (ipv4_is_loopback(tip) || ipv4_is_multicast(tip))
|
||||
return;
|
||||
|
||||
size = arp_hdr_len(skb->dev);
|
||||
send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
|
||||
LL_RESERVED_SPACE(np->dev));
|
||||
|
||||
if (!send_skb)
|
||||
return;
|
||||
spin_lock_irqsave(&npinfo->rx_lock, flags);
|
||||
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
|
||||
if (tip != np->local_ip)
|
||||
continue;
|
||||
|
||||
skb_reset_network_header(send_skb);
|
||||
arp = (struct arphdr *) skb_put(send_skb, size);
|
||||
send_skb->dev = skb->dev;
|
||||
send_skb->protocol = htons(ETH_P_ARP);
|
||||
send_skb = find_skb(np, size + LL_ALLOCATED_SPACE(np->dev),
|
||||
LL_RESERVED_SPACE(np->dev));
|
||||
if (!send_skb)
|
||||
continue;
|
||||
|
||||
/* Fill the device header for the ARP frame */
|
||||
if (dev_hard_header(send_skb, skb->dev, ptype,
|
||||
sha, np->dev->dev_addr,
|
||||
send_skb->len) < 0) {
|
||||
kfree_skb(send_skb);
|
||||
return;
|
||||
skb_reset_network_header(send_skb);
|
||||
arp = (struct arphdr *) skb_put(send_skb, size);
|
||||
send_skb->dev = skb->dev;
|
||||
send_skb->protocol = htons(ETH_P_ARP);
|
||||
|
||||
/* Fill the device header for the ARP frame */
|
||||
if (dev_hard_header(send_skb, skb->dev, ptype,
|
||||
sha, np->dev->dev_addr,
|
||||
send_skb->len) < 0) {
|
||||
kfree_skb(send_skb);
|
||||
continue;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill out the arp protocol part.
|
||||
*
|
||||
* we only support ethernet device type,
|
||||
* which (according to RFC 1390) should
|
||||
* always equal 1 (Ethernet).
|
||||
*/
|
||||
|
||||
arp->ar_hrd = htons(np->dev->type);
|
||||
arp->ar_pro = htons(ETH_P_IP);
|
||||
arp->ar_hln = np->dev->addr_len;
|
||||
arp->ar_pln = 4;
|
||||
arp->ar_op = htons(type);
|
||||
|
||||
arp_ptr = (unsigned char *)(arp + 1);
|
||||
memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
|
||||
arp_ptr += np->dev->addr_len;
|
||||
memcpy(arp_ptr, &tip, 4);
|
||||
arp_ptr += 4;
|
||||
memcpy(arp_ptr, sha, np->dev->addr_len);
|
||||
arp_ptr += np->dev->addr_len;
|
||||
memcpy(arp_ptr, &sip, 4);
|
||||
|
||||
netpoll_send_skb(np, send_skb);
|
||||
|
||||
/* If there are several rx_hooks for the same address,
|
||||
we're fine by sending a single reply */
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Fill out the arp protocol part.
|
||||
*
|
||||
* we only support ethernet device type,
|
||||
* which (according to RFC 1390) should always equal 1 (Ethernet).
|
||||
*/
|
||||
|
||||
arp->ar_hrd = htons(np->dev->type);
|
||||
arp->ar_pro = htons(ETH_P_IP);
|
||||
arp->ar_hln = np->dev->addr_len;
|
||||
arp->ar_pln = 4;
|
||||
arp->ar_op = htons(type);
|
||||
|
||||
arp_ptr=(unsigned char *)(arp + 1);
|
||||
memcpy(arp_ptr, np->dev->dev_addr, np->dev->addr_len);
|
||||
arp_ptr += np->dev->addr_len;
|
||||
memcpy(arp_ptr, &tip, 4);
|
||||
arp_ptr += 4;
|
||||
memcpy(arp_ptr, sha, np->dev->addr_len);
|
||||
arp_ptr += np->dev->addr_len;
|
||||
memcpy(arp_ptr, &sip, 4);
|
||||
|
||||
netpoll_send_skb(np, send_skb);
|
||||
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
|
||||
}
|
||||
|
||||
int __netpoll_rx(struct sk_buff *skb)
|
||||
{
|
||||
int proto, len, ulen;
|
||||
int hits = 0;
|
||||
struct iphdr *iph;
|
||||
struct udphdr *uh;
|
||||
struct netpoll_info *npi = skb->dev->npinfo;
|
||||
struct netpoll *np = npi->rx_np;
|
||||
struct netpoll_info *npinfo = skb->dev->npinfo;
|
||||
struct netpoll *np, *tmp;
|
||||
|
||||
if (!np)
|
||||
if (list_empty(&npinfo->rx_np))
|
||||
goto out;
|
||||
|
||||
if (skb->dev->type != ARPHRD_ETHER)
|
||||
goto out;
|
||||
|
||||
/* check if netpoll clients need ARP */
|
||||
if (skb->protocol == htons(ETH_P_ARP) &&
|
||||
atomic_read(&trapped)) {
|
||||
skb_queue_tail(&npi->arp_tx, skb);
|
||||
skb_queue_tail(&npinfo->arp_tx, skb);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -551,16 +578,23 @@ int __netpoll_rx(struct sk_buff *skb)
|
||||
goto out;
|
||||
if (checksum_udp(skb, uh, ulen, iph->saddr, iph->daddr))
|
||||
goto out;
|
||||
if (np->local_ip && np->local_ip != iph->daddr)
|
||||
goto out;
|
||||
if (np->remote_ip && np->remote_ip != iph->saddr)
|
||||
goto out;
|
||||
if (np->local_port && np->local_port != ntohs(uh->dest))
|
||||
goto out;
|
||||
|
||||
np->rx_hook(np, ntohs(uh->source),
|
||||
(char *)(uh+1),
|
||||
ulen - sizeof(struct udphdr));
|
||||
list_for_each_entry_safe(np, tmp, &npinfo->rx_np, rx) {
|
||||
if (np->local_ip && np->local_ip != iph->daddr)
|
||||
continue;
|
||||
if (np->remote_ip && np->remote_ip != iph->saddr)
|
||||
continue;
|
||||
if (np->local_port && np->local_port != ntohs(uh->dest))
|
||||
continue;
|
||||
|
||||
np->rx_hook(np, ntohs(uh->source),
|
||||
(char *)(uh+1),
|
||||
ulen - sizeof(struct udphdr));
|
||||
hits++;
|
||||
}
|
||||
|
||||
if (!hits)
|
||||
goto out;
|
||||
|
||||
kfree_skb(skb);
|
||||
return 1;
|
||||
@@ -684,6 +718,7 @@ int netpoll_setup(struct netpoll *np)
|
||||
struct net_device *ndev = NULL;
|
||||
struct in_device *in_dev;
|
||||
struct netpoll_info *npinfo;
|
||||
struct netpoll *npe, *tmp;
|
||||
unsigned long flags;
|
||||
int err;
|
||||
|
||||
@@ -704,7 +739,7 @@ int netpoll_setup(struct netpoll *np)
|
||||
}
|
||||
|
||||
npinfo->rx_flags = 0;
|
||||
npinfo->rx_np = NULL;
|
||||
INIT_LIST_HEAD(&npinfo->rx_np);
|
||||
|
||||
spin_lock_init(&npinfo->rx_lock);
|
||||
skb_queue_head_init(&npinfo->arp_tx);
|
||||
@@ -785,7 +820,7 @@ int netpoll_setup(struct netpoll *np)
|
||||
if (np->rx_hook) {
|
||||
spin_lock_irqsave(&npinfo->rx_lock, flags);
|
||||
npinfo->rx_flags |= NETPOLL_RX_ENABLED;
|
||||
npinfo->rx_np = np;
|
||||
list_add_tail(&np->rx, &npinfo->rx_np);
|
||||
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
|
||||
}
|
||||
|
||||
@@ -801,9 +836,16 @@ int netpoll_setup(struct netpoll *np)
|
||||
return 0;
|
||||
|
||||
release:
|
||||
if (!ndev->npinfo)
|
||||
if (!ndev->npinfo) {
|
||||
spin_lock_irqsave(&npinfo->rx_lock, flags);
|
||||
list_for_each_entry_safe(npe, tmp, &npinfo->rx_np, rx) {
|
||||
npe->dev = NULL;
|
||||
}
|
||||
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
|
||||
|
||||
kfree(npinfo);
|
||||
np->dev = NULL;
|
||||
}
|
||||
|
||||
dev_put(ndev);
|
||||
return err;
|
||||
}
|
||||
@@ -823,10 +865,11 @@ void netpoll_cleanup(struct netpoll *np)
|
||||
if (np->dev) {
|
||||
npinfo = np->dev->npinfo;
|
||||
if (npinfo) {
|
||||
if (npinfo->rx_np == np) {
|
||||
if (!list_empty(&npinfo->rx_np)) {
|
||||
spin_lock_irqsave(&npinfo->rx_lock, flags);
|
||||
npinfo->rx_np = NULL;
|
||||
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
|
||||
list_del(&np->rx);
|
||||
if (list_empty(&npinfo->rx_np))
|
||||
npinfo->rx_flags &= ~NETPOLL_RX_ENABLED;
|
||||
spin_unlock_irqrestore(&npinfo->rx_lock, flags);
|
||||
}
|
||||
|
||||
|
||||
+3
-1
@@ -2188,12 +2188,13 @@ static inline int f_pick(struct pktgen_dev *pkt_dev)
|
||||
/* If there was already an IPSEC SA, we keep it as is, else
|
||||
* we go look for it ...
|
||||
*/
|
||||
#define DUMMY_MARK 0
|
||||
static void get_ipsec_sa(struct pktgen_dev *pkt_dev, int flow)
|
||||
{
|
||||
struct xfrm_state *x = pkt_dev->flows[flow].x;
|
||||
if (!x) {
|
||||
/*slow path: we dont already have xfrm_state*/
|
||||
x = xfrm_stateonly_find(&init_net,
|
||||
x = xfrm_stateonly_find(&init_net, DUMMY_MARK,
|
||||
(xfrm_address_t *)&pkt_dev->cur_daddr,
|
||||
(xfrm_address_t *)&pkt_dev->cur_saddr,
|
||||
AF_INET,
|
||||
@@ -3524,6 +3525,7 @@ static int pktgen_thread_worker(void *arg)
|
||||
wait_event_interruptible_timeout(t->queue,
|
||||
t->control != 0,
|
||||
HZ/10);
|
||||
try_to_freeze();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
+119
-16
@@ -35,6 +35,7 @@
|
||||
#include <linux/security.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/if_addr.h>
|
||||
#include <linux/pci.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
#include <asm/system.h>
|
||||
@@ -89,6 +90,14 @@ int rtnl_is_locked(void)
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_is_locked);
|
||||
|
||||
#ifdef CONFIG_PROVE_LOCKING
|
||||
int lockdep_rtnl_is_held(void)
|
||||
{
|
||||
return lockdep_is_held(&rtnl_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL(lockdep_rtnl_is_held);
|
||||
#endif /* #ifdef CONFIG_PROVE_LOCKING */
|
||||
|
||||
static struct rtnl_link *rtnl_msg_handlers[NPROTO];
|
||||
|
||||
static inline int rtm_msgindex(int msgtype)
|
||||
@@ -548,6 +557,19 @@ static void set_operstate(struct net_device *dev, unsigned char transition)
|
||||
}
|
||||
}
|
||||
|
||||
static unsigned int rtnl_dev_combine_flags(const struct net_device *dev,
|
||||
const struct ifinfomsg *ifm)
|
||||
{
|
||||
unsigned int flags = ifm->ifi_flags;
|
||||
|
||||
/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
|
||||
if (ifm->ifi_change)
|
||||
flags = (flags & ifm->ifi_change) |
|
||||
(dev->flags & ~ifm->ifi_change);
|
||||
|
||||
return flags;
|
||||
}
|
||||
|
||||
static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
|
||||
const struct net_device_stats *b)
|
||||
{
|
||||
@@ -580,6 +602,15 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
|
||||
a->tx_compressed = b->tx_compressed;
|
||||
};
|
||||
|
||||
static inline int rtnl_vfinfo_size(const struct net_device *dev)
|
||||
{
|
||||
if (dev->dev.parent && dev_is_pci(dev->dev.parent))
|
||||
return dev_num_vf(dev->dev.parent) *
|
||||
sizeof(struct ifla_vf_info);
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline size_t if_nlmsg_size(const struct net_device *dev)
|
||||
{
|
||||
return NLMSG_ALIGN(sizeof(struct ifinfomsg))
|
||||
@@ -597,6 +628,8 @@ static inline size_t if_nlmsg_size(const struct net_device *dev)
|
||||
+ nla_total_size(4) /* IFLA_MASTER */
|
||||
+ nla_total_size(1) /* IFLA_OPERSTATE */
|
||||
+ nla_total_size(1) /* IFLA_LINKMODE */
|
||||
+ nla_total_size(4) /* IFLA_NUM_VF */
|
||||
+ nla_total_size(rtnl_vfinfo_size(dev)) /* IFLA_VFINFO */
|
||||
+ rtnl_link_get_size(dev); /* IFLA_LINKINFO */
|
||||
}
|
||||
|
||||
@@ -665,6 +698,17 @@ static int rtnl_fill_ifinfo(struct sk_buff *skb, struct net_device *dev,
|
||||
stats = dev_get_stats(dev);
|
||||
copy_rtnl_link_stats(nla_data(attr), stats);
|
||||
|
||||
if (dev->netdev_ops->ndo_get_vf_config && dev->dev.parent) {
|
||||
int i;
|
||||
struct ifla_vf_info ivi;
|
||||
|
||||
NLA_PUT_U32(skb, IFLA_NUM_VF, dev_num_vf(dev->dev.parent));
|
||||
for (i = 0; i < dev_num_vf(dev->dev.parent); i++) {
|
||||
if (dev->netdev_ops->ndo_get_vf_config(dev, i, &ivi))
|
||||
break;
|
||||
NLA_PUT(skb, IFLA_VFINFO, sizeof(ivi), &ivi);
|
||||
}
|
||||
}
|
||||
if (dev->rtnl_link_ops) {
|
||||
if (rtnl_link_fill(skb, dev) < 0)
|
||||
goto nla_put_failure;
|
||||
@@ -725,6 +769,12 @@ const struct nla_policy ifla_policy[IFLA_MAX+1] = {
|
||||
[IFLA_LINKINFO] = { .type = NLA_NESTED },
|
||||
[IFLA_NET_NS_PID] = { .type = NLA_U32 },
|
||||
[IFLA_IFALIAS] = { .type = NLA_STRING, .len = IFALIASZ-1 },
|
||||
[IFLA_VF_MAC] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_mac) },
|
||||
[IFLA_VF_VLAN] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_vlan) },
|
||||
[IFLA_VF_TX_RATE] = { .type = NLA_BINARY,
|
||||
.len = sizeof(struct ifla_vf_tx_rate) },
|
||||
};
|
||||
EXPORT_SYMBOL(ifla_policy);
|
||||
|
||||
@@ -875,13 +925,7 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
||||
}
|
||||
|
||||
if (ifm->ifi_flags || ifm->ifi_change) {
|
||||
unsigned int flags = ifm->ifi_flags;
|
||||
|
||||
/* bugwards compatibility: ifi_change == 0 is treated as ~0 */
|
||||
if (ifm->ifi_change)
|
||||
flags = (flags & ifm->ifi_change) |
|
||||
(dev->flags & ~ifm->ifi_change);
|
||||
err = dev_change_flags(dev, flags);
|
||||
err = dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm));
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
}
|
||||
@@ -898,6 +942,41 @@ static int do_setlink(struct net_device *dev, struct ifinfomsg *ifm,
|
||||
write_unlock_bh(&dev_base_lock);
|
||||
}
|
||||
|
||||
if (tb[IFLA_VF_MAC]) {
|
||||
struct ifla_vf_mac *ivm;
|
||||
ivm = nla_data(tb[IFLA_VF_MAC]);
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_mac)
|
||||
err = ops->ndo_set_vf_mac(dev, ivm->vf, ivm->mac);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
modified = 1;
|
||||
}
|
||||
|
||||
if (tb[IFLA_VF_VLAN]) {
|
||||
struct ifla_vf_vlan *ivv;
|
||||
ivv = nla_data(tb[IFLA_VF_VLAN]);
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_vlan)
|
||||
err = ops->ndo_set_vf_vlan(dev, ivv->vf,
|
||||
ivv->vlan,
|
||||
ivv->qos);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
modified = 1;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
if (tb[IFLA_VF_TX_RATE]) {
|
||||
struct ifla_vf_tx_rate *ivt;
|
||||
ivt = nla_data(tb[IFLA_VF_TX_RATE]);
|
||||
err = -EOPNOTSUPP;
|
||||
if (ops->ndo_set_vf_tx_rate)
|
||||
err = ops->ndo_set_vf_tx_rate(dev, ivt->vf, ivt->rate);
|
||||
if (err < 0)
|
||||
goto errout;
|
||||
modified = 1;
|
||||
}
|
||||
err = 0;
|
||||
|
||||
errout:
|
||||
@@ -989,6 +1068,26 @@ static int rtnl_dellink(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
|
||||
return 0;
|
||||
}
|
||||
|
||||
int rtnl_configure_link(struct net_device *dev, const struct ifinfomsg *ifm)
|
||||
{
|
||||
unsigned int old_flags;
|
||||
int err;
|
||||
|
||||
old_flags = dev->flags;
|
||||
if (ifm && (ifm->ifi_flags || ifm->ifi_change)) {
|
||||
err = __dev_change_flags(dev, rtnl_dev_combine_flags(dev, ifm));
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
dev->rtnl_link_state = RTNL_LINK_INITIALIZED;
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, ~0U);
|
||||
|
||||
__dev_notify_flags(dev, old_flags);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(rtnl_configure_link);
|
||||
|
||||
struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
|
||||
char *ifname, const struct rtnl_link_ops *ops, struct nlattr *tb[])
|
||||
{
|
||||
@@ -1010,6 +1109,7 @@ struct net_device *rtnl_create_link(struct net *src_net, struct net *net,
|
||||
|
||||
dev_net_set(dev, net);
|
||||
dev->rtnl_link_ops = ops;
|
||||
dev->rtnl_link_state = RTNL_LINK_INITIALIZING;
|
||||
dev->real_num_tx_queues = real_num_queues;
|
||||
|
||||
if (strchr(dev->name, '%')) {
|
||||
@@ -1139,7 +1239,7 @@ replay:
|
||||
if (!(nlh->nlmsg_flags & NLM_F_CREATE))
|
||||
return -ENODEV;
|
||||
|
||||
if (ifm->ifi_index || ifm->ifi_flags || ifm->ifi_change)
|
||||
if (ifm->ifi_index)
|
||||
return -EOPNOTSUPP;
|
||||
if (tb[IFLA_MAP] || tb[IFLA_MASTER] || tb[IFLA_PROTINFO])
|
||||
return -EOPNOTSUPP;
|
||||
@@ -1170,9 +1270,15 @@ replay:
|
||||
err = ops->newlink(net, dev, tb, data);
|
||||
else
|
||||
err = register_netdevice(dev);
|
||||
if (err < 0 && !IS_ERR(dev))
|
||||
if (err < 0 && !IS_ERR(dev)) {
|
||||
free_netdev(dev);
|
||||
goto out;
|
||||
}
|
||||
|
||||
err = rtnl_configure_link(dev, ifm);
|
||||
if (err < 0)
|
||||
unregister_netdevice(dev);
|
||||
out:
|
||||
put_net(dest_net);
|
||||
return err;
|
||||
}
|
||||
@@ -1361,17 +1467,14 @@ static int rtnetlink_event(struct notifier_block *this, unsigned long event, voi
|
||||
struct net_device *dev = ptr;
|
||||
|
||||
switch (event) {
|
||||
case NETDEV_UNREGISTER:
|
||||
rtmsg_ifinfo(RTM_DELLINK, dev, ~0U);
|
||||
break;
|
||||
case NETDEV_UP:
|
||||
case NETDEV_DOWN:
|
||||
rtmsg_ifinfo(RTM_NEWLINK, dev, IFF_UP|IFF_RUNNING);
|
||||
break;
|
||||
case NETDEV_PRE_UP:
|
||||
case NETDEV_POST_INIT:
|
||||
case NETDEV_REGISTER:
|
||||
case NETDEV_CHANGE:
|
||||
case NETDEV_GOING_DOWN:
|
||||
case NETDEV_UNREGISTER:
|
||||
case NETDEV_UNREGISTER_BATCH:
|
||||
break;
|
||||
default:
|
||||
@@ -1386,7 +1489,7 @@ static struct notifier_block rtnetlink_dev_notifier = {
|
||||
};
|
||||
|
||||
|
||||
static int rtnetlink_net_init(struct net *net)
|
||||
static int __net_init rtnetlink_net_init(struct net *net)
|
||||
{
|
||||
struct sock *sk;
|
||||
sk = netlink_kernel_create(net, NETLINK_ROUTE, RTNLGRP_MAX,
|
||||
@@ -1397,7 +1500,7 @@ static int rtnetlink_net_init(struct net *net)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rtnetlink_net_exit(struct net *net)
|
||||
static void __net_exit rtnetlink_net_exit(struct net *net)
|
||||
{
|
||||
netlink_kernel_release(net->rtnl);
|
||||
net->rtnl = NULL;
|
||||
|
||||
@@ -156,6 +156,8 @@ int __scm_send(struct socket *sock, struct msghdr *msg, struct scm_cookie *p)
|
||||
switch (cmsg->cmsg_type)
|
||||
{
|
||||
case SCM_RIGHTS:
|
||||
if (!sock->ops || sock->ops->family != PF_UNIX)
|
||||
goto error;
|
||||
err=scm_fp_copy(cmsg, &p->fp);
|
||||
if (err<0)
|
||||
goto error;
|
||||
|
||||
+7
-12
@@ -741,7 +741,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
|
||||
struct timeval tm;
|
||||
} v;
|
||||
|
||||
unsigned int lv = sizeof(int);
|
||||
int lv = sizeof(int);
|
||||
int len;
|
||||
|
||||
if (get_user(len, optlen))
|
||||
@@ -1073,7 +1073,8 @@ static void __sk_free(struct sock *sk)
|
||||
if (sk->sk_destruct)
|
||||
sk->sk_destruct(sk);
|
||||
|
||||
filter = rcu_dereference(sk->sk_filter);
|
||||
filter = rcu_dereference_check(sk->sk_filter,
|
||||
atomic_read(&sk->sk_wmem_alloc) == 0);
|
||||
if (filter) {
|
||||
sk_filter_uncharge(sk, filter);
|
||||
rcu_assign_pointer(sk->sk_filter, NULL);
|
||||
@@ -2140,13 +2141,13 @@ int sock_prot_inuse_get(struct net *net, struct proto *prot)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sock_prot_inuse_get);
|
||||
|
||||
static int sock_inuse_init_net(struct net *net)
|
||||
static int __net_init sock_inuse_init_net(struct net *net)
|
||||
{
|
||||
net->core.inuse = alloc_percpu(struct prot_inuse);
|
||||
return net->core.inuse ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static void sock_inuse_exit_net(struct net *net)
|
||||
static void __net_exit sock_inuse_exit_net(struct net *net)
|
||||
{
|
||||
free_percpu(net->core.inuse);
|
||||
}
|
||||
@@ -2228,13 +2229,10 @@ int proto_register(struct proto *prot, int alloc_slab)
|
||||
}
|
||||
|
||||
if (prot->rsk_prot != NULL) {
|
||||
static const char mask[] = "request_sock_%s";
|
||||
|
||||
prot->rsk_prot->slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL);
|
||||
prot->rsk_prot->slab_name = kasprintf(GFP_KERNEL, "request_sock_%s", prot->name);
|
||||
if (prot->rsk_prot->slab_name == NULL)
|
||||
goto out_free_sock_slab;
|
||||
|
||||
sprintf(prot->rsk_prot->slab_name, mask, prot->name);
|
||||
prot->rsk_prot->slab = kmem_cache_create(prot->rsk_prot->slab_name,
|
||||
prot->rsk_prot->obj_size, 0,
|
||||
SLAB_HWCACHE_ALIGN, NULL);
|
||||
@@ -2247,14 +2245,11 @@ int proto_register(struct proto *prot, int alloc_slab)
|
||||
}
|
||||
|
||||
if (prot->twsk_prot != NULL) {
|
||||
static const char mask[] = "tw_sock_%s";
|
||||
|
||||
prot->twsk_prot->twsk_slab_name = kmalloc(strlen(prot->name) + sizeof(mask) - 1, GFP_KERNEL);
|
||||
prot->twsk_prot->twsk_slab_name = kasprintf(GFP_KERNEL, "tw_sock_%s", prot->name);
|
||||
|
||||
if (prot->twsk_prot->twsk_slab_name == NULL)
|
||||
goto out_free_request_sock_slab;
|
||||
|
||||
sprintf(prot->twsk_prot->twsk_slab_name, mask, prot->name);
|
||||
prot->twsk_prot->twsk_slab =
|
||||
kmem_cache_create(prot->twsk_prot->twsk_slab_name,
|
||||
prot->twsk_prot->twsk_obj_size,
|
||||
|
||||
+8
-8
@@ -54,7 +54,7 @@ MODULE_LICENSE("GPL");
|
||||
/**************** DCB attribute policies *************************************/
|
||||
|
||||
/* DCB netlink attributes policy */
|
||||
static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
|
||||
[DCB_ATTR_IFNAME] = {.type = NLA_NUL_STRING, .len = IFNAMSIZ - 1},
|
||||
[DCB_ATTR_STATE] = {.type = NLA_U8},
|
||||
[DCB_ATTR_PFC_CFG] = {.type = NLA_NESTED},
|
||||
@@ -68,7 +68,7 @@ static struct nla_policy dcbnl_rtnl_policy[DCB_ATTR_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB priority flow control to User Priority nested attributes */
|
||||
static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
|
||||
[DCB_PFC_UP_ATTR_0] = {.type = NLA_U8},
|
||||
[DCB_PFC_UP_ATTR_1] = {.type = NLA_U8},
|
||||
[DCB_PFC_UP_ATTR_2] = {.type = NLA_U8},
|
||||
@@ -81,7 +81,7 @@ static struct nla_policy dcbnl_pfc_up_nest[DCB_PFC_UP_ATTR_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB priority grouping nested attributes */
|
||||
static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
|
||||
[DCB_PG_ATTR_TC_0] = {.type = NLA_NESTED},
|
||||
[DCB_PG_ATTR_TC_1] = {.type = NLA_NESTED},
|
||||
[DCB_PG_ATTR_TC_2] = {.type = NLA_NESTED},
|
||||
@@ -103,7 +103,7 @@ static struct nla_policy dcbnl_pg_nest[DCB_PG_ATTR_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB traffic class nested attributes. */
|
||||
static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
|
||||
[DCB_TC_ATTR_PARAM_PGID] = {.type = NLA_U8},
|
||||
[DCB_TC_ATTR_PARAM_UP_MAPPING] = {.type = NLA_U8},
|
||||
[DCB_TC_ATTR_PARAM_STRICT_PRIO] = {.type = NLA_U8},
|
||||
@@ -112,7 +112,7 @@ static struct nla_policy dcbnl_tc_param_nest[DCB_TC_ATTR_PARAM_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB capabilities nested attributes. */
|
||||
static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
|
||||
[DCB_CAP_ATTR_ALL] = {.type = NLA_FLAG},
|
||||
[DCB_CAP_ATTR_PG] = {.type = NLA_U8},
|
||||
[DCB_CAP_ATTR_PFC] = {.type = NLA_U8},
|
||||
@@ -124,14 +124,14 @@ static struct nla_policy dcbnl_cap_nest[DCB_CAP_ATTR_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB capabilities nested attributes. */
|
||||
static struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_numtcs_nest[DCB_NUMTCS_ATTR_MAX + 1] = {
|
||||
[DCB_NUMTCS_ATTR_ALL] = {.type = NLA_FLAG},
|
||||
[DCB_NUMTCS_ATTR_PG] = {.type = NLA_U8},
|
||||
[DCB_NUMTCS_ATTR_PFC] = {.type = NLA_U8},
|
||||
};
|
||||
|
||||
/* DCB BCN nested attributes. */
|
||||
static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
|
||||
[DCB_BCN_ATTR_RP_0] = {.type = NLA_U8},
|
||||
[DCB_BCN_ATTR_RP_1] = {.type = NLA_U8},
|
||||
[DCB_BCN_ATTR_RP_2] = {.type = NLA_U8},
|
||||
@@ -160,7 +160,7 @@ static struct nla_policy dcbnl_bcn_nest[DCB_BCN_ATTR_MAX + 1] = {
|
||||
};
|
||||
|
||||
/* DCB APP nested attributes. */
|
||||
static struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
|
||||
static const struct nla_policy dcbnl_app_nest[DCB_APP_ATTR_MAX + 1] = {
|
||||
[DCB_APP_ATTR_IDTYPE] = {.type = NLA_U8},
|
||||
[DCB_APP_ATTR_ID] = {.type = NLA_U16},
|
||||
[DCB_APP_ATTR_PRIORITY] = {.type = NLA_U8},
|
||||
|
||||
+5
-6
@@ -63,14 +63,13 @@ int ccid_getsockopt_builtin_ccids(struct sock *sk, int len,
|
||||
u8 *ccid_array, array_len;
|
||||
int err = 0;
|
||||
|
||||
if (len < ARRAY_SIZE(ccids))
|
||||
return -EINVAL;
|
||||
|
||||
if (ccid_get_builtin_ccids(&ccid_array, &array_len))
|
||||
return -ENOBUFS;
|
||||
|
||||
if (put_user(array_len, optlen) ||
|
||||
copy_to_user(optval, ccid_array, array_len))
|
||||
if (put_user(array_len, optlen))
|
||||
err = -EFAULT;
|
||||
else if (len > 0 && copy_to_user(optval, ccid_array,
|
||||
len > array_len ? array_len : len))
|
||||
err = -EFAULT;
|
||||
|
||||
kfree(ccid_array);
|
||||
@@ -83,7 +82,7 @@ static struct kmem_cache *ccid_kmem_cache_create(int obj_size, char *slab_name_f
|
||||
va_list args;
|
||||
|
||||
va_start(args, fmt);
|
||||
vsnprintf(slab_name_fmt, sizeof(slab_name_fmt), fmt, args);
|
||||
vsnprintf(slab_name_fmt, CCID_SLAB_NAME_LENGTH, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
slab = kmem_cache_create(slab_name_fmt, sizeof(struct ccid) + obj_size, 0,
|
||||
|
||||
+5
-3
@@ -19,7 +19,9 @@
|
||||
#include <linux/list.h>
|
||||
#include <linux/module.h>
|
||||
|
||||
#define CCID_MAX 255
|
||||
/* maximum value for a CCID (RFC 4340, 19.5) */
|
||||
#define CCID_MAX 255
|
||||
#define CCID_SLAB_NAME_LENGTH 32
|
||||
|
||||
struct tcp_info;
|
||||
|
||||
@@ -49,8 +51,8 @@ struct ccid_operations {
|
||||
const char *ccid_name;
|
||||
struct kmem_cache *ccid_hc_rx_slab,
|
||||
*ccid_hc_tx_slab;
|
||||
char ccid_hc_rx_slab_name[32];
|
||||
char ccid_hc_tx_slab_name[32];
|
||||
char ccid_hc_rx_slab_name[CCID_SLAB_NAME_LENGTH];
|
||||
char ccid_hc_tx_slab_name[CCID_SLAB_NAME_LENGTH];
|
||||
__u32 ccid_hc_rx_obj_size,
|
||||
ccid_hc_tx_obj_size;
|
||||
/* Interface Routines */
|
||||
|
||||
+2
-2
@@ -996,7 +996,7 @@ static struct inet_protosw dccp_v4_protosw = {
|
||||
.flags = INET_PROTOSW_ICSK,
|
||||
};
|
||||
|
||||
static int dccp_v4_init_net(struct net *net)
|
||||
static int __net_init dccp_v4_init_net(struct net *net)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ static int dccp_v4_init_net(struct net *net)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dccp_v4_exit_net(struct net *net)
|
||||
static void __net_exit dccp_v4_exit_net(struct net *net)
|
||||
{
|
||||
inet_ctl_sock_destroy(net->dccp.v4_ctl_sk);
|
||||
}
|
||||
|
||||
+2
-2
@@ -1189,7 +1189,7 @@ static struct inet_protosw dccp_v6_protosw = {
|
||||
.flags = INET_PROTOSW_ICSK,
|
||||
};
|
||||
|
||||
static int dccp_v6_init_net(struct net *net)
|
||||
static int __net_init dccp_v6_init_net(struct net *net)
|
||||
{
|
||||
int err;
|
||||
|
||||
@@ -1198,7 +1198,7 @@ static int dccp_v6_init_net(struct net *net)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void dccp_v6_exit_net(struct net *net)
|
||||
static void __net_exit dccp_v6_exit_net(struct net *net)
|
||||
{
|
||||
inet_ctl_sock_destroy(net->dccp.v6_ctl_sk);
|
||||
}
|
||||
|
||||
+2
-2
@@ -161,8 +161,8 @@ static __init int dccpprobe_init(void)
|
||||
if (!proc_net_fops_create(&init_net, procname, S_IRUSR, &dccpprobe_fops))
|
||||
goto err0;
|
||||
|
||||
ret = try_then_request_module((register_jprobe(&dccp_send_probe) == 0),
|
||||
"dccp");
|
||||
try_then_request_module((ret = register_jprobe(&dccp_send_probe)) == 0,
|
||||
"dccp");
|
||||
if (ret)
|
||||
goto err1;
|
||||
|
||||
|
||||
+5
-2
@@ -835,6 +835,8 @@ verify_sock_status:
|
||||
len = -EFAULT;
|
||||
break;
|
||||
}
|
||||
if (flags & MSG_TRUNC)
|
||||
len = skb->len;
|
||||
found_fin_ok:
|
||||
if (!(flags & MSG_PEEK))
|
||||
sk_eat_skb(sk, skb, 0);
|
||||
@@ -1003,12 +1005,13 @@ EXPORT_SYMBOL_GPL(dccp_shutdown);
|
||||
|
||||
static inline int dccp_mib_init(void)
|
||||
{
|
||||
return snmp_mib_init((void**)dccp_statistics, sizeof(struct dccp_mib));
|
||||
return snmp_mib_init((void __percpu **)dccp_statistics,
|
||||
sizeof(struct dccp_mib));
|
||||
}
|
||||
|
||||
static inline void dccp_mib_exit(void)
|
||||
{
|
||||
snmp_mib_free((void**)dccp_statistics);
|
||||
snmp_mib_free((void __percpu **)dccp_statistics);
|
||||
}
|
||||
|
||||
static int thash_entries;
|
||||
|
||||
@@ -1155,8 +1155,8 @@ static int __dn_route_output_key(struct dst_entry **pprt, const struct flowi *fl
|
||||
|
||||
if (!(flags & MSG_TRYHARD)) {
|
||||
rcu_read_lock_bh();
|
||||
for(rt = rcu_dereference(dn_rt_hash_table[hash].chain); rt;
|
||||
rt = rcu_dereference(rt->u.dst.dn_next)) {
|
||||
for (rt = rcu_dereference_bh(dn_rt_hash_table[hash].chain); rt;
|
||||
rt = rcu_dereference_bh(rt->u.dst.dn_next)) {
|
||||
if ((flp->fld_dst == rt->fl.fld_dst) &&
|
||||
(flp->fld_src == rt->fl.fld_src) &&
|
||||
(flp->mark == rt->fl.mark) &&
|
||||
@@ -1618,9 +1618,9 @@ int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb)
|
||||
if (h > s_h)
|
||||
s_idx = 0;
|
||||
rcu_read_lock_bh();
|
||||
for(rt = rcu_dereference(dn_rt_hash_table[h].chain), idx = 0;
|
||||
for(rt = rcu_dereference_bh(dn_rt_hash_table[h].chain), idx = 0;
|
||||
rt;
|
||||
rt = rcu_dereference(rt->u.dst.dn_next), idx++) {
|
||||
rt = rcu_dereference_bh(rt->u.dst.dn_next), idx++) {
|
||||
if (idx < s_idx)
|
||||
continue;
|
||||
skb_dst_set(skb, dst_clone(&rt->u.dst));
|
||||
@@ -1654,12 +1654,12 @@ static struct dn_route *dn_rt_cache_get_first(struct seq_file *seq)
|
||||
|
||||
for(s->bucket = dn_rt_hash_mask; s->bucket >= 0; --s->bucket) {
|
||||
rcu_read_lock_bh();
|
||||
rt = dn_rt_hash_table[s->bucket].chain;
|
||||
rt = rcu_dereference_bh(dn_rt_hash_table[s->bucket].chain);
|
||||
if (rt)
|
||||
break;
|
||||
rcu_read_unlock_bh();
|
||||
}
|
||||
return rcu_dereference(rt);
|
||||
return rt;
|
||||
}
|
||||
|
||||
static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_route *rt)
|
||||
@@ -1674,7 +1674,7 @@ static struct dn_route *dn_rt_cache_get_next(struct seq_file *seq, struct dn_rou
|
||||
rcu_read_lock_bh();
|
||||
rt = dn_rt_hash_table[s->bucket].chain;
|
||||
}
|
||||
return rcu_dereference(rt);
|
||||
return rcu_dereference_bh(rt);
|
||||
}
|
||||
|
||||
static void *dn_rt_cache_seq_start(struct seq_file *seq, loff_t *pos)
|
||||
|
||||
+3
-3
@@ -73,8 +73,8 @@ __setup("ether=", netdev_boot_setup);
|
||||
* @len: packet length (<= skb->len)
|
||||
*
|
||||
*
|
||||
* Set the protocol type. For a packet of type ETH_P_802_3 we put the length
|
||||
* in here instead. It is up to the 802.2 layer to carry protocol information.
|
||||
* Set the protocol type. For a packet of type ETH_P_802_3/2 we put the length
|
||||
* in here instead.
|
||||
*/
|
||||
int eth_header(struct sk_buff *skb, struct net_device *dev,
|
||||
unsigned short type,
|
||||
@@ -82,7 +82,7 @@ int eth_header(struct sk_buff *skb, struct net_device *dev,
|
||||
{
|
||||
struct ethhdr *eth = (struct ethhdr *)skb_push(skb, ETH_HLEN);
|
||||
|
||||
if (type != ETH_P_802_3)
|
||||
if (type != ETH_P_802_3 && type != ETH_P_802_2)
|
||||
eth->h_proto = htons(type);
|
||||
else
|
||||
eth->h_proto = htons(len);
|
||||
|
||||
+23
-23
@@ -1385,7 +1385,7 @@ int inet_ctl_sock_create(struct sock **sk, unsigned short family,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(inet_ctl_sock_create);
|
||||
|
||||
unsigned long snmp_fold_field(void *mib[], int offt)
|
||||
unsigned long snmp_fold_field(void __percpu *mib[], int offt)
|
||||
{
|
||||
unsigned long res = 0;
|
||||
int i;
|
||||
@@ -1398,7 +1398,7 @@ unsigned long snmp_fold_field(void *mib[], int offt)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snmp_fold_field);
|
||||
|
||||
int snmp_mib_init(void *ptr[2], size_t mibsize)
|
||||
int snmp_mib_init(void __percpu *ptr[2], size_t mibsize)
|
||||
{
|
||||
BUG_ON(ptr == NULL);
|
||||
ptr[0] = __alloc_percpu(mibsize, __alignof__(unsigned long long));
|
||||
@@ -1416,7 +1416,7 @@ err0:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snmp_mib_init);
|
||||
|
||||
void snmp_mib_free(void *ptr[2])
|
||||
void snmp_mib_free(void __percpu *ptr[2])
|
||||
{
|
||||
BUG_ON(ptr == NULL);
|
||||
free_percpu(ptr[0]);
|
||||
@@ -1460,25 +1460,25 @@ static const struct net_protocol icmp_protocol = {
|
||||
|
||||
static __net_init int ipv4_mib_init_net(struct net *net)
|
||||
{
|
||||
if (snmp_mib_init((void **)net->mib.tcp_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.tcp_statistics,
|
||||
sizeof(struct tcp_mib)) < 0)
|
||||
goto err_tcp_mib;
|
||||
if (snmp_mib_init((void **)net->mib.ip_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.ip_statistics,
|
||||
sizeof(struct ipstats_mib)) < 0)
|
||||
goto err_ip_mib;
|
||||
if (snmp_mib_init((void **)net->mib.net_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.net_statistics,
|
||||
sizeof(struct linux_mib)) < 0)
|
||||
goto err_net_mib;
|
||||
if (snmp_mib_init((void **)net->mib.udp_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.udp_statistics,
|
||||
sizeof(struct udp_mib)) < 0)
|
||||
goto err_udp_mib;
|
||||
if (snmp_mib_init((void **)net->mib.udplite_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.udplite_statistics,
|
||||
sizeof(struct udp_mib)) < 0)
|
||||
goto err_udplite_mib;
|
||||
if (snmp_mib_init((void **)net->mib.icmp_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.icmp_statistics,
|
||||
sizeof(struct icmp_mib)) < 0)
|
||||
goto err_icmp_mib;
|
||||
if (snmp_mib_init((void **)net->mib.icmpmsg_statistics,
|
||||
if (snmp_mib_init((void __percpu **)net->mib.icmpmsg_statistics,
|
||||
sizeof(struct icmpmsg_mib)) < 0)
|
||||
goto err_icmpmsg_mib;
|
||||
|
||||
@@ -1486,30 +1486,30 @@ static __net_init int ipv4_mib_init_net(struct net *net)
|
||||
return 0;
|
||||
|
||||
err_icmpmsg_mib:
|
||||
snmp_mib_free((void **)net->mib.icmp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
|
||||
err_icmp_mib:
|
||||
snmp_mib_free((void **)net->mib.udplite_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
|
||||
err_udplite_mib:
|
||||
snmp_mib_free((void **)net->mib.udp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.udp_statistics);
|
||||
err_udp_mib:
|
||||
snmp_mib_free((void **)net->mib.net_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.net_statistics);
|
||||
err_net_mib:
|
||||
snmp_mib_free((void **)net->mib.ip_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.ip_statistics);
|
||||
err_ip_mib:
|
||||
snmp_mib_free((void **)net->mib.tcp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.tcp_statistics);
|
||||
err_tcp_mib:
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
static __net_exit void ipv4_mib_exit_net(struct net *net)
|
||||
{
|
||||
snmp_mib_free((void **)net->mib.icmpmsg_statistics);
|
||||
snmp_mib_free((void **)net->mib.icmp_statistics);
|
||||
snmp_mib_free((void **)net->mib.udplite_statistics);
|
||||
snmp_mib_free((void **)net->mib.udp_statistics);
|
||||
snmp_mib_free((void **)net->mib.net_statistics);
|
||||
snmp_mib_free((void **)net->mib.ip_statistics);
|
||||
snmp_mib_free((void **)net->mib.tcp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.icmpmsg_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.icmp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.udplite_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.udp_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.net_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.ip_statistics);
|
||||
snmp_mib_free((void __percpu **)net->mib.tcp_statistics);
|
||||
}
|
||||
|
||||
static __net_initdata struct pernet_operations ipv4_mib_ops = {
|
||||
|
||||
+1
-1
@@ -393,7 +393,7 @@ static void ah4_err(struct sk_buff *skb, u32 info)
|
||||
icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
|
||||
return;
|
||||
|
||||
x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
|
||||
x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, ah->spi, IPPROTO_AH, AF_INET);
|
||||
if (!x)
|
||||
return;
|
||||
printk(KERN_DEBUG "pmtu discovery on SA AH/%08x/%08x\n",
|
||||
|
||||
+51
-7
@@ -70,6 +70,7 @@
|
||||
* bonding can change the skb before
|
||||
* sending (e.g. insert 8021q tag).
|
||||
* Harald Welte : convert to make use of jenkins hash
|
||||
* Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@@ -524,12 +525,15 @@ int arp_bind_neighbour(struct dst_entry *dst)
|
||||
/*
|
||||
* Check if we can use proxy ARP for this path
|
||||
*/
|
||||
|
||||
static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
|
||||
static inline int arp_fwd_proxy(struct in_device *in_dev,
|
||||
struct net_device *dev, struct rtable *rt)
|
||||
{
|
||||
struct in_device *out_dev;
|
||||
int imi, omi = -1;
|
||||
|
||||
if (rt->u.dst.dev == dev)
|
||||
return 0;
|
||||
|
||||
if (!IN_DEV_PROXY_ARP(in_dev))
|
||||
return 0;
|
||||
|
||||
@@ -547,6 +551,43 @@ static inline int arp_fwd_proxy(struct in_device *in_dev, struct rtable *rt)
|
||||
return (omi != imi && omi != -1);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check for RFC3069 proxy arp private VLAN (allow to send back to same dev)
|
||||
*
|
||||
* RFC3069 supports proxy arp replies back to the same interface. This
|
||||
* is done to support (ethernet) switch features, like RFC 3069, where
|
||||
* the individual ports are not allowed to communicate with each
|
||||
* other, BUT they are allowed to talk to the upstream router. As
|
||||
* described in RFC 3069, it is possible to allow these hosts to
|
||||
* communicate through the upstream router, by proxy_arp'ing.
|
||||
*
|
||||
* RFC 3069: "VLAN Aggregation for Efficient IP Address Allocation"
|
||||
*
|
||||
* This technology is known by different names:
|
||||
* In RFC 3069 it is called VLAN Aggregation.
|
||||
* Cisco and Allied Telesyn call it Private VLAN.
|
||||
* Hewlett-Packard call it Source-Port filtering or port-isolation.
|
||||
* Ericsson call it MAC-Forced Forwarding (RFC Draft).
|
||||
*
|
||||
*/
|
||||
static inline int arp_fwd_pvlan(struct in_device *in_dev,
|
||||
struct net_device *dev, struct rtable *rt,
|
||||
__be32 sip, __be32 tip)
|
||||
{
|
||||
/* Private VLAN is only concerned about the same ethernet segment */
|
||||
if (rt->u.dst.dev != dev)
|
||||
return 0;
|
||||
|
||||
/* Don't reply on self probes (often done by windowz boxes)*/
|
||||
if (sip == tip)
|
||||
return 0;
|
||||
|
||||
if (IN_DEV_PROXY_ARP_PVLAN(in_dev))
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Interface to link layer: send routine and receive handler.
|
||||
*/
|
||||
@@ -833,8 +874,11 @@ static int arp_process(struct sk_buff *skb)
|
||||
}
|
||||
goto out;
|
||||
} else if (IN_DEV_FORWARD(in_dev)) {
|
||||
if (addr_type == RTN_UNICAST && rt->u.dst.dev != dev &&
|
||||
(arp_fwd_proxy(in_dev, rt) || pneigh_lookup(&arp_tbl, net, &tip, dev, 0))) {
|
||||
if (addr_type == RTN_UNICAST &&
|
||||
(arp_fwd_proxy(in_dev, dev, rt) ||
|
||||
arp_fwd_pvlan(in_dev, dev, rt, sip, tip) ||
|
||||
pneigh_lookup(&arp_tbl, net, &tip, dev, 0)))
|
||||
{
|
||||
n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
|
||||
if (n)
|
||||
neigh_release(n);
|
||||
@@ -863,7 +907,8 @@ static int arp_process(struct sk_buff *skb)
|
||||
devices (strip is candidate)
|
||||
*/
|
||||
if (n == NULL &&
|
||||
arp->ar_op == htons(ARPOP_REPLY) &&
|
||||
(arp->ar_op == htons(ARPOP_REPLY) ||
|
||||
(arp->ar_op == htons(ARPOP_REQUEST) && tip == sip)) &&
|
||||
inet_addr_type(net, sip) == RTN_UNICAST)
|
||||
n = __neigh_lookup(&arp_tbl, &sip, dev, 1);
|
||||
}
|
||||
@@ -1239,8 +1284,7 @@ void __init arp_init(void)
|
||||
dev_add_pack(&arp_packet_type);
|
||||
arp_proc_init();
|
||||
#ifdef CONFIG_SYSCTL
|
||||
neigh_sysctl_register(NULL, &arp_tbl.parms, NET_IPV4,
|
||||
NET_IPV4_NEIGH, "ipv4", NULL);
|
||||
neigh_sysctl_register(NULL, &arp_tbl.parms, "ipv4", NULL);
|
||||
#endif
|
||||
register_netdevice_notifier(&arp_netdev_notifier);
|
||||
}
|
||||
|
||||
+21
-16
@@ -64,20 +64,20 @@
|
||||
|
||||
static struct ipv4_devconf ipv4_devconf = {
|
||||
.data = {
|
||||
[NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
|
||||
[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
|
||||
},
|
||||
};
|
||||
|
||||
static struct ipv4_devconf ipv4_devconf_dflt = {
|
||||
.data = {
|
||||
[NET_IPV4_CONF_ACCEPT_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SEND_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SECURE_REDIRECTS - 1] = 1,
|
||||
[NET_IPV4_CONF_SHARED_MEDIA - 1] = 1,
|
||||
[NET_IPV4_CONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
|
||||
[IPV4_DEVCONF_ACCEPT_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SEND_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SECURE_REDIRECTS - 1] = 1,
|
||||
[IPV4_DEVCONF_SHARED_MEDIA - 1] = 1,
|
||||
[IPV4_DEVCONF_ACCEPT_SOURCE_ROUTE - 1] = 1,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1317,14 +1317,19 @@ static int devinet_sysctl_forward(ctl_table *ctl, int write,
|
||||
{
|
||||
int *valp = ctl->data;
|
||||
int val = *valp;
|
||||
loff_t pos = *ppos;
|
||||
int ret = proc_dointvec(ctl, write, buffer, lenp, ppos);
|
||||
|
||||
if (write && *valp != val) {
|
||||
struct net *net = ctl->extra2;
|
||||
|
||||
if (valp != &IPV4_DEVCONF_DFLT(net, FORWARDING)) {
|
||||
if (!rtnl_trylock())
|
||||
if (!rtnl_trylock()) {
|
||||
/* Restore the original values before restarting */
|
||||
*valp = val;
|
||||
*ppos = pos;
|
||||
return restart_syscall();
|
||||
}
|
||||
if (valp == &IPV4_DEVCONF_ALL(net, FORWARDING)) {
|
||||
inet_forward_change(net);
|
||||
} else if (*valp) {
|
||||
@@ -1360,7 +1365,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
|
||||
{ \
|
||||
.procname = name, \
|
||||
.data = ipv4_devconf.data + \
|
||||
NET_IPV4_CONF_ ## attr - 1, \
|
||||
IPV4_DEVCONF_ ## attr - 1, \
|
||||
.maxlen = sizeof(int), \
|
||||
.mode = mval, \
|
||||
.proc_handler = proc, \
|
||||
@@ -1381,7 +1386,7 @@ int ipv4_doint_and_flush(ctl_table *ctl, int write,
|
||||
|
||||
static struct devinet_sysctl_table {
|
||||
struct ctl_table_header *sysctl_header;
|
||||
struct ctl_table devinet_vars[__NET_IPV4_CONF_MAX];
|
||||
struct ctl_table devinet_vars[__IPV4_DEVCONF_MAX];
|
||||
char *dev_name;
|
||||
} devinet_sysctl = {
|
||||
.devinet_vars = {
|
||||
@@ -1408,6 +1413,7 @@ static struct devinet_sysctl_table {
|
||||
DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"),
|
||||
DEVINET_SYSCTL_RW_ENTRY(ARP_ACCEPT, "arp_accept"),
|
||||
DEVINET_SYSCTL_RW_ENTRY(ARP_NOTIFY, "arp_notify"),
|
||||
DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP_PVLAN, "proxy_arp_pvlan"),
|
||||
|
||||
DEVINET_SYSCTL_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
|
||||
DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
|
||||
@@ -1486,8 +1492,7 @@ static void __devinet_sysctl_unregister(struct ipv4_devconf *cnf)
|
||||
|
||||
static void devinet_sysctl_register(struct in_device *idev)
|
||||
{
|
||||
neigh_sysctl_register(idev->dev, idev->arp_parms, NET_IPV4,
|
||||
NET_IPV4_NEIGH, "ipv4", NULL);
|
||||
neigh_sysctl_register(idev->dev, idev->arp_parms, "ipv4", NULL);
|
||||
__devinet_sysctl_register(dev_net(idev->dev), idev->dev->name,
|
||||
&idev->cnf);
|
||||
}
|
||||
@@ -1502,7 +1507,7 @@ static struct ctl_table ctl_forward_entry[] = {
|
||||
{
|
||||
.procname = "ip_forward",
|
||||
.data = &ipv4_devconf.data[
|
||||
NET_IPV4_CONF_FORWARDING - 1],
|
||||
IPV4_DEVCONF_FORWARDING - 1],
|
||||
.maxlen = sizeof(int),
|
||||
.mode = 0644,
|
||||
.proc_handler = devinet_sysctl_forward,
|
||||
@@ -1546,7 +1551,7 @@ static __net_init int devinet_init_net(struct net *net)
|
||||
if (tbl == NULL)
|
||||
goto err_alloc_ctl;
|
||||
|
||||
tbl[0].data = &all->data[NET_IPV4_CONF_FORWARDING - 1];
|
||||
tbl[0].data = &all->data[IPV4_DEVCONF_FORWARDING - 1];
|
||||
tbl[0].extra1 = all;
|
||||
tbl[0].extra2 = net;
|
||||
#endif
|
||||
|
||||
+1
-1
@@ -422,7 +422,7 @@ static void esp4_err(struct sk_buff *skb, u32 info)
|
||||
icmp_hdr(skb)->code != ICMP_FRAG_NEEDED)
|
||||
return;
|
||||
|
||||
x = xfrm_state_lookup(net, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
|
||||
x = xfrm_state_lookup(net, skb->mark, (xfrm_address_t *)&iph->daddr, esph->spi, IPPROTO_ESP, AF_INET);
|
||||
if (!x)
|
||||
return;
|
||||
NETDEBUG(KERN_DEBUG "pmtu discovery on SA ESP/%08x/%08x\n",
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user