Merge branch 'linus' into cpumask-for-linus

Conflicts:
	arch/x86/kernel/cpu/common.c
This commit is contained in:
Ingo Molnar
2009-03-30 23:53:32 +02:00
5215 changed files with 427767 additions and 208405 deletions
+8 -7
View File
@@ -29,7 +29,7 @@ static struct llc_sap *snap_sap;
/*
* Find a snap client by matching the 5 bytes.
*/
static struct datalink_proto *find_snap_client(unsigned char *desc)
static struct datalink_proto *find_snap_client(const unsigned char *desc)
{
struct datalink_proto *proto = NULL, *p;
@@ -51,7 +51,7 @@ static int snap_rcv(struct sk_buff *skb, struct net_device *dev,
int rc = 1;
struct datalink_proto *proto;
static struct packet_type snap_packet_type = {
.type = __constant_htons(ETH_P_SNAP),
.type = cpu_to_be16(ETH_P_SNAP),
};
if (unlikely(!pskb_may_pull(skb, 5)))
@@ -95,15 +95,16 @@ static int snap_request(struct datalink_proto *dl,
EXPORT_SYMBOL(register_snap_client);
EXPORT_SYMBOL(unregister_snap_client);
static char snap_err_msg[] __initdata =
static const char snap_err_msg[] __initconst =
KERN_CRIT "SNAP - unable to register with 802.2\n";
static int __init snap_init(void)
{
snap_sap = llc_sap_open(0xAA, snap_rcv);
if (!snap_sap)
if (!snap_sap) {
printk(snap_err_msg);
return -EBUSY;
}
return 0;
}
@@ -121,7 +122,7 @@ module_exit(snap_exit);
/*
* Register SNAP clients. We don't yet use this for IP.
*/
struct datalink_proto *register_snap_client(unsigned char *desc,
struct datalink_proto *register_snap_client(const unsigned char *desc,
int (*rcvfunc)(struct sk_buff *,
struct net_device *,
struct packet_type *,
@@ -136,7 +137,7 @@ struct datalink_proto *register_snap_client(unsigned char *desc,
proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
if (proto) {
memcpy(proto->type, desc,5);
memcpy(proto->type, desc, 5);
proto->rcvfunc = rcvfunc;
proto->header_length = 5 + 3; /* snap + 802.2 */
proto->request = snap_request;
+2
View File
@@ -486,6 +486,7 @@ static struct rif_cache *rif_get_idx(loff_t pos)
}
static void *rif_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(&rif_lock)
{
spin_lock_irq(&rif_lock);
@@ -517,6 +518,7 @@ static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void rif_seq_stop(struct seq_file *seq, void *v)
__releases(&rif_lock)
{
spin_unlock_irq(&rif_lock);
}
+2 -2
View File
@@ -51,8 +51,8 @@ const char vlan_version[] = DRV_VERSION;
static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
static struct packet_type vlan_packet_type = {
.type = __constant_htons(ETH_P_8021Q),
static struct packet_type vlan_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_8021Q),
.func = vlan_skb_recv, /* VLAN receive method */
};
+13 -40
View File
@@ -89,38 +89,27 @@ static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
goto drop;
for (p = napi->gro_list; p; p = p->next) {
NAPI_GRO_CB(p)->same_flow = p->dev == skb->dev;
NAPI_GRO_CB(p)->same_flow =
p->dev == skb->dev && !compare_ether_header(
skb_mac_header(p), skb_gro_mac_header(skb));
NAPI_GRO_CB(p)->flush = 0;
}
return dev_gro_receive(napi, skb);
drop:
return 2;
return GRO_DROP;
}
int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct sk_buff *skb)
{
int err = NET_RX_SUCCESS;
if (netpoll_rx_on(skb))
return vlan_hwaccel_receive_skb(skb, grp, vlan_tci);
if (netpoll_receive_skb(skb))
return NET_RX_DROP;
skb_gro_reset_offset(skb);
switch (vlan_gro_common(napi, grp, vlan_tci, skb)) {
case -1:
return netif_receive_skb(skb);
case 2:
err = NET_RX_DROP;
/* fall through */
case 1:
kfree_skb(skb);
break;
}
return err;
return napi_skb_finish(vlan_gro_common(napi, grp, vlan_tci, skb), skb);
}
EXPORT_SYMBOL(vlan_gro_receive);
@@ -128,30 +117,14 @@ int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
unsigned int vlan_tci, struct napi_gro_fraginfo *info)
{
struct sk_buff *skb = napi_fraginfo_skb(napi, info);
int err = NET_RX_DROP;
if (!skb)
goto out;
return NET_RX_DROP;
if (netpoll_receive_skb(skb))
goto out;
if (netpoll_rx_on(skb))
return vlan_hwaccel_receive_skb(skb, grp, vlan_tci);
err = NET_RX_SUCCESS;
switch (vlan_gro_common(napi, grp, vlan_tci, skb)) {
case -1:
return netif_receive_skb(skb);
case 2:
err = NET_RX_DROP;
/* fall through */
case 1:
napi_reuse_skb(napi, skb);
break;
}
out:
return err;
return napi_frags_finish(napi, skb,
vlan_gro_common(napi, grp, vlan_tci, skb));
}
EXPORT_SYMBOL(vlan_gro_frags);
+1 -1
View File
@@ -417,7 +417,7 @@ static int p9_fd_write(struct p9_client *client, void *v, int len)
oldfs = get_fs();
set_fs(get_ds());
/* The cast to a user pointer is valid due to the set_fs() */
ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
ret = vfs_write(ts->wr, (__force void __user *)v, len, &ts->wr->f_pos);
set_fs(oldfs);
if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
+14 -4
View File
@@ -4,6 +4,7 @@
menuconfig NET
bool "Networking support"
select NLATTR
---help---
Unless you really know what you are doing, you should say Y here.
The reason is that some programs need kernel networking support even
@@ -24,9 +25,6 @@ if NET
menu "Networking options"
config COMPAT_NET_DEV_OPS
def_bool y
source "net/packet/Kconfig"
source "net/unix/Kconfig"
source "net/xfrm/Kconfig"
@@ -171,6 +169,7 @@ endif
source "net/dccp/Kconfig"
source "net/sctp/Kconfig"
source "net/rds/Kconfig"
source "net/tipc/Kconfig"
source "net/atm/Kconfig"
source "net/802/Kconfig"
@@ -185,6 +184,7 @@ source "net/x25/Kconfig"
source "net/lapb/Kconfig"
source "net/econet/Kconfig"
source "net/wanrouter/Kconfig"
source "net/phonet/Kconfig"
source "net/sched/Kconfig"
source "net/dcb/Kconfig"
@@ -220,6 +220,17 @@ config NET_TCPPROBE
To compile this code as a module, choose M here: the
module will be called tcp_probe.
config NET_DROP_MONITOR
boolean "Network packet drop alerting service"
depends on INET && EXPERIMENTAL && TRACEPOINTS
---help---
This feature provides an alerting service to userspace in the
event that packets are discarded in the network stack. Alerts
are broadcast via netlink socket to any listening user space
process. If you don't need network drop alerts, or if you are ok
just checking the various proc files and other utilities for
drop statistics, say N here.
endmenu
endmenu
@@ -229,7 +240,6 @@ source "net/can/Kconfig"
source "net/irda/Kconfig"
source "net/bluetooth/Kconfig"
source "net/rxrpc/Kconfig"
source "net/phonet/Kconfig"
config FIB_RULES
bool
+1
View File
@@ -49,6 +49,7 @@ obj-y += 8021q/
endif
obj-$(CONFIG_IP_DCCP) += dccp/
obj-$(CONFIG_IP_SCTP) += sctp/
obj-$(CONFIG_RDS) += rds/
obj-y += wireless/
obj-$(CONFIG_MAC80211) += mac80211/
obj-$(CONFIG_TIPC) += tipc/
+6 -10
View File
@@ -1571,14 +1571,10 @@ static int atalk_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr
usat->sat_family != AF_APPLETALK)
return -EINVAL;
/* netatalk doesn't implement this check */
/* netatalk didn't implement this check */
if (usat->sat_addr.s_node == ATADDR_BCAST &&
!sock_flag(sk, SOCK_BROADCAST)) {
printk(KERN_INFO "SO_BROADCAST: Fix your netatalk as "
"it will break before 2.2\n");
#if 0
return -EPERM;
#endif
}
} else {
if (sk->sk_state != TCP_ESTABLISHED)
@@ -1860,13 +1856,13 @@ static struct notifier_block ddp_notifier = {
.notifier_call = ddp_device_event,
};
static struct packet_type ltalk_packet_type = {
.type = __constant_htons(ETH_P_LOCALTALK),
static struct packet_type ltalk_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_LOCALTALK),
.func = ltalk_rcv,
};
static struct packet_type ppptalk_packet_type = {
.type = __constant_htons(ETH_P_PPPTALK),
static struct packet_type ppptalk_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_PPPTALK),
.func = atalk_rcv,
};
@@ -1877,7 +1873,7 @@ EXPORT_SYMBOL(aarp_send_ddp);
EXPORT_SYMBOL(atrtr_get_dev);
EXPORT_SYMBOL(atalk_find_dev_addr);
static char atalk_err_snap[] __initdata =
static const char atalk_err_snap[] __initconst =
KERN_CRIT "Unable to register DDP with SNAP.\n";
/* Called by proto.c on kernel start up */
+4 -6
View File
@@ -9,22 +9,20 @@
#include <linux/if_arp.h>
#include <linux/if_ltalk.h>
#ifdef CONFIG_COMPAT_NET_DEV_OPS
static int ltalk_change_mtu(struct net_device *dev, int mtu)
{
return -EINVAL;
}
static int ltalk_mac_addr(struct net_device *dev, void *addr)
{
return -EINVAL;
}
#endif
static void ltalk_setup(struct net_device *dev)
{
/* Fill in the fields of the device structure with localtalk-generic values. */
#ifdef CONFIG_COMPAT_NET_DEV_OPS
dev->change_mtu = ltalk_change_mtu;
dev->set_mac_address = ltalk_mac_addr;
#endif
dev->type = ARPHRD_LOCALTLK;
dev->hard_header_len = LTALK_HLEN;
+26 -32
View File
@@ -83,7 +83,6 @@ struct br2684_dev {
struct list_head br2684_devs;
int number;
struct list_head brvccs; /* one device <=> one vcc (before xmas) */
struct net_device_stats stats;
int mac_was_set;
enum br2684_payload payload;
};
@@ -148,9 +147,10 @@ static struct net_device *br2684_find_dev(const struct br2684_if_spec *s)
* the way for multiple vcc's per itf. Returns true if we can send,
* otherwise false
*/
static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
static int br2684_xmit_vcc(struct sk_buff *skb, struct net_device *dev,
struct br2684_vcc *brvcc)
{
struct br2684_dev *brdev = BRPRIV(dev);
struct atm_vcc *atmvcc;
int minheadroom = (brvcc->encaps == e_llc) ? 10 : 2;
@@ -211,8 +211,8 @@ static int br2684_xmit_vcc(struct sk_buff *skb, struct br2684_dev *brdev,
}
atomic_add(skb->truesize, &sk_atm(atmvcc)->sk_wmem_alloc);
ATM_SKB(skb)->atm_options = atmvcc->atm_options;
brdev->stats.tx_packets++;
brdev->stats.tx_bytes += skb->len;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
atmvcc->send(atmvcc, skb);
return 1;
}
@@ -233,14 +233,14 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
brvcc = pick_outgoing_vcc(skb, brdev);
if (brvcc == NULL) {
pr_debug("no vcc attached to dev %s\n", dev->name);
brdev->stats.tx_errors++;
brdev->stats.tx_carrier_errors++;
dev->stats.tx_errors++;
dev->stats.tx_carrier_errors++;
/* netif_stop_queue(dev); */
dev_kfree_skb(skb);
read_unlock(&devs_lock);
return 0;
}
if (!br2684_xmit_vcc(skb, brdev, brvcc)) {
if (!br2684_xmit_vcc(skb, dev, brvcc)) {
/*
* We should probably use netif_*_queue() here, but that
* involves added complication. We need to walk before
@@ -248,27 +248,20 @@ static int br2684_start_xmit(struct sk_buff *skb, struct net_device *dev)
*
* Don't free here! this pointer might be no longer valid!
*/
brdev->stats.tx_errors++;
brdev->stats.tx_fifo_errors++;
dev->stats.tx_errors++;
dev->stats.tx_fifo_errors++;
}
read_unlock(&devs_lock);
return 0;
}
static struct net_device_stats *br2684_get_stats(struct net_device *dev)
{
pr_debug("br2684_get_stats\n");
return &BRPRIV(dev)->stats;
}
/*
* We remember when the MAC gets set, so we don't override it later with
* the ESI of the ATM card of the first VC
*/
static int (*my_eth_mac_addr) (struct net_device *, void *);
static int br2684_mac_addr(struct net_device *dev, void *p)
{
int err = my_eth_mac_addr(dev, p);
int err = eth_mac_addr(dev, p);
if (!err)
BRPRIV(dev)->mac_was_set = 1;
return err;
@@ -430,17 +423,17 @@ static void br2684_push(struct atm_vcc *atmvcc, struct sk_buff *skb)
/* sigh, interface is down? */
if (unlikely(!(net_dev->flags & IFF_UP)))
goto dropped;
brdev->stats.rx_packets++;
brdev->stats.rx_bytes += skb->len;
net_dev->stats.rx_packets++;
net_dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
return;
dropped:
brdev->stats.rx_dropped++;
net_dev->stats.rx_dropped++;
goto free_skb;
error:
brdev->stats.rx_errors++;
net_dev->stats.rx_errors++;
free_skb:
dev_kfree_skb(skb);
return;
@@ -531,8 +524,8 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
skb->next = skb->prev = NULL;
br2684_push(atmvcc, skb);
BRPRIV(skb->dev)->stats.rx_bytes -= skb->len;
BRPRIV(skb->dev)->stats.rx_packets--;
skb->dev->stats.rx_bytes -= skb->len;
skb->dev->stats.rx_packets--;
skb = next;
}
@@ -544,17 +537,20 @@ static int br2684_regvcc(struct atm_vcc *atmvcc, void __user * arg)
return err;
}
static const struct net_device_ops br2684_netdev_ops = {
.ndo_start_xmit = br2684_start_xmit,
.ndo_set_mac_address = br2684_mac_addr,
.ndo_change_mtu = eth_change_mtu,
.ndo_validate_addr = eth_validate_addr,
};
static void br2684_setup(struct net_device *netdev)
{
struct br2684_dev *brdev = BRPRIV(netdev);
ether_setup(netdev);
brdev->net_dev = netdev;
my_eth_mac_addr = netdev->set_mac_address;
netdev->set_mac_address = br2684_mac_addr;
netdev->hard_start_xmit = br2684_start_xmit;
netdev->get_stats = br2684_get_stats;
netdev->netdev_ops = &br2684_netdev_ops;
INIT_LIST_HEAD(&brdev->brvccs);
}
@@ -565,10 +561,8 @@ static void br2684_setup_routed(struct net_device *netdev)
brdev->net_dev = netdev;
netdev->hard_header_len = 0;
my_eth_mac_addr = netdev->set_mac_address;
netdev->set_mac_address = br2684_mac_addr;
netdev->hard_start_xmit = br2684_start_xmit;
netdev->get_stats = br2684_get_stats;
netdev->netdev_ops = &br2684_netdev_ops;
netdev->addr_len = 0;
netdev->mtu = 1500;
netdev->type = ARPHRD_PPP;
+18 -21
View File
@@ -214,15 +214,15 @@ static void clip_push(struct atm_vcc *vcc, struct sk_buff *skb)
skb->protocol = ((__be16 *) skb->data)[3];
skb_pull(skb, RFC1483LLC_LEN);
if (skb->protocol == htons(ETH_P_ARP)) {
PRIV(skb->dev)->stats.rx_packets++;
PRIV(skb->dev)->stats.rx_bytes += skb->len;
skb->dev->stats.rx_packets++;
skb->dev->stats.rx_bytes += skb->len;
clip_arp_rcv(skb);
return;
}
}
clip_vcc->last_use = jiffies;
PRIV(skb->dev)->stats.rx_packets++;
PRIV(skb->dev)->stats.rx_bytes += skb->len;
skb->dev->stats.rx_packets++;
skb->dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
}
@@ -372,7 +372,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
if (!skb->dst) {
printk(KERN_ERR "clip_start_xmit: skb->dst == NULL\n");
dev_kfree_skb(skb);
clip_priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
return 0;
}
if (!skb->dst->neighbour) {
@@ -380,13 +380,13 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb->dst->neighbour = clip_find_neighbour(skb->dst, 1);
if (!skb->dst->neighbour) {
dev_kfree_skb(skb); /* lost that one */
clip_priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
return 0;
}
#endif
printk(KERN_ERR "clip_start_xmit: NO NEIGHBOUR !\n");
dev_kfree_skb(skb);
clip_priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
return 0;
}
entry = NEIGH2ENTRY(skb->dst->neighbour);
@@ -400,7 +400,7 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
skb_queue_tail(&entry->neigh->arp_queue, skb);
else {
dev_kfree_skb(skb);
clip_priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
}
return 0;
}
@@ -423,8 +423,8 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
printk(KERN_WARNING "clip_start_xmit: XOFF->XOFF transition\n");
return 0;
}
clip_priv->stats.tx_packets++;
clip_priv->stats.tx_bytes += skb->len;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
vcc->send(vcc, skb);
if (atm_may_send(vcc, 0)) {
entry->vccs->xoff = 0;
@@ -443,11 +443,6 @@ static int clip_start_xmit(struct sk_buff *skb, struct net_device *dev)
return 0;
}
static struct net_device_stats *clip_get_stats(struct net_device *dev)
{
return &PRIV(dev)->stats;
}
static int clip_mkip(struct atm_vcc *vcc, int timeout)
{
struct clip_vcc *clip_vcc;
@@ -501,8 +496,8 @@ static int clip_mkip(struct atm_vcc *vcc, int timeout)
skb_get(skb);
clip_push(vcc, skb);
PRIV(skb->dev)->stats.rx_packets--;
PRIV(skb->dev)->stats.rx_bytes -= len;
skb->dev->stats.rx_packets--;
skb->dev->stats.rx_bytes -= len;
kfree_skb(skb);
}
@@ -557,11 +552,13 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
return error;
}
static const struct net_device_ops clip_netdev_ops = {
.ndo_start_xmit = clip_start_xmit,
};
static void clip_setup(struct net_device *dev)
{
dev->hard_start_xmit = clip_start_xmit;
/* sg_xmit ... */
dev->get_stats = clip_get_stats;
dev->netdev_ops = &clip_netdev_ops;
dev->type = ARPHRD_ATM;
dev->hard_header_len = RFC1483LLC_LEN;
dev->mtu = RFC1626_MTU;
@@ -621,7 +618,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
}
/* ignore non-CLIP devices */
if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)
if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops)
return NOTIFY_DONE;
switch (event) {
+29 -37
View File
@@ -62,7 +62,6 @@ static unsigned char bridge_ula_lec[] = { 0x01, 0x80, 0xc2, 0x00, 0x00 };
static int lec_open(struct net_device *dev);
static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev);
static int lec_close(struct net_device *dev);
static struct net_device_stats *lec_get_stats(struct net_device *dev);
static void lec_init(struct net_device *dev);
static struct lec_arp_table *lec_arp_find(struct lec_priv *priv,
const unsigned char *mac_addr);
@@ -218,28 +217,28 @@ static unsigned char *get_tr_dst(unsigned char *packet, unsigned char *rdesc)
static int lec_open(struct net_device *dev)
{
struct lec_priv *priv = netdev_priv(dev);
netif_start_queue(dev);
memset(&priv->stats, 0, sizeof(struct net_device_stats));
memset(&dev->stats, 0, sizeof(struct net_device_stats));
return 0;
}
static __inline__ void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb, struct lec_priv *priv)
static void
lec_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
struct net_device *dev = skb->dev;
ATM_SKB(skb)->vcc = vcc;
ATM_SKB(skb)->atm_options = vcc->atm_options;
atomic_add(skb->truesize, &sk_atm(vcc)->sk_wmem_alloc);
if (vcc->send(vcc, skb) < 0) {
priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
return;
}
priv->stats.tx_packets++;
priv->stats.tx_bytes += skb->len;
dev->stats.tx_packets++;
dev->stats.tx_bytes += skb->len;
}
static void lec_tx_timeout(struct net_device *dev)
@@ -270,7 +269,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
pr_debug("lec_start_xmit called\n");
if (!priv->lecd) {
printk("%s:No lecd attached\n", dev->name);
priv->stats.tx_errors++;
dev->stats.tx_errors++;
netif_stop_queue(dev);
return -EUNATCH;
}
@@ -345,7 +344,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
GFP_ATOMIC);
dev_kfree_skb(skb);
if (skb2 == NULL) {
priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
return 0;
}
skb = skb2;
@@ -380,7 +379,7 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
("%s:lec_start_xmit: tx queue full or no arp entry, dropping, ",
dev->name);
pr_debug("MAC address %pM\n", lec_h->h_dest);
priv->stats.tx_dropped++;
dev->stats.tx_dropped++;
dev_kfree_skb(skb);
}
goto out;
@@ -392,10 +391,10 @@ static int lec_start_xmit(struct sk_buff *skb, struct net_device *dev)
while (entry && (skb2 = skb_dequeue(&entry->tx_wait))) {
pr_debug("lec.c: emptying tx queue, ");
pr_debug("MAC address %pM\n", lec_h->h_dest);
lec_send(vcc, skb2, priv);
lec_send(vcc, skb2);
}
lec_send(vcc, skb, priv);
lec_send(vcc, skb);
if (!atm_may_send(vcc, 0)) {
struct lec_vcc_priv *vpriv = LEC_VCC_PRIV(vcc);
@@ -427,15 +426,6 @@ static int lec_close(struct net_device *dev)
return 0;
}
/*
* Get the current statistics.
* This may be called with the card open or closed.
*/
static struct net_device_stats *lec_get_stats(struct net_device *dev)
{
return &((struct lec_priv *)netdev_priv(dev))->stats;
}
static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
{
unsigned long flags;
@@ -512,7 +502,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
priv->lane2_ops = NULL;
if (priv->lane_version > 1)
priv->lane2_ops = &lane2_ops;
if (dev->change_mtu(dev, mesg->content.config.mtu))
if (dev_set_mtu(dev, mesg->content.config.mtu))
printk("%s: change_mtu to %d failed\n", dev->name,
mesg->content.config.mtu);
priv->is_proxy = mesg->content.config.is_proxy;
@@ -677,17 +667,19 @@ static void lec_set_multicast_list(struct net_device *dev)
return;
}
static const struct net_device_ops lec_netdev_ops = {
.ndo_open = lec_open,
.ndo_stop = lec_close,
.ndo_start_xmit = lec_start_xmit,
.ndo_change_mtu = lec_change_mtu,
.ndo_tx_timeout = lec_tx_timeout,
.ndo_set_multicast_list = lec_set_multicast_list,
};
static void lec_init(struct net_device *dev)
{
dev->change_mtu = lec_change_mtu;
dev->open = lec_open;
dev->stop = lec_close;
dev->hard_start_xmit = lec_start_xmit;
dev->tx_timeout = lec_tx_timeout;
dev->get_stats = lec_get_stats;
dev->set_multicast_list = lec_set_multicast_list;
dev->do_ioctl = NULL;
dev->netdev_ops = &lec_netdev_ops;
printk("%s: Initialized!\n", dev->name);
}
@@ -810,8 +802,8 @@ static void lec_push(struct atm_vcc *vcc, struct sk_buff *skb)
else
#endif
skb->protocol = eth_type_trans(skb, dev);
priv->stats.rx_packets++;
priv->stats.rx_bytes += skb->len;
dev->stats.rx_packets++;
dev->stats.rx_bytes += skb->len;
memset(ATM_SKB(skb), 0, sizeof(struct atm_skb_data));
netif_rx(skb);
}
@@ -1887,7 +1879,7 @@ restart:
lec_arp_hold(entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
lec_send(vcc, skb, entry->priv);
lec_send(vcc, skb);
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
@@ -2305,7 +2297,7 @@ restart:
lec_arp_hold(entry);
spin_unlock_irqrestore(&priv->lec_arp_lock, flags);
while ((skb = skb_dequeue(&entry->tx_wait)) != NULL)
lec_send(vcc, skb, entry->priv);
lec_send(vcc, skb);
entry->last_used = jiffies;
entry->status = ESI_FORWARD_DIRECT;
lec_arp_put(entry);
-1
View File
@@ -69,7 +69,6 @@ struct lane2_ops {
#define LEC_ARP_TABLE_SIZE 16
struct lec_priv {
struct net_device_stats stats;
unsigned short lecid; /* Lecid of this client */
struct hlist_head lec_arp_empty_ones;
/* Used for storing VCC's that don't have a MAC address attached yet */
+14 -18
View File
@@ -286,33 +286,32 @@ static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
{
dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name);
if (dev->hard_start_xmit == NULL) {
printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",
dev->name);
return;
if (!dev->netdev_ops)
printk("mpoa: (%s) start_mpc not starting\n", dev->name);
else {
mpc->old_ops = dev->netdev_ops;
mpc->new_ops = *mpc->old_ops;
mpc->new_ops.ndo_start_xmit = mpc_send_packet;
dev->netdev_ops = &mpc->new_ops;
}
mpc->old_hard_start_xmit = dev->hard_start_xmit;
dev->hard_start_xmit = mpc_send_packet;
return;
}
static void stop_mpc(struct mpoa_client *mpc)
{
struct net_device *dev = mpc->dev;
dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name);
/* Lets not nullify lec device's dev->hard_start_xmit */
if (mpc->dev->hard_start_xmit != mpc_send_packet) {
if (dev->netdev_ops != &mpc->new_ops) {
dprintk(" mpc already stopped, not fatal\n");
return;
}
dprintk("\n");
mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit;
mpc->old_hard_start_xmit = NULL;
/* close_shortcuts(mpc); ??? FIXME */
return;
dev->netdev_ops = mpc->old_ops;
mpc->old_ops = NULL;
/* close_shortcuts(mpc); ??? FIXME */
}
static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
@@ -531,7 +530,6 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
*/
static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
{
int retval;
struct mpoa_client *mpc;
struct ethhdr *eth;
int i = 0;
@@ -561,9 +559,7 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
}
non_ip:
retval = mpc->old_hard_start_xmit(skb,dev);
return retval;
return mpc->old_ops->ndo_start_xmit(skb,dev);
}
static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
+4 -1
View File
@@ -15,7 +15,7 @@ struct mpoa_client {
struct mpoa_client *next;
struct net_device *dev; /* lec in question */
int dev_num; /* e.g. 2 for lec2 */
int (*old_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev);
struct atm_vcc *mpoad_vcc; /* control channel to mpoad */
uint8_t mps_ctrl_addr[ATM_ESA_LEN]; /* MPS control ATM address */
uint8_t our_ctrl_addr[ATM_ESA_LEN]; /* MPC's control ATM address */
@@ -31,6 +31,9 @@ struct mpoa_client {
uint8_t *mps_macs; /* array of MPS MAC addresses, >=1 */
int number_of_mps_macs; /* number of the above MAC addresses */
struct mpc_parameters parameters; /* parameters for this client */
const struct net_device_ops *old_ops;
struct net_device_ops new_ops;
};
+3 -6
View File
@@ -1529,10 +1529,8 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
dp = ax25->digipeat;
}
SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n");
/* Build a packet */
SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n");
SOCK_DEBUG(sk, "AX.25: sendto: Addresses built. Building packet.\n");
/* Assume the worst case */
size = len + ax25->ax25_dev->dev->hard_header_len;
@@ -1985,9 +1983,8 @@ static const struct proto_ops ax25_proto_ops = {
/*
* Called by socket.c on kernel start up
*/
static struct packet_type ax25_packet_type = {
.type = __constant_htons(ETH_P_AX25),
.dev = NULL, /* All devices */
static struct packet_type ax25_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_AX25),
.func = ax25_kiss_rcv,
};
+5 -8
View File
@@ -61,27 +61,24 @@ void ax25_protocol_release(unsigned int pid)
write_lock_bh(&protocol_list_lock);
protocol = protocol_list;
if (protocol == NULL) {
write_unlock_bh(&protocol_list_lock);
return;
}
if (protocol == NULL)
goto out;
if (protocol->pid == pid) {
protocol_list = protocol->next;
write_unlock_bh(&protocol_list_lock);
return;
goto out;
}
while (protocol != NULL && protocol->next != NULL) {
if (protocol->next->pid == pid) {
s = protocol->next;
protocol->next = protocol->next->next;
write_unlock_bh(&protocol_list_lock);
return;
goto out;
}
protocol = protocol->next;
}
out:
write_unlock_bh(&protocol_list_lock);
}
+7 -10
View File
@@ -41,14 +41,13 @@
#include <net/bluetooth/bluetooth.h>
#define VERSION "2.14"
#define VERSION "2.15"
/* Bluetooth sockets */
#define BT_MAX_PROTO 8
static struct net_proto_family *bt_proto[BT_MAX_PROTO];
static DEFINE_RWLOCK(bt_proto_lock);
#ifdef CONFIG_DEBUG_LOCK_ALLOC
static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
static const char *bt_key_strings[BT_MAX_PROTO] = {
"sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
@@ -86,11 +85,6 @@ static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
bt_slock_key_strings[proto], &bt_slock_key[proto],
bt_key_strings[proto], &bt_lock_key[proto]);
}
#else
static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
{
}
#endif
int bt_sock_register(int proto, struct net_proto_family *ops)
{
@@ -217,7 +211,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
continue;
}
if (sk->sk_state == BT_CONNECTED || !newsock) {
if (sk->sk_state == BT_CONNECTED || !newsock ||
bt_sk(parent)->defer_setup) {
bt_accept_unlink(sk);
if (newsock)
sock_graft(sk, newsock);
@@ -232,7 +227,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
EXPORT_SYMBOL(bt_accept_dequeue);
int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t len, int flags)
struct msghdr *msg, size_t len, int flags)
{
int noblock = flags & MSG_DONTWAIT;
struct sock *sk = sock->sk;
@@ -277,7 +272,9 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
if (sk->sk_state == BT_CONNECTED)
if (sk->sk_state == BT_CONNECTED ||
(bt_sk(parent)->defer_setup &&
sk->sk_state == BT_CONNECT2))
return POLLIN | POLLRDNORM;
}
+1 -2
View File
@@ -126,8 +126,7 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const
session->reassembly[id] = nskb;
if (skb)
kfree_skb(skb);
kfree_skb(skb);
}
static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
+41 -23
View File
@@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT;
conn->out = 1;
conn->attempt++;
cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(conn->pkt_type);
@@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
conn->state = BT_CONNECT;
conn->out = 1;
conn->attempt++;
cp.handle = cpu_to_le16(handle);
cp.pkt_type = cpu_to_le16(conn->pkt_type);
@@ -155,6 +159,7 @@ static void hci_conn_timeout(unsigned long arg)
{
struct hci_conn *conn = (void *) arg;
struct hci_dev *hdev = conn->hdev;
__u8 reason;
BT_DBG("conn %p state %d", conn, conn->state);
@@ -173,7 +178,8 @@ static void hci_conn_timeout(unsigned long arg)
break;
case BT_CONFIG:
case BT_CONNECTED:
hci_acl_disconn(conn, 0x13);
reason = hci_proto_disconn_ind(conn);
hci_acl_disconn(conn, reason);
break;
default:
conn->state = BT_CLOSED;
@@ -216,12 +222,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
break;
case SCO_LINK:
if (lmp_esco_capable(hdev))
conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
(hdev->esco_type & EDR_ESCO_MASK);
else
conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
break;
case ESCO_LINK:
conn->pkt_type = hdev->esco_type;
conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
break;
}
@@ -280,6 +287,8 @@ int hci_conn_del(struct hci_conn *conn)
skb_queue_purge(&conn->data_q);
hci_conn_del_sysfs(conn);
return 0;
}
@@ -325,7 +334,7 @@ EXPORT_SYMBOL(hci_get_route);
/* Create SCO or ACL connection.
* Device _must_ be locked */
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type)
struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
{
struct hci_conn *acl;
struct hci_conn *sco;
@@ -340,6 +349,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
hci_conn_hold(acl);
if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
acl->sec_level = sec_level;
acl->auth_type = auth_type;
hci_acl_connect(acl);
}
@@ -385,51 +395,59 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
EXPORT_SYMBOL(hci_conn_check_link_mode);
/* Authenticate remote device */
int hci_conn_auth(struct hci_conn *conn)
static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
if (!(conn->auth_type & 0x01)) {
conn->auth_type |= 0x01;
conn->link_mode &= ~HCI_LM_AUTH;
}
}
if (conn->link_mode & HCI_LM_AUTH)
if (sec_level > conn->sec_level)
conn->sec_level = sec_level;
else if (conn->link_mode & HCI_LM_AUTH)
return 1;
conn->auth_type = auth_type;
if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
struct hci_cp_auth_requested cp;
cp.handle = cpu_to_le16(conn->handle);
hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
sizeof(cp), &cp);
}
return 0;
}
EXPORT_SYMBOL(hci_conn_auth);
/* Enable encryption */
int hci_conn_encrypt(struct hci_conn *conn)
/* Enable security */
int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
{
BT_DBG("conn %p", conn);
if (sec_level == BT_SECURITY_SDP)
return 1;
if (sec_level == BT_SECURITY_LOW) {
if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
return hci_conn_auth(conn, sec_level, auth_type);
else
return 1;
}
if (conn->link_mode & HCI_LM_ENCRYPT)
return hci_conn_auth(conn);
return hci_conn_auth(conn, sec_level, auth_type);
if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
return 0;
if (hci_conn_auth(conn)) {
if (hci_conn_auth(conn, sec_level, auth_type)) {
struct hci_cp_set_conn_encrypt cp;
cp.handle = cpu_to_le16(conn->handle);
cp.encrypt = 1;
hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
sizeof(cp), &cp);
}
return 0;
}
EXPORT_SYMBOL(hci_conn_encrypt);
EXPORT_SYMBOL(hci_conn_security);
/* Change link key */
int hci_conn_change_link_key(struct hci_conn *conn)
@@ -442,12 +460,13 @@ int hci_conn_change_link_key(struct hci_conn *conn)
hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
sizeof(cp), &cp);
}
return 0;
}
EXPORT_SYMBOL(hci_conn_change_link_key);
/* Switch role */
int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
{
BT_DBG("conn %p", conn);
@@ -460,6 +479,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
cp.role = role;
hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
}
return 0;
}
EXPORT_SYMBOL(hci_conn_switch_role);
@@ -542,9 +562,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
c->state = BT_CLOSED;
hci_conn_del_sysfs(c);
hci_proto_disconn_ind(c, 0x16);
hci_proto_disconn_cfm(c, 0x16);
hci_conn_del(c);
}
}
+1 -2
View File
@@ -1565,8 +1565,7 @@ static void hci_cmd_task(unsigned long arg)
/* Send queued commands */
if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
if (hdev->sent_cmd)
kfree_skb(hdev->sent_cmd);
kfree_skb(hdev->sent_cmd);
if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
atomic_dec(&hdev->cmd_cnt);
+21 -5
View File
@@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
if (hdev->features[4] & LMP_EV5)
hdev->esco_type |= (ESCO_EV5);
if (hdev->features[5] & LMP_EDR_ESCO_2M)
hdev->esco_type |= (ESCO_2EV3);
if (hdev->features[5] & LMP_EDR_ESCO_3M)
hdev->esco_type |= (ESCO_3EV3);
if (hdev->features[5] & LMP_EDR_3S_ESCO)
hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
hdev->features[0], hdev->features[1],
hdev->features[2], hdev->features[3],
@@ -914,7 +923,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
if (ev->status) {
hci_proto_connect_cfm(conn, ev->status);
hci_conn_del(conn);
}
} else if (ev->link_type != ACL_LINK)
hci_proto_connect_cfm(conn, ev->status);
unlock:
hci_dev_unlock(hdev);
@@ -1009,9 +1019,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
if (conn) {
conn->state = BT_CLOSED;
hci_conn_del_sysfs(conn);
hci_proto_disconn_ind(conn, ev->reason);
hci_proto_disconn_cfm(conn, ev->reason);
hci_conn_del(conn);
}
@@ -1600,7 +1608,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
if (conn->state == BT_CONFIG) {
if (!ev->status && hdev->ssp_mode > 0 &&
conn->ssp_mode > 0 && conn->out) {
conn->ssp_mode > 0 && conn->out &&
conn->sec_level != BT_SECURITY_SDP) {
struct hci_cp_auth_requested cp;
cp.handle = ev->handle;
hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
@@ -1637,6 +1646,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
conn->type = SCO_LINK;
}
if (conn->out && ev->status == 0x1c && conn->attempt < 2) {
conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
(hdev->esco_type & EDR_ESCO_MASK);
hci_setup_sync(conn, conn->link->handle);
goto unlock;
}
if (!ev->status) {
conn->handle = __le16_to_cpu(ev->handle);
conn->state = BT_CONNECTED;
+1 -1
View File
@@ -140,7 +140,7 @@ static void del_conn(struct work_struct *work)
dev = device_find_child(&conn->dev, NULL, __match_tty);
if (!dev)
break;
device_move(dev, NULL);
device_move(dev, NULL, DPM_ORDER_DEV_LAST);
put_device(dev);
}
+441 -163
View File
@@ -50,9 +50,10 @@
#include <net/bluetooth/hci_core.h>
#include <net/bluetooth/l2cap.h>
#define VERSION "2.11"
#define VERSION "2.13"
static u32 l2cap_feat_mask = 0x0000;
static u32 l2cap_feat_mask = 0x0080;
static u8 l2cap_fixed_chan[8] = { 0x02, };
static const struct proto_ops l2cap_sock_ops;
@@ -77,9 +78,10 @@ static void l2cap_sock_timeout(unsigned long arg)
bh_lock_sock(sk);
if (sk->sk_state == BT_CONNECT &&
(l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH |
L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)))
if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
reason = ECONNREFUSED;
else if (sk->sk_state == BT_CONNECT &&
l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
reason = ECONNREFUSED;
else
reason = ETIMEDOUT;
@@ -204,6 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
conn->disc_reason = 0x13;
l2cap_pi(sk)->conn = conn;
if (sk->sk_type == SOCK_SEQPACKET) {
@@ -259,18 +263,35 @@ static void l2cap_chan_del(struct sock *sk, int err)
}
/* Service level security */
static inline int l2cap_check_link_mode(struct sock *sk)
static inline int l2cap_check_security(struct sock *sk)
{
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
__u8 auth_type;
if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
(l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE))
return hci_conn_encrypt(conn->hcon);
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_NO_BONDING;
if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH)
return hci_conn_auth(conn->hcon);
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
}
return 1;
return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
auth_type);
}
static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
@@ -312,7 +333,10 @@ static void l2cap_do_start(struct sock *sk)
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
if (l2cap_check_link_mode(sk)) {
if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
return;
if (l2cap_check_security(sk)) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
@@ -356,7 +380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
}
if (sk->sk_state == BT_CONNECT) {
if (l2cap_check_link_mode(sk)) {
if (l2cap_check_security(sk)) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
@@ -371,10 +395,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
if (l2cap_check_link_mode(sk)) {
sk->sk_state = BT_CONFIG;
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
if (l2cap_check_security(sk)) {
if (bt_sk(sk)->defer_setup) {
struct sock *parent = bt_sk(sk)->parent;
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
}
} else {
rsp.result = cpu_to_le16(L2CAP_CR_PEND);
rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
@@ -426,7 +458,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
if (l2cap_pi(sk)->force_reliable)
sk->sk_err = err;
}
@@ -437,6 +469,7 @@ static void l2cap_info_timeout(unsigned long arg)
{
struct l2cap_conn *conn = (void *) arg;
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
@@ -470,6 +503,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
spin_lock_init(&conn->lock);
rwlock_init(&conn->chan_list.lock);
conn->disc_reason = 0x13;
return conn;
}
@@ -483,8 +518,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
if (conn->rx_skb)
kfree_skb(conn->rx_skb);
kfree_skb(conn->rx_skb);
/* Kill channels */
while ((sk = conn->chan_list.head)) {
@@ -608,7 +642,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
case BT_CONNECTED:
case BT_CONFIG:
case BT_CONNECT2:
if (sk->sk_type == SOCK_SEQPACKET) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct l2cap_disconn_req req;
@@ -624,6 +657,27 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
l2cap_chan_del(sk, reason);
break;
case BT_CONNECT2:
if (sk->sk_type == SOCK_SEQPACKET) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
struct l2cap_conn_rsp rsp;
__u16 result;
if (bt_sk(sk)->defer_setup)
result = L2CAP_CR_SEC_BLOCK;
else
result = L2CAP_CR_BAD_PSM;
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
} else
l2cap_chan_del(sk, reason);
break;
case BT_CONNECT:
case BT_DISCONN:
l2cap_chan_del(sk, reason);
@@ -653,13 +707,19 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
if (parent) {
sk->sk_type = parent->sk_type;
bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
pi->imtu = l2cap_pi(parent)->imtu;
pi->omtu = l2cap_pi(parent)->omtu;
pi->link_mode = l2cap_pi(parent)->link_mode;
pi->sec_level = l2cap_pi(parent)->sec_level;
pi->role_switch = l2cap_pi(parent)->role_switch;
pi->force_reliable = l2cap_pi(parent)->force_reliable;
} else {
pi->imtu = L2CAP_DEFAULT_MTU;
pi->omtu = 0;
pi->link_mode = 0;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
pi->force_reliable = 0;
}
/* Default config options */
@@ -723,17 +783,24 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)
return 0;
}
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
{
struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
struct sock *sk = sock->sk;
int err = 0;
struct sockaddr_l2 la;
int len, err = 0;
BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
BT_DBG("sk %p", sk);
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
memset(&la, 0, sizeof(la));
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
if (la.l2_cid)
return -EINVAL;
lock_sock(sk);
if (sk->sk_state != BT_OPEN) {
@@ -741,7 +808,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
goto done;
}
if (la->l2_psm && btohs(la->l2_psm) < 0x1001 &&
if (la.l2_psm && btohs(la.l2_psm) < 0x1001 &&
!capable(CAP_NET_BIND_SERVICE)) {
err = -EACCES;
goto done;
@@ -749,14 +816,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
write_lock_bh(&l2cap_sk_list.lock);
if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
err = -EADDRINUSE;
} else {
/* Save source address */
bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
l2cap_pi(sk)->psm = la->l2_psm;
l2cap_pi(sk)->sport = la->l2_psm;
bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm;
l2cap_pi(sk)->sport = la.l2_psm;
sk->sk_state = BT_BOUND;
if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
}
write_unlock_bh(&l2cap_sk_list.lock);
@@ -776,7 +846,8 @@ static int l2cap_do_connect(struct sock *sk)
__u8 auth_type;
int err = 0;
BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
l2cap_pi(sk)->psm);
if (!(hdev = hci_get_route(dst, src)))
return -EHOSTUNREACH;
@@ -785,21 +856,42 @@ static int l2cap_do_connect(struct sock *sk)
err = -ENOMEM;
if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
if (sk->sk_type == SOCK_RAW) {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_DEDICATED_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_DEDICATED_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
} else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
auth_type = HCI_AT_NO_BONDING_MITM;
else
auth_type = HCI_AT_GENERAL_BONDING_MITM;
} else {
if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
auth_type = HCI_AT_NO_BONDING;
else
if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
} else {
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
}
hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
hcon = hci_connect(hdev, ACL_LINK, dst,
l2cap_pi(sk)->sec_level, auth_type);
if (!hcon)
goto done;
@@ -835,20 +927,25 @@ done:
static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
{
struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
struct sock *sk = sock->sk;
int err = 0;
lock_sock(sk);
struct sockaddr_l2 la;
int len, err = 0;
BT_DBG("sk %p", sk);
if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
err = -EINVAL;
goto done;
}
if (!addr || addr->sa_family != AF_BLUETOOTH)
return -EINVAL;
if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) {
memset(&la, 0, sizeof(la));
len = min_t(unsigned int, sizeof(la), alen);
memcpy(&la, addr, len);
if (la.l2_cid)
return -EINVAL;
lock_sock(sk);
if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
err = -EINVAL;
goto done;
}
@@ -875,8 +972,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
}
/* Set destination address and psm */
bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
l2cap_pi(sk)->psm = la->l2_psm;
bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
l2cap_pi(sk)->psm = la.l2_psm;
if ((err = l2cap_do_connect(sk)))
goto done;
@@ -1000,12 +1097,16 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
addr->sa_family = AF_BLUETOOTH;
*len = sizeof(struct sockaddr_l2);
if (peer)
if (peer) {
la->l2_psm = l2cap_pi(sk)->psm;
bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
else
la->l2_cid = htobs(l2cap_pi(sk)->dcid);
} else {
la->l2_psm = l2cap_pi(sk)->sport;
bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
la->l2_cid = htobs(l2cap_pi(sk)->scid);
}
la->l2_psm = l2cap_pi(sk)->psm;
return 0;
}
@@ -1106,11 +1207,38 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
return err;
}
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
{
struct sock *sk = sock->sk;
lock_sock(sk);
if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
struct l2cap_conn_rsp rsp;
sk->sk_state = BT_CONFIG;
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
release_sock(sk);
return 0;
}
release_sock(sk);
return bt_sock_recvmsg(iocb, sock, msg, len, flags);
}
static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct l2cap_options opts;
int err = 0, len;
int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
@@ -1140,7 +1268,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
break;
}
l2cap_pi(sk)->link_mode = opt;
if (opt & L2CAP_LM_AUTH)
l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
if (opt & L2CAP_LM_ENCRYPT)
l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
if (opt & L2CAP_LM_SECURE)
l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
l2cap_pi(sk)->role_switch = (opt & L2CAP_LM_MASTER);
l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
break;
default:
@@ -1152,12 +1288,77 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
return err;
}
static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct bt_security sec;
int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
if (level == SOL_L2CAP)
return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
lock_sock(sk);
switch (optname) {
case BT_SECURITY:
if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
err = -EINVAL;
break;
}
sec.level = BT_SECURITY_LOW;
len = min_t(unsigned int, sizeof(sec), optlen);
if (copy_from_user((char *) &sec, optval, len)) {
err = -EFAULT;
break;
}
if (sec.level < BT_SECURITY_LOW ||
sec.level > BT_SECURITY_HIGH) {
err = -EINVAL;
break;
}
l2cap_pi(sk)->sec_level = sec.level;
break;
case BT_DEFER_SETUP:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
break;
}
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
bt_sk(sk)->defer_setup = opt;
break;
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct l2cap_options opts;
struct l2cap_conninfo cinfo;
int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
@@ -1180,12 +1381,36 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
break;
case L2CAP_LM:
if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
switch (l2cap_pi(sk)->sec_level) {
case BT_SECURITY_LOW:
opt = L2CAP_LM_AUTH;
break;
case BT_SECURITY_MEDIUM:
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
break;
case BT_SECURITY_HIGH:
opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
L2CAP_LM_SECURE;
break;
default:
opt = 0;
break;
}
if (l2cap_pi(sk)->role_switch)
opt |= L2CAP_LM_MASTER;
if (l2cap_pi(sk)->force_reliable)
opt |= L2CAP_LM_RELIABLE;
if (put_user(opt, (u32 __user *) optval))
err = -EFAULT;
break;
case L2CAP_CONNINFO:
if (sk->sk_state != BT_CONNECTED) {
if (sk->sk_state != BT_CONNECTED &&
!(sk->sk_state == BT_CONNECT2 &&
bt_sk(sk)->defer_setup)) {
err = -ENOTCONN;
break;
}
@@ -1208,6 +1433,60 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
return err;
}
static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct bt_security sec;
int len, err = 0;
BT_DBG("sk %p", sk);
if (level == SOL_L2CAP)
return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
if (get_user(len, optlen))
return -EFAULT;
lock_sock(sk);
switch (optname) {
case BT_SECURITY:
if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
err = -EINVAL;
break;
}
sec.level = l2cap_pi(sk)->sec_level;
len = min_t(unsigned int, len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT;
break;
case BT_DEFER_SETUP:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
break;
}
if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
err = -EFAULT;
break;
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static int l2cap_sock_shutdown(struct socket *sock, int how)
{
struct sock *sk = sock->sk;
@@ -1270,11 +1549,6 @@ static void l2cap_chan_ready(struct sock *sk)
*/
parent->sk_data_ready(parent, 0);
}
if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
struct l2cap_conn *conn = l2cap_pi(sk)->conn;
hci_conn_change_link_key(conn->hcon);
}
}
/* Copy frame to all raw sockets on that connection */
@@ -1549,8 +1823,11 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
cmd->ident == conn->info_ident) {
conn->info_ident = 0;
del_timer(&conn->info_timer);
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
}
@@ -1580,6 +1857,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
/* Check if the ACL is secure enough (if not SDP) */
if (psm != cpu_to_le16(0x0001) &&
!hci_conn_check_link_mode(conn->hcon)) {
conn->disc_reason = 0x05;
result = L2CAP_CR_SEC_BLOCK;
goto response;
}
@@ -1621,11 +1899,18 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->ident = cmd->ident;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
if (l2cap_check_link_mode(sk)) {
sk->sk_state = BT_CONFIG;
result = L2CAP_CR_SUCCESS;
status = L2CAP_CS_NO_INFO;
if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
if (l2cap_check_security(sk)) {
if (bt_sk(sk)->defer_setup) {
sk->sk_state = BT_CONNECT2;
result = L2CAP_CR_PEND;
status = L2CAP_CS_AUTHOR_PEND;
parent->sk_data_ready(parent, 0);
} else {
sk->sk_state = BT_CONFIG;
result = L2CAP_CR_SUCCESS;
status = L2CAP_CS_NO_INFO;
}
} else {
sk->sk_state = BT_CONNECT2;
result = L2CAP_CR_PEND;
@@ -1695,11 +1980,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
l2cap_pi(sk)->dcid = dcid;
l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
l2cap_build_conf_req(sk, req), req);
break;
case L2CAP_CR_PEND:
l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
break;
default:
@@ -1908,6 +2196,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else if (type == L2CAP_IT_FIXED_CHAN) {
u8 buf[12];
struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
rsp->type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
memcpy(buf + 4, l2cap_fixed_chan, 8);
l2cap_send_cmd(conn, cmd->ident,
L2CAP_INFO_RSP, sizeof(buf), buf);
} else {
struct l2cap_info_rsp rsp;
rsp.type = cpu_to_le16(type);
@@ -1929,14 +2225,31 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
conn->info_ident = 0;
del_timer(&conn->info_timer);
if (type == L2CAP_IT_FEAT_MASK)
if (type == L2CAP_IT_FEAT_MASK) {
conn->feat_mask = get_unaligned_le32(rsp->data);
l2cap_conn_start(conn);
if (conn->feat_mask & 0x0080) {
struct l2cap_info_req req;
req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
conn->info_ident = l2cap_get_ident(conn);
l2cap_send_cmd(conn, conn->info_ident,
L2CAP_INFO_REQ, sizeof(req), &req);
} else {
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
}
} else if (type == L2CAP_IT_FIXED_CHAN) {
conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
conn->info_ident = 0;
l2cap_conn_start(conn);
}
return 0;
}
@@ -2143,10 +2456,15 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
continue;
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
lm1 |= HCI_LM_ACCEPT;
if (l2cap_pi(sk)->role_switch)
lm1 |= HCI_LM_MASTER;
exact++;
} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
} else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
lm2 |= HCI_LM_ACCEPT;
if (l2cap_pi(sk)->role_switch)
lm2 |= HCI_LM_MASTER;
}
}
read_unlock(&l2cap_sk_list.lock);
@@ -2172,7 +2490,19 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
return 0;
}
static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
static int l2cap_disconn_ind(struct hci_conn *hcon)
{
struct l2cap_conn *conn = hcon->l2cap_data;
BT_DBG("hcon %p", hcon);
if (hcon->type != ACL_LINK || !conn)
return 0x13;
return conn->disc_reason;
}
static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
@@ -2184,7 +2514,24 @@ static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
return 0;
}
static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
{
if (sk->sk_type != SOCK_SEQPACKET)
return;
if (encrypt == 0x00) {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
l2cap_sock_clear_timer(sk);
l2cap_sock_set_timer(sk, HZ * 5);
} else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
__l2cap_sock_close(sk, ECONNREFUSED);
} else {
if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
l2cap_sock_clear_timer(sk);
}
}
static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data;
@@ -2200,85 +2547,16 @@ static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
struct l2cap_pinfo *pi = l2cap_pi(sk);
bh_lock_sock(sk);
if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
!(hcon->link_mode & HCI_LM_ENCRYPT) &&
!status) {
if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
bh_unlock_sock(sk);
continue;
}
if (sk->sk_state == BT_CONNECT) {
if (!status) {
struct l2cap_conn_req req;
req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
req.psm = l2cap_pi(sk)->psm;
l2cap_pi(sk)->ident = l2cap_get_ident(conn);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_REQ, sizeof(req), &req);
} else {
l2cap_sock_clear_timer(sk);
l2cap_sock_set_timer(sk, HZ / 10);
}
} else if (sk->sk_state == BT_CONNECT2) {
struct l2cap_conn_rsp rsp;
__u16 result;
if (!status) {
sk->sk_state = BT_CONFIG;
result = L2CAP_CR_SUCCESS;
} else {
sk->sk_state = BT_DISCONN;
l2cap_sock_set_timer(sk, HZ / 10);
result = L2CAP_CR_SEC_BLOCK;
}
rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
rsp.result = cpu_to_le16(result);
rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
L2CAP_CONN_RSP, sizeof(rsp), &rsp);
}
bh_unlock_sock(sk);
}
read_unlock(&l->lock);
return 0;
}
static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
{
struct l2cap_chan_list *l;
struct l2cap_conn *conn = hcon->l2cap_data;
struct sock *sk;
if (!conn)
return 0;
l = &conn->chan_list;
BT_DBG("conn %p", conn);
read_lock(&l->lock);
for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
struct l2cap_pinfo *pi = l2cap_pi(sk);
bh_lock_sock(sk);
if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
(sk->sk_state == BT_CONNECTED ||
sk->sk_state == BT_CONFIG) &&
!status && encrypt == 0x00) {
__l2cap_sock_close(sk, ECONNREFUSED);
if (!status && (sk->sk_state == BT_CONNECTED ||
sk->sk_state == BT_CONFIG)) {
l2cap_check_encryption(sk, encrypt);
bh_unlock_sock(sk);
continue;
}
@@ -2376,7 +2654,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
goto drop;
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
skb->len);
skb->len);
conn->rx_len = len - skb->len;
} else {
BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
@@ -2398,7 +2676,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
}
skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
skb->len);
skb->len);
conn->rx_len -= skb->len;
if (!conn->rx_len) {
@@ -2424,10 +2702,10 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
sk_for_each(sk, node, &l2cap_sk_list.head) {
struct l2cap_pinfo *pi = l2cap_pi(sk);
str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
pi->imtu, pi->omtu, pi->link_mode);
pi->imtu, pi->omtu, pi->sec_level);
}
read_unlock_bh(&l2cap_sk_list.lock);
@@ -2447,7 +2725,7 @@ static const struct proto_ops l2cap_sock_ops = {
.accept = l2cap_sock_accept,
.getname = l2cap_sock_getname,
.sendmsg = l2cap_sock_sendmsg,
.recvmsg = bt_sock_recvmsg,
.recvmsg = l2cap_sock_recvmsg,
.poll = bt_sock_poll,
.ioctl = bt_sock_ioctl,
.mmap = sock_no_mmap,
@@ -2469,8 +2747,8 @@ static struct hci_proto l2cap_hci_proto = {
.connect_ind = l2cap_connect_ind,
.connect_cfm = l2cap_connect_cfm,
.disconn_ind = l2cap_disconn_ind,
.auth_cfm = l2cap_auth_cfm,
.encrypt_cfm = l2cap_encrypt_cfm,
.disconn_cfm = l2cap_disconn_cfm,
.security_cfm = l2cap_security_cfm,
.recv_acldata = l2cap_recv_acldata
};
+100 -79
View File
@@ -46,7 +46,7 @@
#include <net/bluetooth/l2cap.h>
#include <net/bluetooth/rfcomm.h>
#define VERSION "1.10"
#define VERSION "1.11"
static int disable_cfc = 0;
static int channel_mtu = -1;
@@ -223,19 +223,25 @@ static int rfcomm_l2sock_create(struct socket **sock)
return err;
}
static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
static inline int rfcomm_check_security(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
__u8 auth_type;
if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
return 1;
} else if (d->link_mode & RFCOMM_LM_AUTH) {
if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
return 1;
switch (d->sec_level) {
case BT_SECURITY_HIGH:
auth_type = HCI_AT_GENERAL_BONDING_MITM;
break;
case BT_SECURITY_MEDIUM:
auth_type = HCI_AT_GENERAL_BONDING;
break;
default:
auth_type = HCI_AT_NO_BONDING;
break;
}
return 0;
return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
auth_type);
}
/* ---- RFCOMM DLCs ---- */
@@ -388,10 +394,10 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
if (s->state == BT_CONNECTED) {
if (rfcomm_check_link_mode(d))
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
else
if (rfcomm_check_security(d))
rfcomm_send_pn(s, 1, d);
else
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
}
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
@@ -421,9 +427,16 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
d, d->state, d->dlci, err, s);
switch (d->state) {
case BT_CONNECTED:
case BT_CONFIG:
case BT_CONNECT:
case BT_CONFIG:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
rfcomm_schedule(RFCOMM_SCHED_AUTH);
break;
}
/* Fall through */
case BT_CONNECTED:
d->state = BT_DISCONN;
if (skb_queue_empty(&d->tx_queue)) {
rfcomm_send_disc(s, d->dlci);
@@ -434,6 +447,15 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
}
break;
case BT_OPEN:
case BT_CONNECT2:
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
rfcomm_schedule(RFCOMM_SCHED_AUTH);
break;
}
/* Fall through */
default:
rfcomm_dlc_clear_timer(d);
@@ -636,6 +658,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
bacpy(&addr.l2_bdaddr, src);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = 0;
addr.l2_cid = 0;
*err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (*err < 0)
goto failed;
@@ -657,6 +680,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
bacpy(&addr.l2_bdaddr, dst);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
addr.l2_cid = 0;
*err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
if (*err == 0 || *err == -EINPROGRESS)
return s;
@@ -1162,7 +1186,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
return 0;
}
static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
void rfcomm_dlc_accept(struct rfcomm_dlc *d)
{
struct sock *sk = d->session->sock->sk;
@@ -1175,12 +1199,31 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
if (d->link_mode & RFCOMM_LM_MASTER)
if (d->role_switch)
hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
}
static void rfcomm_check_accept(struct rfcomm_dlc *d)
{
if (rfcomm_check_security(d)) {
if (d->defer_setup) {
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
rfcomm_dlc_lock(d);
d->state = BT_CONNECT2;
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
} else {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
}
}
static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
{
struct rfcomm_dlc *d;
@@ -1203,11 +1246,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
if (d) {
if (d->state == BT_OPEN) {
/* DLC was previously opened by PN request */
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
} else
rfcomm_dlc_accept(d);
rfcomm_check_accept(d);
}
return 0;
}
@@ -1219,11 +1258,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
d->addr = __addr(s->initiator, dlci);
rfcomm_dlc_link(s, d);
if (rfcomm_check_link_mode(d)) {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
} else
rfcomm_dlc_accept(d);
rfcomm_check_accept(d);
} else {
rfcomm_send_dm(s, dlci);
}
@@ -1637,11 +1672,12 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
d = list_entry(p, struct rfcomm_dlc, list);
if (d->state == BT_CONFIG) {
d->mtu = s->mtu;
if (rfcomm_check_link_mode(d)) {
if (rfcomm_check_security(d)) {
rfcomm_send_pn(s, 1, d);
} else {
set_bit(RFCOMM_AUTH_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
} else
rfcomm_send_pn(s, 1, d);
}
}
}
}
@@ -1717,11 +1753,17 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
if (d->out) {
rfcomm_send_pn(s, 1, d);
rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
} else
rfcomm_dlc_accept(d);
if (d->link_mode & RFCOMM_LM_SECURE) {
struct sock *sk = s->sock->sk;
hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
} else {
if (d->defer_setup) {
set_bit(RFCOMM_DEFER_SETUP, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
rfcomm_dlc_lock(d);
d->state = BT_CONNECT2;
d->state_change(d, 0);
rfcomm_dlc_unlock(d);
} else
rfcomm_dlc_accept(d);
}
continue;
} else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
@@ -1734,6 +1776,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
continue;
}
if (test_bit(RFCOMM_SEC_PENDING, &d->flags))
continue;
if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
continue;
@@ -1876,6 +1921,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
bacpy(&addr.l2_bdaddr, ba);
addr.l2_family = AF_BLUETOOTH;
addr.l2_psm = htobs(RFCOMM_PSM);
addr.l2_cid = 0;
err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
if (err < 0) {
BT_ERR("Bind failed %d", err);
@@ -1947,42 +1993,7 @@ static int rfcomm_run(void *unused)
return 0;
}
static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
{
struct rfcomm_session *s;
struct rfcomm_dlc *d;
struct list_head *p, *n;
BT_DBG("conn %p status 0x%02x", conn, status);
s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);
if (!s)
return;
rfcomm_session_hold(s);
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
!(conn->link_mode & HCI_LM_ENCRYPT) && !status)
continue;
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue;
if (!status)
set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
}
rfcomm_session_put(s);
rfcomm_schedule(RFCOMM_SCHED_AUTH);
}
static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
{
struct rfcomm_session *s;
struct rfcomm_dlc *d;
@@ -1999,18 +2010,29 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
list_for_each_safe(p, n, &s->dlcs) {
d = list_entry(p, struct rfcomm_dlc, list);
if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
(d->state == BT_CONNECTED ||
d->state == BT_CONFIG) &&
!status && encrypt == 0x00) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
rfcomm_dlc_clear_timer(d);
if (status || encrypt == 0x00) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
}
if (d->state == BT_CONNECTED && !status && encrypt == 0x00) {
if (d->sec_level == BT_SECURITY_MEDIUM) {
set_bit(RFCOMM_SEC_PENDING, &d->flags);
rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
continue;
} else if (d->sec_level == BT_SECURITY_HIGH) {
__rfcomm_dlc_close(d, ECONNREFUSED);
continue;
}
}
if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
continue;
if (!status && encrypt)
if (!status)
set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
else
set_bit(RFCOMM_AUTH_REJECT, &d->flags);
@@ -2023,8 +2045,7 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
static struct hci_cb rfcomm_cb = {
.name = "RFCOMM",
.auth_cfm = rfcomm_auth_cfm,
.encrypt_cfm = rfcomm_encrypt_cfm
.security_cfm = rfcomm_security_cfm
};
static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
+191 -22
View File
@@ -261,12 +261,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
if (parent) {
sk->sk_type = parent->sk_type;
pi->link_mode = rfcomm_pi(parent)->link_mode;
pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
pi->sec_level = rfcomm_pi(parent)->sec_level;
pi->role_switch = rfcomm_pi(parent)->role_switch;
} else {
pi->link_mode = 0;
pi->dlc->defer_setup = 0;
pi->sec_level = BT_SECURITY_LOW;
pi->role_switch = 0;
}
pi->dlc->link_mode = pi->link_mode;
pi->dlc->sec_level = pi->sec_level;
pi->dlc->role_switch = pi->role_switch;
}
static struct proto rfcomm_proto = {
@@ -406,7 +413,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
rfcomm_pi(sk)->channel = sa->rc_channel;
d->link_mode = rfcomm_pi(sk)->link_mode;
d->sec_level = rfcomm_pi(sk)->sec_level;
d->role_switch = rfcomm_pi(sk)->role_switch;
err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
if (!err)
@@ -554,6 +562,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
struct sk_buff *skb;
int sent = 0;
if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
return -ENOTCONN;
if (msg->msg_flags & MSG_OOB)
return -EOPNOTSUPP;
@@ -570,8 +581,11 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
msg->msg_flags & MSG_DONTWAIT, &err);
if (!skb)
if (!skb) {
if (sent == 0)
sent = err;
break;
}
skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
@@ -630,10 +644,16 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
struct msghdr *msg, size_t size, int flags)
{
struct sock *sk = sock->sk;
struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
int err = 0;
size_t target, copied = 0;
long timeo;
if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
rfcomm_dlc_accept(d);
return 0;
}
if (flags & MSG_OOB)
return -EOPNOTSUPP;
@@ -710,7 +730,7 @@ out:
return copied ? : err;
}
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
int err = 0;
@@ -727,7 +747,144 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
break;
}
rfcomm_pi(sk)->link_mode = opt;
if (opt & RFCOMM_LM_AUTH)
rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
if (opt & RFCOMM_LM_ENCRYPT)
rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
if (opt & RFCOMM_LM_SECURE)
rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
break;
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
{
struct sock *sk = sock->sk;
struct bt_security sec;
int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
if (level == SOL_RFCOMM)
return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
lock_sock(sk);
switch (optname) {
case BT_SECURITY:
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
break;
}
sec.level = BT_SECURITY_LOW;
len = min_t(unsigned int, sizeof(sec), optlen);
if (copy_from_user((char *) &sec, optval, len)) {
err = -EFAULT;
break;
}
if (sec.level > BT_SECURITY_HIGH) {
err = -EINVAL;
break;
}
rfcomm_pi(sk)->sec_level = sec.level;
break;
case BT_DEFER_SETUP:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
break;
}
if (get_user(opt, (u32 __user *) optval)) {
err = -EFAULT;
break;
}
bt_sk(sk)->defer_setup = opt;
break;
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
int len, err = 0;
u32 opt;
BT_DBG("sk %p", sk);
if (get_user(len, optlen))
return -EFAULT;
lock_sock(sk);
switch (optname) {
case RFCOMM_LM:
switch (rfcomm_pi(sk)->sec_level) {
case BT_SECURITY_LOW:
opt = RFCOMM_LM_AUTH;
break;
case BT_SECURITY_MEDIUM:
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
break;
case BT_SECURITY_HIGH:
opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
RFCOMM_LM_SECURE;
break;
default:
opt = 0;
break;
}
if (rfcomm_pi(sk)->role_switch)
opt |= RFCOMM_LM_MASTER;
if (put_user(opt, (u32 __user *) optval))
err = -EFAULT;
break;
case RFCOMM_CONNINFO:
if (sk->sk_state != BT_CONNECTED &&
!rfcomm_pi(sk)->dlc->defer_setup) {
err = -ENOTCONN;
break;
}
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
err = -EFAULT;
break;
default:
@@ -742,36 +899,44 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct sock *l2cap_sk;
struct rfcomm_conninfo cinfo;
struct bt_security sec;
int len, err = 0;
BT_DBG("sk %p", sk);
if (level == SOL_RFCOMM)
return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
if (level != SOL_BLUETOOTH)
return -ENOPROTOOPT;
if (get_user(len, optlen))
return -EFAULT;
lock_sock(sk);
switch (optname) {
case RFCOMM_LM:
if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
err = -EFAULT;
break;
case RFCOMM_CONNINFO:
if (sk->sk_state != BT_CONNECTED) {
err = -ENOTCONN;
case BT_SECURITY:
if (sk->sk_type != SOCK_STREAM) {
err = -EINVAL;
break;
}
l2cap_sk = rfcomm_pi(sk)->dlc->session->sock->sk;
sec.level = rfcomm_pi(sk)->sec_level;
cinfo.hci_handle = l2cap_pi(l2cap_sk)->conn->hcon->handle;
memcpy(cinfo.dev_class, l2cap_pi(l2cap_sk)->conn->hcon->dev_class, 3);
len = min_t(unsigned int, len, sizeof(sec));
if (copy_to_user(optval, (char *) &sec, len))
err = -EFAULT;
len = min_t(unsigned int, len, sizeof(cinfo));
if (copy_to_user(optval, (char *) &cinfo, len))
break;
case BT_DEFER_SETUP:
if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
err = -EINVAL;
break;
}
if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
err = -EFAULT;
break;
@@ -888,6 +1053,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
done:
bh_unlock_sock(parent);
if (bt_sk(parent)->defer_setup)
parent->sk_state_change(parent);
return result;
}
+3 -2
View File
@@ -731,7 +731,8 @@ static int rfcomm_tty_open(struct tty_struct *tty, struct file *filp)
remove_wait_queue(&dev->wait, &wait);
if (err == 0)
device_move(dev->tty_dev, rfcomm_get_device(dev));
device_move(dev->tty_dev, rfcomm_get_device(dev),
DPM_ORDER_DEV_AFTER_PARENT);
rfcomm_tty_copy_pending(dev);
@@ -751,7 +752,7 @@ static void rfcomm_tty_close(struct tty_struct *tty, struct file *filp)
if (atomic_dec_and_test(&dev->opened)) {
if (dev->tty_dev->parent)
device_move(dev->tty_dev, NULL);
device_move(dev->tty_dev, NULL, DPM_ORDER_DEV_LAST);
/* Close DLC and dettach TTY */
rfcomm_dlc_close(dev->dlc, 0);
+51 -6
View File
@@ -195,7 +195,7 @@ static int sco_connect(struct sock *sk)
else
type = SCO_LINK;
hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
if (!hcon)
goto done;
@@ -668,7 +668,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
return err;
}
static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
struct sco_options opts;
@@ -723,6 +723,31 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
return err;
}
static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
{
struct sock *sk = sock->sk;
int len, err = 0;
BT_DBG("sk %p", sk);
if (level == SOL_SCO)
return sco_sock_getsockopt_old(sock, optname, optval, optlen);
if (get_user(len, optlen))
return -EFAULT;
lock_sock(sk);
switch (optname) {
default:
err = -ENOPROTOOPT;
break;
}
release_sock(sk);
return err;
}
static int sco_sock_release(struct socket *sock)
{
struct sock *sk = sock->sk;
@@ -832,10 +857,30 @@ done:
/* ----- SCO interface with lower layer (HCI) ----- */
static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
{
register struct sock *sk;
struct hlist_node *node;
int lm = 0;
if (type != SCO_LINK && type != ESCO_LINK)
return 0;
BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
/* Always accept connection */
return HCI_LM_ACCEPT;
/* Find listening sockets */
read_lock(&sco_sk_list.lock);
sk_for_each(sk, node, &sco_sk_list.head) {
if (sk->sk_state != BT_LISTEN)
continue;
if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
lm |= HCI_LM_ACCEPT;
break;
}
}
read_unlock(&sco_sk_list.lock);
return lm;
}
static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
@@ -857,7 +902,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
return 0;
}
static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
{
BT_DBG("hcon %p reason %d", hcon, reason);
@@ -940,7 +985,7 @@ static struct hci_proto sco_hci_proto = {
.id = HCI_PROTO_SCO,
.connect_ind = sco_connect_ind,
.connect_cfm = sco_connect_cfm,
.disconn_ind = sco_disconn_ind,
.disconn_cfm = sco_disconn_cfm,
.recv_scodata = sco_recv_scodata
};
-1
View File
@@ -426,7 +426,6 @@ err2:
err1:
kobject_del(&p->kobj);
err0:
kobject_put(&p->kobj);
dev_set_promiscuity(dev, -1);
put_back:
dev_put(dev);
+1 -1
View File
@@ -107,7 +107,7 @@ static void fake_update_pmtu(struct dst_entry *dst, u32 mtu)
static struct dst_ops fake_dst_ops = {
.family = AF_INET,
.protocol = __constant_htons(ETH_P_IP),
.protocol = cpu_to_be16(ETH_P_IP),
.update_pmtu = fake_update_pmtu,
.entries = ATOMIC_INIT(0),
};
+2 -1
View File
@@ -98,7 +98,8 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
+1 -1
View File
@@ -214,7 +214,7 @@ static struct xt_target ebt_log_tg_reg __read_mostly = {
.me = THIS_MODULE,
};
static const struct nf_logger ebt_log_logger = {
static struct nf_logger ebt_log_logger __read_mostly = {
.name = "ebt_log",
.logfn = &ebt_log_packet,
.me = THIS_MODULE,
+7 -7
View File
@@ -279,21 +279,21 @@ static struct xt_target ebt_ulog_tg_reg __read_mostly = {
.me = THIS_MODULE,
};
static const struct nf_logger ebt_ulog_logger = {
.name = "ulog",
static struct nf_logger ebt_ulog_logger __read_mostly = {
.name = "ebt_ulog",
.logfn = &ebt_log_packet,
.me = THIS_MODULE,
};
static int __init ebt_ulog_init(void)
{
bool ret = true;
int ret;
int i;
if (nlbufsiz >= 128*1024) {
printk(KERN_NOTICE "ebt_ulog: Netlink buffer has to be <= 128kB,"
" please try a smaller nlbufsiz parameter.\n");
return false;
return -EINVAL;
}
/* initialize ulog_buffers */
@@ -308,12 +308,12 @@ static int __init ebt_ulog_init(void)
if (!ebtulognl) {
printk(KERN_WARNING KBUILD_MODNAME ": out of memory trying to "
"call netlink_kernel_create\n");
ret = false;
} else if (xt_register_target(&ebt_ulog_tg_reg) != 0) {
ret = -ENOMEM;
} else if ((ret = xt_register_target(&ebt_ulog_tg_reg)) != 0) {
netlink_kernel_release(ebtulognl);
}
if (ret)
if (ret == 0)
nf_log_register(NFPROTO_BRIDGE, &ebt_ulog_logger);
return ret;
-1
View File
@@ -46,7 +46,6 @@ static struct ebt_table broute_table =
.name = "broute",
.table = &initial_table,
.valid_hooks = 1 << NF_BR_BROUTING,
.lock = __RW_LOCK_UNLOCKED(broute_table.lock),
.check = check,
.me = THIS_MODULE,
};
-1
View File
@@ -55,7 +55,6 @@ static struct ebt_table frame_filter =
.name = "filter",
.table = &initial_table,
.valid_hooks = FILTER_VALID_HOOKS,
.lock = __RW_LOCK_UNLOCKED(frame_filter.lock),
.check = check,
.me = THIS_MODULE,
};
-1
View File
@@ -55,7 +55,6 @@ static struct ebt_table frame_nat =
.name = "nat",
.table = &initial_table,
.valid_hooks = NAT_VALID_HOOKS,
.lock = __RW_LOCK_UNLOCKED(frame_nat.lock),
.check = check,
.me = THIS_MODULE,
};
+2 -3
View File
@@ -273,8 +273,7 @@ int can_send(struct sk_buff *skb, int loop)
err = net_xmit_errno(err);
if (err) {
if (newskb)
kfree_skb(newskb);
kfree_skb(newskb);
return err;
}
@@ -828,7 +827,7 @@ static int can_notifier(struct notifier_block *nb, unsigned long msg,
*/
static struct packet_type can_packet __read_mostly = {
.type = __constant_htons(ETH_P_CAN),
.type = cpu_to_be16(ETH_P_CAN),
.dev = NULL,
.func = can_rcv,
};
+3
View File
@@ -646,6 +646,9 @@ static int raw_sendmsg(struct kiocb *iocb, struct socket *sock,
goto put_dev;
err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
if (err < 0)
goto free_skb;
err = sock_tx_timestamp(msg, sk, skb_tx(skb));
if (err < 0)
goto free_skb;
skb->dev = dev;
+12 -7
View File
@@ -216,7 +216,7 @@ Efault:
int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *data)
{
struct compat_timeval ctv;
struct compat_timespec cts;
struct compat_timespec cts[3];
struct compat_cmsghdr __user *cm = (struct compat_cmsghdr __user *) kmsg->msg_control;
struct compat_cmsghdr cmhdr;
int cmlen;
@@ -233,12 +233,17 @@ int put_cmsg_compat(struct msghdr *kmsg, int level, int type, int len, void *dat
data = &ctv;
len = sizeof(ctv);
}
if (level == SOL_SOCKET && type == SCM_TIMESTAMPNS) {
if (level == SOL_SOCKET &&
(type == SCM_TIMESTAMPNS || type == SCM_TIMESTAMPING)) {
int count = type == SCM_TIMESTAMPNS ? 1 : 3;
int i;
struct timespec *ts = (struct timespec *)data;
cts.tv_sec = ts->tv_sec;
cts.tv_nsec = ts->tv_nsec;
for (i = 0; i < count; i++) {
cts[i].tv_sec = ts[i].tv_sec;
cts[i].tv_nsec = ts[i].tv_nsec;
}
data = &cts;
len = sizeof(cts);
len = sizeof(cts[0]) * count;
}
cmlen = CMSG_COMPAT_LEN(len);
@@ -455,7 +460,7 @@ int compat_sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
struct timeval tv;
if (!sock_flag(sk, SOCK_TIMESTAMP))
sock_enable_timestamp(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
tv = ktime_to_timeval(sk->sk_stamp);
if (tv.tv_sec == -1)
return err;
@@ -479,7 +484,7 @@ int compat_sock_get_timestampns(struct sock *sk, struct timespec __user *usersta
struct timespec ts;
if (!sock_flag(sk, SOCK_TIMESTAMP))
sock_enable_timestamp(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
ts = ktime_to_timespec(sk->sk_stamp);
if (ts.tv_sec == -1)
return err;
+3
View File
@@ -17,3 +17,6 @@ obj-$(CONFIG_NET_PKTGEN) += pktgen.o
obj-$(CONFIG_NETPOLL) += netpoll.o
obj-$(CONFIG_NET_DMA) += user_dma.o
obj-$(CONFIG_FIB_RULES) += fib_rules.o
obj-$(CONFIG_TRACEPOINTS) += net-traces.o
obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
+1 -1
View File
@@ -208,7 +208,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
{
kfree_skb(skb);
consume_skb(skb);
sk_mem_reclaim_partial(sk);
}
+163 -111
View File
@@ -1457,7 +1457,9 @@ static bool can_checksum_protocol(unsigned long features, __be16 protocol)
((features & NETIF_F_IP_CSUM) &&
protocol == htons(ETH_P_IP)) ||
((features & NETIF_F_IPV6_CSUM) &&
protocol == htons(ETH_P_IPV6)));
protocol == htons(ETH_P_IPV6)) ||
((features & NETIF_F_FCOE_CRC) &&
protocol == htons(ETH_P_FCOE)));
}
static bool dev_can_checksum(struct net_device *dev, struct sk_buff *skb)
@@ -1668,8 +1670,8 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
struct netdev_queue *txq)
{
const struct net_device_ops *ops = dev->netdev_ops;
int rc;
prefetch(&dev->netdev_ops->ndo_start_xmit);
if (likely(!skb->next)) {
if (!list_empty(&ptype_all))
dev_queue_xmit_nit(skb, dev);
@@ -1681,13 +1683,27 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
goto gso;
}
return ops->ndo_start_xmit(skb, dev);
rc = ops->ndo_start_xmit(skb, dev);
/*
* TODO: if skb_orphan() was called by
* dev->hard_start_xmit() (for example, the unmodified
* igb driver does that; bnx2 doesn't), then
* skb_tx_software_timestamp() will be unable to send
* back the time stamp.
*
* How can this be prevented? Always create another
* reference to the socket before calling
* dev->hard_start_xmit()? Prevent that skb_orphan()
* does anything in dev->hard_start_xmit() by clearing
* the skb destructor before the call and restoring it
* afterwards, then doing the skb_orphan() ourselves?
*/
return rc;
}
gso:
do {
struct sk_buff *nskb = skb->next;
int rc;
skb->next = nskb->next;
nskb->next = NULL;
@@ -1708,59 +1724,24 @@ out_kfree_skb:
return 0;
}
static u32 simple_tx_hashrnd;
static int simple_tx_hashrnd_initialized = 0;
static u32 skb_tx_hashrnd;
static u16 simple_tx_hash(struct net_device *dev, struct sk_buff *skb)
u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
{
u32 addr1, addr2, ports;
u32 hash, ihl;
u8 ip_proto = 0;
u32 hash;
if (unlikely(!simple_tx_hashrnd_initialized)) {
get_random_bytes(&simple_tx_hashrnd, 4);
simple_tx_hashrnd_initialized = 1;
}
if (skb_rx_queue_recorded(skb)) {
hash = skb_get_rx_queue(skb);
} else if (skb->sk && skb->sk->sk_hash) {
hash = skb->sk->sk_hash;
} else
hash = skb->protocol;
switch (skb->protocol) {
case htons(ETH_P_IP):
if (!(ip_hdr(skb)->frag_off & htons(IP_MF | IP_OFFSET)))
ip_proto = ip_hdr(skb)->protocol;
addr1 = ip_hdr(skb)->saddr;
addr2 = ip_hdr(skb)->daddr;
ihl = ip_hdr(skb)->ihl;
break;
case htons(ETH_P_IPV6):
ip_proto = ipv6_hdr(skb)->nexthdr;
addr1 = ipv6_hdr(skb)->saddr.s6_addr32[3];
addr2 = ipv6_hdr(skb)->daddr.s6_addr32[3];
ihl = (40 >> 2);
break;
default:
return 0;
}
switch (ip_proto) {
case IPPROTO_TCP:
case IPPROTO_UDP:
case IPPROTO_DCCP:
case IPPROTO_ESP:
case IPPROTO_AH:
case IPPROTO_SCTP:
case IPPROTO_UDPLITE:
ports = *((u32 *) (skb_network_header(skb) + (ihl * 4)));
break;
default:
ports = 0;
break;
}
hash = jhash_3words(addr1, addr2, ports, simple_tx_hashrnd);
hash = jhash_1word(hash, skb_tx_hashrnd);
return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
}
EXPORT_SYMBOL(skb_tx_hash);
static struct netdev_queue *dev_pick_tx(struct net_device *dev,
struct sk_buff *skb)
@@ -1771,7 +1752,7 @@ static struct netdev_queue *dev_pick_tx(struct net_device *dev,
if (ops->ndo_select_queue)
queue_index = ops->ndo_select_queue(dev, skb);
else if (dev->real_num_tx_queues > 1)
queue_index = simple_tx_hash(dev, skb);
queue_index = skb_tx_hash(dev, skb);
skb_set_queue_mapping(skb, queue_index);
return netdev_get_tx_queue(dev, queue_index);
@@ -2297,6 +2278,8 @@ ncls:
if (!skb)
goto out;
skb_orphan(skb);
type = skb->protocol;
list_for_each_entry_rcu(ptype,
&ptype_base[ntohs(type) & PTYPE_HASH_MASK], list) {
@@ -2366,7 +2349,6 @@ static int napi_gro_complete(struct sk_buff *skb)
out:
skb_shinfo(skb)->gso_size = 0;
__skb_push(skb, -skb_network_offset(skb));
return netif_receive_skb(skb);
}
@@ -2380,20 +2362,40 @@ void napi_gro_flush(struct napi_struct *napi)
napi_gro_complete(skb);
}
napi->gro_count = 0;
napi->gro_list = NULL;
}
EXPORT_SYMBOL(napi_gro_flush);
void *skb_gro_header(struct sk_buff *skb, unsigned int hlen)
{
unsigned int offset = skb_gro_offset(skb);
hlen += offset;
if (hlen <= skb_headlen(skb))
return skb->data + offset;
if (unlikely(!skb_shinfo(skb)->nr_frags ||
skb_shinfo(skb)->frags[0].size <=
hlen - skb_headlen(skb) ||
PageHighMem(skb_shinfo(skb)->frags[0].page)))
return pskb_may_pull(skb, hlen) ? skb->data + offset : NULL;
return page_address(skb_shinfo(skb)->frags[0].page) +
skb_shinfo(skb)->frags[0].page_offset +
offset - skb_headlen(skb);
}
EXPORT_SYMBOL(skb_gro_header);
int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
struct sk_buff **pp = NULL;
struct packet_type *ptype;
__be16 type = skb->protocol;
struct list_head *head = &ptype_base[ntohs(type) & PTYPE_HASH_MASK];
int count = 0;
int same_flow;
int mac_len;
int free;
int ret;
if (!(skb->dev->features & NETIF_F_GRO))
goto normal;
@@ -2403,30 +2405,16 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
rcu_read_lock();
list_for_each_entry_rcu(ptype, head, list) {
struct sk_buff *p;
if (ptype->type != type || ptype->dev || !ptype->gro_receive)
continue;
skb_reset_network_header(skb);
skb_set_network_header(skb, skb_gro_offset(skb));
mac_len = skb->network_header - skb->mac_header;
skb->mac_len = mac_len;
NAPI_GRO_CB(skb)->same_flow = 0;
NAPI_GRO_CB(skb)->flush = 0;
NAPI_GRO_CB(skb)->free = 0;
for (p = napi->gro_list; p; p = p->next) {
count++;
if (!NAPI_GRO_CB(p)->same_flow)
continue;
if (p->mac_len != mac_len ||
memcmp(skb_mac_header(p), skb_mac_header(skb),
mac_len))
NAPI_GRO_CB(p)->same_flow = 0;
}
pp = ptype->gro_receive(&napi->gro_list, skb);
break;
}
@@ -2436,7 +2424,7 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
goto normal;
same_flow = NAPI_GRO_CB(skb)->same_flow;
free = NAPI_GRO_CB(skb)->free;
ret = NAPI_GRO_CB(skb)->free ? GRO_MERGED_FREE : GRO_MERGED;
if (pp) {
struct sk_buff *nskb = *pp;
@@ -2444,27 +2432,35 @@ int dev_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
*pp = nskb->next;
nskb->next = NULL;
napi_gro_complete(nskb);
count--;
napi->gro_count--;
}
if (same_flow)
goto ok;
if (NAPI_GRO_CB(skb)->flush || count >= MAX_GRO_SKBS) {
__skb_push(skb, -skb_network_offset(skb));
if (NAPI_GRO_CB(skb)->flush || napi->gro_count >= MAX_GRO_SKBS)
goto normal;
}
napi->gro_count++;
NAPI_GRO_CB(skb)->count = 1;
skb_shinfo(skb)->gso_size = skb->len;
skb_shinfo(skb)->gso_size = skb_gro_len(skb);
skb->next = napi->gro_list;
napi->gro_list = skb;
ret = GRO_HELD;
pull:
if (unlikely(!pskb_may_pull(skb, skb_gro_offset(skb)))) {
if (napi->gro_list == skb)
napi->gro_list = skb->next;
ret = GRO_DROP;
}
ok:
return free;
return ret;
normal:
return -1;
ret = GRO_NORMAL;
goto pull;
}
EXPORT_SYMBOL(dev_gro_receive);
@@ -2472,29 +2468,44 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
struct sk_buff *p;
if (netpoll_rx_on(skb))
return GRO_NORMAL;
for (p = napi->gro_list; p; p = p->next) {
NAPI_GRO_CB(p)->same_flow = 1;
NAPI_GRO_CB(p)->same_flow = !compare_ether_header(
skb_mac_header(p), skb_gro_mac_header(skb));
NAPI_GRO_CB(p)->flush = 0;
}
return dev_gro_receive(napi, skb);
}
int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
int napi_skb_finish(int ret, struct sk_buff *skb)
{
if (netpoll_receive_skb(skb))
return NET_RX_DROP;
int err = NET_RX_SUCCESS;
switch (__napi_gro_receive(napi, skb)) {
case -1:
switch (ret) {
case GRO_NORMAL:
return netif_receive_skb(skb);
case 1:
case GRO_DROP:
err = NET_RX_DROP;
/* fall through */
case GRO_MERGED_FREE:
kfree_skb(skb);
break;
}
return NET_RX_SUCCESS;
return err;
}
EXPORT_SYMBOL(napi_skb_finish);
int napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
{
skb_gro_reset_offset(skb);
return napi_skb_finish(__napi_gro_receive(napi, skb), skb);
}
EXPORT_SYMBOL(napi_gro_receive);
@@ -2512,6 +2523,9 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
{
struct net_device *dev = napi->dev;
struct sk_buff *skb = napi->skb;
struct ethhdr *eth;
skb_frag_t *frag;
int i;
napi->skb = NULL;
@@ -2524,20 +2538,36 @@ struct sk_buff *napi_fraginfo_skb(struct napi_struct *napi,
}
BUG_ON(info->nr_frags > MAX_SKB_FRAGS);
frag = &info->frags[info->nr_frags - 1];
for (i = skb_shinfo(skb)->nr_frags; i < info->nr_frags; i++) {
skb_fill_page_desc(skb, i, frag->page, frag->page_offset,
frag->size);
frag++;
}
skb_shinfo(skb)->nr_frags = info->nr_frags;
memcpy(skb_shinfo(skb)->frags, info->frags, sizeof(info->frags));
skb->data_len = info->len;
skb->len += info->len;
skb->truesize += info->len;
if (!pskb_may_pull(skb, ETH_HLEN)) {
skb_reset_mac_header(skb);
skb_gro_reset_offset(skb);
eth = skb_gro_header(skb, sizeof(*eth));
if (!eth) {
napi_reuse_skb(napi, skb);
skb = NULL;
goto out;
}
skb->protocol = eth_type_trans(skb, dev);
skb_gro_pull(skb, sizeof(*eth));
/*
* This works because the only protocols we care about don't require
* special handling. We'll fix it up properly at the end.
*/
skb->protocol = eth->h_proto;
skb->ip_summed = info->ip_summed;
skb->csum = info->csum;
@@ -2547,31 +2577,42 @@ out:
}
EXPORT_SYMBOL(napi_fraginfo_skb);
int napi_frags_finish(struct napi_struct *napi, struct sk_buff *skb, int ret)
{
int err = NET_RX_SUCCESS;
switch (ret) {
case GRO_NORMAL:
case GRO_HELD:
skb->protocol = eth_type_trans(skb, napi->dev);
if (ret == GRO_NORMAL)
return netif_receive_skb(skb);
skb_gro_pull(skb, -ETH_HLEN);
break;
case GRO_DROP:
err = NET_RX_DROP;
/* fall through */
case GRO_MERGED_FREE:
napi_reuse_skb(napi, skb);
break;
}
return err;
}
EXPORT_SYMBOL(napi_frags_finish);
int napi_gro_frags(struct napi_struct *napi, struct napi_gro_fraginfo *info)
{
struct sk_buff *skb = napi_fraginfo_skb(napi, info);
int err = NET_RX_DROP;
if (!skb)
goto out;
return NET_RX_DROP;
if (netpoll_receive_skb(skb))
goto out;
err = NET_RX_SUCCESS;
switch (__napi_gro_receive(napi, skb)) {
case -1:
return netif_receive_skb(skb);
case 0:
goto out;
}
napi_reuse_skb(napi, skb);
out:
return err;
return napi_frags_finish(napi, skb, __napi_gro_receive(napi, skb));
}
EXPORT_SYMBOL(napi_gro_frags);
@@ -2594,11 +2635,9 @@ static int process_backlog(struct napi_struct *napi, int quota)
}
local_irq_enable();
napi_gro_receive(napi, skb);
netif_receive_skb(skb);
} while (++work < quota && jiffies == start_time);
napi_gro_flush(napi);
return work;
}
@@ -2652,6 +2691,7 @@ void netif_napi_add(struct net_device *dev, struct napi_struct *napi,
int (*poll)(struct napi_struct *, int), int weight)
{
INIT_LIST_HEAD(&napi->poll_list);
napi->gro_count = 0;
napi->gro_list = NULL;
napi->skb = NULL;
napi->poll = poll;
@@ -2671,7 +2711,7 @@ void netif_napi_del(struct napi_struct *napi)
struct sk_buff *skb, *next;
list_del_init(&napi->dev_list);
kfree(napi->skb);
kfree_skb(napi->skb);
for (skb = napi->gro_list; skb; skb = next) {
next = skb->next;
@@ -2680,6 +2720,7 @@ void netif_napi_del(struct napi_struct *napi)
}
napi->gro_list = NULL;
napi->gro_count = 0;
}
EXPORT_SYMBOL(netif_napi_del);
@@ -3948,6 +3989,7 @@ static int dev_ifsioc(struct net *net, struct ifreq *ifr, unsigned int cmd)
cmd == SIOCSMIIREG ||
cmd == SIOCBRADDIF ||
cmd == SIOCBRDELIF ||
cmd == SIOCSHWTSTAMP ||
cmd == SIOCWANDEV) {
err = -EOPNOTSUPP;
if (ops->ndo_do_ioctl) {
@@ -4102,6 +4144,7 @@ int dev_ioctl(struct net *net, unsigned int cmd, void __user *arg)
case SIOCBONDCHANGEACTIVE:
case SIOCBRADDIF:
case SIOCBRDELIF:
case SIOCSHWTSTAMP:
if (!capable(CAP_NET_ADMIN))
return -EPERM;
/* fall through */
@@ -5198,6 +5241,7 @@ static int __init net_dev_init(void)
queue->backlog.poll = process_backlog;
queue->backlog.weight = weight_p;
queue->backlog.gro_list = NULL;
queue->backlog.gro_count = 0;
}
dev_boot_phase = 0;
@@ -5230,6 +5274,14 @@ out:
subsys_initcall(net_dev_init);
static int __init initialize_hashrnd(void)
{
get_random_bytes(&skb_tx_hashrnd, sizeof(skb_tx_hashrnd));
return 0;
}
late_initcall_sync(initialize_hashrnd);
EXPORT_SYMBOL(__dev_get_by_index);
EXPORT_SYMBOL(__dev_get_by_name);
EXPORT_SYMBOL(__dev_remove_pack);
+263
View File
@@ -0,0 +1,263 @@
/*
* Monitoring code for network dropped packet alerts
*
* Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
#include <linux/inet.h>
#include <linux/interrupt.h>
#include <linux/netpoll.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/netlink.h>
#include <linux/net_dropmon.h>
#include <linux/percpu.h>
#include <linux/timer.h>
#include <linux/bitops.h>
#include <net/genetlink.h>
#include <trace/skb.h>
#include <asm/unaligned.h>
#define TRACE_ON 1
#define TRACE_OFF 0
static void send_dm_alert(struct work_struct *unused);
/*
* Globals, our netlink socket pointer
* and the work handle that will send up
* netlink alerts
*/
struct sock *dm_sock;
struct per_cpu_dm_data {
struct work_struct dm_alert_work;
struct sk_buff *skb;
atomic_t dm_hit_count;
struct timer_list send_timer;
};
static struct genl_family net_drop_monitor_family = {
.id = GENL_ID_GENERATE,
.hdrsize = 0,
.name = "NET_DM",
.version = 1,
.maxattr = NET_DM_CMD_MAX,
};
static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data);
static int dm_hit_limit = 64;
static int dm_delay = 1;
static void reset_per_cpu_data(struct per_cpu_dm_data *data)
{
size_t al;
struct net_dm_alert_msg *msg;
al = sizeof(struct net_dm_alert_msg);
al += dm_hit_limit * sizeof(struct net_dm_drop_point);
data->skb = genlmsg_new(al, GFP_KERNEL);
genlmsg_put(data->skb, 0, 0, &net_drop_monitor_family,
0, NET_DM_CMD_ALERT);
msg = __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_alert_msg));
memset(msg, 0, al);
atomic_set(&data->dm_hit_count, dm_hit_limit);
}
static void send_dm_alert(struct work_struct *unused)
{
struct sk_buff *skb;
struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
/*
* Grab the skb we're about to send
*/
skb = data->skb;
/*
* Replace it with a new one
*/
reset_per_cpu_data(data);
/*
* Ship it!
*/
genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
}
/*
* This is the timer function to delay the sending of an alert
* in the event that more drops will arrive during the
* hysteresis period. Note that it operates under the timer interrupt
* so we don't need to disable preemption here
*/
static void sched_send_work(unsigned long unused)
{
struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
schedule_work(&data->dm_alert_work);
}
static void trace_kfree_skb_hit(struct sk_buff *skb, void *location)
{
struct net_dm_alert_msg *msg;
struct nlmsghdr *nlh;
int i;
struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
if (!atomic_add_unless(&data->dm_hit_count, -1, 0)) {
/*
* we're already at zero, discard this hit
*/
goto out;
}
nlh = (struct nlmsghdr *)data->skb->data;
msg = genlmsg_data(nlmsg_data(nlh));
for (i = 0; i < msg->entries; i++) {
if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) {
msg->points[i].count++;
goto out;
}
}
/*
* We need to create a new entry
*/
__nla_reserve_nohdr(data->skb, sizeof(struct net_dm_drop_point));
memcpy(msg->points[msg->entries].pc, &location, sizeof(void *));
msg->points[msg->entries].count = 1;
msg->entries++;
if (!timer_pending(&data->send_timer)) {
data->send_timer.expires = jiffies + dm_delay * HZ;
add_timer_on(&data->send_timer, smp_processor_id());
}
out:
return;
}
static int set_all_monitor_traces(int state)
{
int rc = 0;
switch (state) {
case TRACE_ON:
rc |= register_trace_kfree_skb(trace_kfree_skb_hit);
break;
case TRACE_OFF:
rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit);
tracepoint_synchronize_unregister();
break;
default:
rc = 1;
break;
}
if (rc)
return -EINPROGRESS;
return rc;
}
static int net_dm_cmd_config(struct sk_buff *skb,
struct genl_info *info)
{
return -ENOTSUPP;
}
static int net_dm_cmd_trace(struct sk_buff *skb,
struct genl_info *info)
{
switch (info->genlhdr->cmd) {
case NET_DM_CMD_START:
return set_all_monitor_traces(TRACE_ON);
break;
case NET_DM_CMD_STOP:
return set_all_monitor_traces(TRACE_OFF);
break;
}
return -ENOTSUPP;
}
static struct genl_ops dropmon_ops[] = {
{
.cmd = NET_DM_CMD_CONFIG,
.doit = net_dm_cmd_config,
},
{
.cmd = NET_DM_CMD_START,
.doit = net_dm_cmd_trace,
},
{
.cmd = NET_DM_CMD_STOP,
.doit = net_dm_cmd_trace,
},
};
static int __init init_net_drop_monitor(void)
{
int cpu;
int rc, i, ret;
struct per_cpu_dm_data *data;
printk(KERN_INFO "Initalizing network drop monitor service\n");
if (sizeof(void *) > 8) {
printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n");
return -ENOSPC;
}
if (genl_register_family(&net_drop_monitor_family) < 0) {
printk(KERN_ERR "Could not create drop monitor netlink family\n");
return -EFAULT;
}
rc = -EFAULT;
for (i = 0; i < ARRAY_SIZE(dropmon_ops); i++) {
ret = genl_register_ops(&net_drop_monitor_family,
&dropmon_ops[i]);
if (ret) {
printk(KERN_CRIT "failed to register operation %d\n",
dropmon_ops[i].cmd);
goto out_unreg;
}
}
rc = 0;
for_each_present_cpu(cpu) {
data = &per_cpu(dm_cpu_data, cpu);
reset_per_cpu_data(data);
INIT_WORK(&data->dm_alert_work, send_dm_alert);
init_timer(&data->send_timer);
data->send_timer.data = cpu;
data->send_timer.function = sched_send_work;
}
goto out;
out_unreg:
genl_unregister_family(&net_drop_monitor_family);
out:
return rc;
}
late_initcall(init_net_drop_monitor);
+48 -10
View File
@@ -209,34 +209,62 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
return 0;
}
static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr)
static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
{
struct ethtool_rxnfc cmd;
if (!dev->ethtool_ops->set_rxhash)
if (!dev->ethtool_ops->set_rxnfc)
return -EOPNOTSUPP;
if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
return -EFAULT;
return dev->ethtool_ops->set_rxhash(dev, &cmd);
return dev->ethtool_ops->set_rxnfc(dev, &cmd);
}
static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr)
static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
{
struct ethtool_rxnfc info;
const struct ethtool_ops *ops = dev->ethtool_ops;
int ret;
void *rule_buf = NULL;
if (!dev->ethtool_ops->get_rxhash)
if (!ops->get_rxnfc)
return -EOPNOTSUPP;
if (copy_from_user(&info, useraddr, sizeof(info)))
return -EFAULT;
dev->ethtool_ops->get_rxhash(dev, &info);
if (info.cmd == ETHTOOL_GRXCLSRLALL) {
if (info.rule_cnt > 0) {
rule_buf = kmalloc(info.rule_cnt * sizeof(u32),
GFP_USER);
if (!rule_buf)
return -ENOMEM;
}
}
ret = ops->get_rxnfc(dev, &info, rule_buf);
if (ret < 0)
goto err_out;
ret = -EFAULT;
if (copy_to_user(useraddr, &info, sizeof(info)))
return -EFAULT;
return 0;
goto err_out;
if (rule_buf) {
useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
if (copy_to_user(useraddr, rule_buf,
info.rule_cnt * sizeof(u32)))
goto err_out;
}
ret = 0;
err_out:
if (rule_buf)
kfree(rule_buf);
return ret;
}
static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
@@ -901,6 +929,10 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
case ETHTOOL_GFLAGS:
case ETHTOOL_GPFLAGS:
case ETHTOOL_GRXFH:
case ETHTOOL_GRXRINGS:
case ETHTOOL_GRXCLSRLCNT:
case ETHTOOL_GRXCLSRULE:
case ETHTOOL_GRXCLSRLALL:
break;
default:
if (!capable(CAP_NET_ADMIN))
@@ -1052,10 +1084,16 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
dev->ethtool_ops->set_priv_flags);
break;
case ETHTOOL_GRXFH:
rc = ethtool_get_rxhash(dev, useraddr);
case ETHTOOL_GRXRINGS:
case ETHTOOL_GRXCLSRLCNT:
case ETHTOOL_GRXCLSRULE:
case ETHTOOL_GRXCLSRLALL:
rc = ethtool_get_rxnfc(dev, useraddr);
break;
case ETHTOOL_SRXFH:
rc = ethtool_set_rxhash(dev, useraddr);
case ETHTOOL_SRXCLSRLDEL:
case ETHTOOL_SRXCLSRLINS:
rc = ethtool_set_rxnfc(dev, useraddr);
break;
case ETHTOOL_GGRO:
rc = ethtool_get_gro(dev, useraddr);
+2 -1
View File
@@ -588,7 +588,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
goto errout;
}
err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, ops->nlgroup, err);
+9 -6
View File
@@ -871,8 +871,7 @@ static void neigh_timer_handler(unsigned long arg)
write_unlock(&neigh->lock);
neigh->ops->solicit(neigh, skb);
atomic_inc(&neigh->probes);
if (skb)
kfree_skb(skb);
kfree_skb(skb);
} else {
out:
write_unlock(&neigh->lock);
@@ -908,8 +907,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
neigh->updated = jiffies;
write_unlock_bh(&neigh->lock);
if (skb)
kfree_skb(skb);
kfree_skb(skb);
return 1;
}
} else if (neigh->nud_state & NUD_STALE) {
@@ -1656,7 +1654,11 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
flags &= ~NEIGH_UPDATE_F_OVERRIDE;
}
err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
if (ndm->ndm_flags & NTF_USE) {
neigh_event_send(neigh, NULL);
err = 0;
} else
err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
neigh_release(neigh);
goto out_dev_put;
}
@@ -2534,7 +2536,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
+1 -1
View File
@@ -498,7 +498,7 @@ int netdev_register_kobject(struct net_device *net)
dev->groups = groups;
BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
dev_set_name(dev, net->name);
dev_set_name(dev, "%s", net->name);
#ifdef CONFIG_SYSFS
*groups++ = &netstat_group;
+29
View File
@@ -0,0 +1,29 @@
/*
* consolidates trace point definitions
*
* Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
*/
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/string.h>
#include <linux/if_arp.h>
#include <linux/inetdevice.h>
#include <linux/inet.h>
#include <linux/interrupt.h>
#include <linux/netpoll.h>
#include <linux/sched.h>
#include <linux/delay.h>
#include <linux/rcupdate.h>
#include <linux/types.h>
#include <linux/workqueue.h>
#include <linux/netlink.h>
#include <linux/net_dropmon.h>
#include <trace/skb.h>
#include <asm/unaligned.h>
#include <asm/bitops.h>
DEFINE_TRACE(kfree_skb);
EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);
+6 -12
View File
@@ -3275,8 +3275,7 @@ static void pktgen_stop(struct pktgen_thread *t)
list_for_each_entry(pkt_dev, &t->if_list, list) {
pktgen_stop_device(pkt_dev);
if (pkt_dev->skb)
kfree_skb(pkt_dev->skb);
kfree_skb(pkt_dev->skb);
pkt_dev->skb = NULL;
}
@@ -3303,8 +3302,7 @@ static void pktgen_rem_one_if(struct pktgen_thread *t)
if (!cur->removal_mark)
continue;
if (cur->skb)
kfree_skb(cur->skb);
kfree_skb(cur->skb);
cur->skb = NULL;
pktgen_remove_device(t, cur);
@@ -3328,8 +3326,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
list_for_each_safe(q, n, &t->if_list) {
cur = list_entry(q, struct pktgen_dev, list);
if (cur->skb)
kfree_skb(cur->skb);
kfree_skb(cur->skb);
cur->skb = NULL;
pktgen_remove_device(t, cur);
@@ -3393,8 +3390,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
if (!netif_running(odev)) {
pktgen_stop_device(pkt_dev);
if (pkt_dev->skb)
kfree_skb(pkt_dev->skb);
kfree_skb(pkt_dev->skb);
pkt_dev->skb = NULL;
goto out;
}
@@ -3415,8 +3411,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
|| (!pkt_dev->skb)) {
/* build a new pkt */
if (pkt_dev->skb)
kfree_skb(pkt_dev->skb);
kfree_skb(pkt_dev->skb);
pkt_dev->skb = fill_packet(odev, pkt_dev);
if (pkt_dev->skb == NULL) {
@@ -3498,8 +3493,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
/* Done with this */
pktgen_stop_device(pkt_dev);
if (pkt_dev->skb)
kfree_skb(pkt_dev->skb);
kfree_skb(pkt_dev->skb);
pkt_dev->skb = NULL;
}
out:;
+5 -4
View File
@@ -455,8 +455,8 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
return nlmsg_unicast(rtnl, skb, pid);
}
int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
struct nlmsghdr *nlh, gfp_t flags)
void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
struct nlmsghdr *nlh, gfp_t flags)
{
struct sock *rtnl = net->rtnl;
int report = 0;
@@ -464,7 +464,7 @@ int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
if (nlh)
report = nlmsg_report(nlh);
return nlmsg_notify(rtnl, skb, pid, group, report, flags);
nlmsg_notify(rtnl, skb, pid, group, report, flags);
}
void rtnl_set_sk_err(struct net *net, u32 group, int error)
@@ -1246,7 +1246,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
+170 -65
View File
@@ -55,6 +55,7 @@
#include <linux/rtnetlink.h>
#include <linux/init.h>
#include <linux/scatterlist.h>
#include <linux/errqueue.h>
#include <net/protocol.h>
#include <net/dst.h>
@@ -64,6 +65,7 @@
#include <asm/uaccess.h>
#include <asm/system.h>
#include <trace/skb.h>
#include "kmap_skb.h"
@@ -123,6 +125,7 @@ void skb_over_panic(struct sk_buff *skb, int sz, void *here)
skb->dev ? skb->dev->name : "<NULL>");
BUG();
}
EXPORT_SYMBOL(skb_over_panic);
/**
* skb_under_panic - private function
@@ -142,6 +145,7 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
skb->dev ? skb->dev->name : "<NULL>");
BUG();
}
EXPORT_SYMBOL(skb_under_panic);
/* Allocate a new skbuff. We do this ourselves so we can fill in a few
* 'private' fields and also do memory statistics to find all the
@@ -205,7 +209,9 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask,
shinfo->gso_segs = 0;
shinfo->gso_type = 0;
shinfo->ip6_frag_id = 0;
shinfo->tx_flags.flags = 0;
shinfo->frag_list = NULL;
memset(&shinfo->hwtstamps, 0, sizeof(shinfo->hwtstamps));
if (fclone) {
struct sk_buff *child = skb + 1;
@@ -223,6 +229,7 @@ nodata:
skb = NULL;
goto out;
}
EXPORT_SYMBOL(__alloc_skb);
/**
* __netdev_alloc_skb - allocate an skbuff for rx on a specific device
@@ -250,6 +257,7 @@ struct sk_buff *__netdev_alloc_skb(struct net_device *dev,
}
return skb;
}
EXPORT_SYMBOL(__netdev_alloc_skb);
struct page *__netdev_alloc_page(struct net_device *dev, gfp_t gfp_mask)
{
@@ -418,6 +426,7 @@ void __kfree_skb(struct sk_buff *skb)
skb_release_all(skb);
kfree_skbmem(skb);
}
EXPORT_SYMBOL(__kfree_skb);
/**
* kfree_skb - free an sk_buff
@@ -434,8 +443,30 @@ void kfree_skb(struct sk_buff *skb)
smp_rmb();
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
trace_kfree_skb(skb, __builtin_return_address(0));
__kfree_skb(skb);
}
EXPORT_SYMBOL(kfree_skb);
/**
* consume_skb - free an skbuff
* @skb: buffer to free
*
* Drop a ref to the buffer and free it if the usage count has hit zero
* Functions identically to kfree_skb, but kfree_skb assumes that the frame
* is being dropped after a failure and notes that
*/
void consume_skb(struct sk_buff *skb)
{
if (unlikely(!skb))
return;
if (likely(atomic_read(&skb->users) == 1))
smp_rmb();
else if (likely(!atomic_dec_and_test(&skb->users)))
return;
__kfree_skb(skb);
}
EXPORT_SYMBOL(consume_skb);
/**
* skb_recycle_check - check if skb can be reused for receive
@@ -605,6 +636,7 @@ struct sk_buff *skb_clone(struct sk_buff *skb, gfp_t gfp_mask)
return __skb_clone(n, skb);
}
EXPORT_SYMBOL(skb_clone);
static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
{
@@ -671,7 +703,7 @@ struct sk_buff *skb_copy(const struct sk_buff *skb, gfp_t gfp_mask)
copy_skb_header(n, skb);
return n;
}
EXPORT_SYMBOL(skb_copy);
/**
* pskb_copy - create copy of an sk_buff with private head.
@@ -730,6 +762,7 @@ struct sk_buff *pskb_copy(struct sk_buff *skb, gfp_t gfp_mask)
out:
return n;
}
EXPORT_SYMBOL(pskb_copy);
/**
* pskb_expand_head - reallocate header of &sk_buff
@@ -813,6 +846,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
nodata:
return -ENOMEM;
}
EXPORT_SYMBOL(pskb_expand_head);
/* Make private copy of skb with writable head and some headroom */
@@ -833,7 +867,7 @@ struct sk_buff *skb_realloc_headroom(struct sk_buff *skb, unsigned int headroom)
}
return skb2;
}
EXPORT_SYMBOL(skb_realloc_headroom);
/**
* skb_copy_expand - copy and expand sk_buff
@@ -898,6 +932,7 @@ struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
return n;
}
EXPORT_SYMBOL(skb_copy_expand);
/**
* skb_pad - zero pad the tail of an skb
@@ -943,6 +978,7 @@ free_skb:
kfree_skb(skb);
return err;
}
EXPORT_SYMBOL(skb_pad);
/**
* skb_put - add data to a buffer
@@ -1100,6 +1136,7 @@ done:
return 0;
}
EXPORT_SYMBOL(___pskb_trim);
/**
* __pskb_pull_tail - advance tail of skb header
@@ -1193,8 +1230,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
insp = list;
}
if (!pskb_pull(list, eat)) {
if (clone)
kfree_skb(clone);
kfree_skb(clone);
return NULL;
}
break;
@@ -1238,6 +1274,7 @@ pull_pages:
return skb_tail_pointer(skb);
}
EXPORT_SYMBOL(__pskb_pull_tail);
/* Copy some data bits from skb to kernel buffer. */
@@ -1315,6 +1352,7 @@ int skb_copy_bits(const struct sk_buff *skb, int offset, void *to, int len)
fault:
return -EFAULT;
}
EXPORT_SYMBOL(skb_copy_bits);
/*
* Callback from splice_to_pipe(), if we need to release some pages
@@ -1325,14 +1363,39 @@ static void sock_spd_release(struct splice_pipe_desc *spd, unsigned int i)
put_page(spd->pages[i]);
}
static inline struct page *linear_to_page(struct page *page, unsigned int len,
unsigned int offset)
static inline struct page *linear_to_page(struct page *page, unsigned int *len,
unsigned int *offset,
struct sk_buff *skb)
{
struct page *p = alloc_pages(GFP_KERNEL, 0);
struct sock *sk = skb->sk;
struct page *p = sk->sk_sndmsg_page;
unsigned int off;
if (!p)
return NULL;
memcpy(page_address(p) + offset, page_address(page) + offset, len);
if (!p) {
new_page:
p = sk->sk_sndmsg_page = alloc_pages(sk->sk_allocation, 0);
if (!p)
return NULL;
off = sk->sk_sndmsg_off = 0;
/* hold one ref to this page until it's full */
} else {
unsigned int mlen;
off = sk->sk_sndmsg_off;
mlen = PAGE_SIZE - off;
if (mlen < 64 && mlen < *len) {
put_page(p);
goto new_page;
}
*len = min_t(unsigned int, *len, mlen);
}
memcpy(page_address(p) + off, page_address(page) + *offset, *len);
sk->sk_sndmsg_off += *len;
*offset = off;
get_page(p);
return p;
}
@@ -1341,21 +1404,21 @@ static inline struct page *linear_to_page(struct page *page, unsigned int len,
* Fill page/offset/length into spd, if it can hold more pages.
*/
static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,
unsigned int len, unsigned int offset,
unsigned int *len, unsigned int offset,
struct sk_buff *skb, int linear)
{
if (unlikely(spd->nr_pages == PIPE_BUFFERS))
return 1;
if (linear) {
page = linear_to_page(page, len, offset);
page = linear_to_page(page, len, &offset, skb);
if (!page)
return 1;
} else
get_page(page);
spd->pages[spd->nr_pages] = page;
spd->partial[spd->nr_pages].len = len;
spd->partial[spd->nr_pages].len = *len;
spd->partial[spd->nr_pages].offset = offset;
spd->nr_pages++;
@@ -1365,8 +1428,13 @@ static inline int spd_fill_page(struct splice_pipe_desc *spd, struct page *page,
static inline void __segment_seek(struct page **page, unsigned int *poff,
unsigned int *plen, unsigned int off)
{
unsigned long n;
*poff += off;
*page += *poff / PAGE_SIZE;
n = *poff / PAGE_SIZE;
if (n)
*page = nth_page(*page, n);
*poff = *poff % PAGE_SIZE;
*plen -= off;
}
@@ -1397,7 +1465,7 @@ static inline int __splice_segment(struct page *page, unsigned int poff,
/* the linear region may spread across several pages */
flen = min_t(unsigned int, flen, PAGE_SIZE - poff);
if (spd_fill_page(spd, page, flen, poff, skb, linear))
if (spd_fill_page(spd, page, &flen, poff, skb, linear))
return 1;
__segment_seek(&page, &poff, &plen, flen);
@@ -1590,7 +1658,6 @@ int skb_store_bits(struct sk_buff *skb, int offset, const void *from, int len)
fault:
return -EFAULT;
}
EXPORT_SYMBOL(skb_store_bits);
/* Checksum skb data. */
@@ -1667,6 +1734,7 @@ __wsum skb_checksum(const struct sk_buff *skb, int offset,
return csum;
}
EXPORT_SYMBOL(skb_checksum);
/* Both of above in one bottle. */
@@ -1748,6 +1816,7 @@ __wsum skb_copy_and_csum_bits(const struct sk_buff *skb, int offset,
BUG_ON(len);
return csum;
}
EXPORT_SYMBOL(skb_copy_and_csum_bits);
void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
{
@@ -1774,6 +1843,7 @@ void skb_copy_and_csum_dev(const struct sk_buff *skb, u8 *to)
*((__sum16 *)(to + csstuff)) = csum_fold(csum);
}
}
EXPORT_SYMBOL(skb_copy_and_csum_dev);
/**
* skb_dequeue - remove from the head of the queue
@@ -1794,6 +1864,7 @@ struct sk_buff *skb_dequeue(struct sk_buff_head *list)
spin_unlock_irqrestore(&list->lock, flags);
return result;
}
EXPORT_SYMBOL(skb_dequeue);
/**
* skb_dequeue_tail - remove from the tail of the queue
@@ -1813,6 +1884,7 @@ struct sk_buff *skb_dequeue_tail(struct sk_buff_head *list)
spin_unlock_irqrestore(&list->lock, flags);
return result;
}
EXPORT_SYMBOL(skb_dequeue_tail);
/**
* skb_queue_purge - empty a list
@@ -1828,6 +1900,7 @@ void skb_queue_purge(struct sk_buff_head *list)
while ((skb = skb_dequeue(list)) != NULL)
kfree_skb(skb);
}
EXPORT_SYMBOL(skb_queue_purge);
/**
* skb_queue_head - queue a buffer at the list head
@@ -1848,6 +1921,7 @@ void skb_queue_head(struct sk_buff_head *list, struct sk_buff *newsk)
__skb_queue_head(list, newsk);
spin_unlock_irqrestore(&list->lock, flags);
}
EXPORT_SYMBOL(skb_queue_head);
/**
* skb_queue_tail - queue a buffer at the list tail
@@ -1868,6 +1942,7 @@ void skb_queue_tail(struct sk_buff_head *list, struct sk_buff *newsk)
__skb_queue_tail(list, newsk);
spin_unlock_irqrestore(&list->lock, flags);
}
EXPORT_SYMBOL(skb_queue_tail);
/**
* skb_unlink - remove a buffer from a list
@@ -1887,6 +1962,7 @@ void skb_unlink(struct sk_buff *skb, struct sk_buff_head *list)
__skb_unlink(skb, list);
spin_unlock_irqrestore(&list->lock, flags);
}
EXPORT_SYMBOL(skb_unlink);
/**
* skb_append - append a buffer
@@ -1906,7 +1982,7 @@ void skb_append(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head
__skb_queue_after(list, old, newsk);
spin_unlock_irqrestore(&list->lock, flags);
}
EXPORT_SYMBOL(skb_append);
/**
* skb_insert - insert a buffer
@@ -1928,6 +2004,7 @@ void skb_insert(struct sk_buff *old, struct sk_buff *newsk, struct sk_buff_head
__skb_insert(newsk, old->prev, old, list);
spin_unlock_irqrestore(&list->lock, flags);
}
EXPORT_SYMBOL(skb_insert);
static inline void skb_split_inside_header(struct sk_buff *skb,
struct sk_buff* skb1,
@@ -2006,6 +2083,7 @@ void skb_split(struct sk_buff *skb, struct sk_buff *skb1, const u32 len)
else /* Second chunk has no header, nothing to copy. */
skb_split_no_header(skb, skb1, len, pos);
}
EXPORT_SYMBOL(skb_split);
/* Shifting from/to a cloned skb is a no-go.
*
@@ -2168,6 +2246,7 @@ void skb_prepare_seq_read(struct sk_buff *skb, unsigned int from,
st->frag_idx = st->stepped_offset = 0;
st->frag_data = NULL;
}
EXPORT_SYMBOL(skb_prepare_seq_read);
/**
* skb_seq_read - Sequentially read skb data
@@ -2255,6 +2334,7 @@ next_skb:
return 0;
}
EXPORT_SYMBOL(skb_seq_read);
/**
* skb_abort_seq_read - Abort a sequential read of skb data
@@ -2268,6 +2348,7 @@ void skb_abort_seq_read(struct skb_seq_state *st)
if (st->frag_data)
kunmap_skb_frag(st->frag_data);
}
EXPORT_SYMBOL(skb_abort_seq_read);
#define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb))
@@ -2310,6 +2391,7 @@ unsigned int skb_find_text(struct sk_buff *skb, unsigned int from,
ret = textsearch_find(config, state);
return (ret <= to - from ? ret : UINT_MAX);
}
EXPORT_SYMBOL(skb_find_text);
/**
* skb_append_datato_frags: - append the user data to a skb
@@ -2382,6 +2464,7 @@ int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
return 0;
}
EXPORT_SYMBOL(skb_append_datato_frags);
/**
* skb_pull_rcsum - pull skb and update receive checksum
@@ -2569,7 +2652,6 @@ err:
}
return ERR_PTR(err);
}
EXPORT_SYMBOL_GPL(skb_segment);
int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
@@ -2577,17 +2659,23 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
struct sk_buff *p = *head;
struct sk_buff *nskb;
unsigned int headroom;
unsigned int hlen = p->data - skb_mac_header(p);
unsigned int len = skb->len;
unsigned int len = skb_gro_len(skb);
if (hlen + p->len + len >= 65536)
if (p->len + len >= 65536)
return -E2BIG;
if (skb_shinfo(p)->frag_list)
goto merge;
else if (!skb_headlen(p) && !skb_headlen(skb) &&
skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags <
MAX_SKB_FRAGS) {
else if (skb_headlen(skb) <= skb_gro_offset(skb)) {
if (skb_shinfo(p)->nr_frags + skb_shinfo(skb)->nr_frags >
MAX_SKB_FRAGS)
return -E2BIG;
skb_shinfo(skb)->frags[0].page_offset +=
skb_gro_offset(skb) - skb_headlen(skb);
skb_shinfo(skb)->frags[0].size -=
skb_gro_offset(skb) - skb_headlen(skb);
memcpy(skb_shinfo(p)->frags + skb_shinfo(p)->nr_frags,
skb_shinfo(skb)->frags,
skb_shinfo(skb)->nr_frags * sizeof(skb_frag_t));
@@ -2604,7 +2692,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
}
headroom = skb_headroom(p);
nskb = netdev_alloc_skb(p->dev, headroom);
nskb = netdev_alloc_skb(p->dev, headroom + skb_gro_offset(p));
if (unlikely(!nskb))
return -ENOMEM;
@@ -2612,12 +2700,15 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
nskb->mac_len = p->mac_len;
skb_reserve(nskb, headroom);
__skb_put(nskb, skb_gro_offset(p));
skb_set_mac_header(nskb, -hlen);
skb_set_mac_header(nskb, skb_mac_header(p) - p->data);
skb_set_network_header(nskb, skb_network_offset(p));
skb_set_transport_header(nskb, skb_transport_offset(p));
memcpy(skb_mac_header(nskb), skb_mac_header(p), hlen);
__skb_pull(p, skb_gro_offset(p));
memcpy(skb_mac_header(nskb), skb_mac_header(p),
p->data - skb_mac_header(p));
*NAPI_GRO_CB(nskb) = *NAPI_GRO_CB(p);
skb_shinfo(nskb)->frag_list = p;
@@ -2636,6 +2727,17 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
p = nskb;
merge:
if (skb_gro_offset(skb) > skb_headlen(skb)) {
skb_shinfo(skb)->frags[0].page_offset +=
skb_gro_offset(skb) - skb_headlen(skb);
skb_shinfo(skb)->frags[0].size -=
skb_gro_offset(skb) - skb_headlen(skb);
skb_gro_reset_offset(skb);
skb_gro_pull(skb, skb_headlen(skb));
}
__skb_pull(skb, skb_gro_offset(skb));
p->prev->next = skb;
p->prev = skb;
skb_header_release(skb);
@@ -2747,6 +2849,7 @@ int skb_to_sgvec(struct sk_buff *skb, struct scatterlist *sg, int offset, int le
return nsg;
}
EXPORT_SYMBOL_GPL(skb_to_sgvec);
/**
* skb_cow_data - Check that a socket buffer's data buffers are writable
@@ -2856,6 +2959,45 @@ int skb_cow_data(struct sk_buff *skb, int tailbits, struct sk_buff **trailer)
return elt;
}
EXPORT_SYMBOL_GPL(skb_cow_data);
void skb_tstamp_tx(struct sk_buff *orig_skb,
struct skb_shared_hwtstamps *hwtstamps)
{
struct sock *sk = orig_skb->sk;
struct sock_exterr_skb *serr;
struct sk_buff *skb;
int err;
if (!sk)
return;
skb = skb_clone(orig_skb, GFP_ATOMIC);
if (!skb)
return;
if (hwtstamps) {
*skb_hwtstamps(skb) =
*hwtstamps;
} else {
/*
* no hardware time stamps available,
* so keep the skb_shared_tx and only
* store software time stamp
*/
skb->tstamp = ktime_get_real();
}
serr = SKB_EXT_ERR(skb);
memset(serr, 0, sizeof(*serr));
serr->ee.ee_errno = ENOMSG;
serr->ee.ee_origin = SO_EE_ORIGIN_TIMESTAMPING;
err = sock_queue_err_skb(sk, skb);
if (err)
kfree_skb(skb);
}
EXPORT_SYMBOL_GPL(skb_tstamp_tx);
/**
* skb_partial_csum_set - set up and verify partial csum values for packet
@@ -2884,6 +3026,7 @@ bool skb_partial_csum_set(struct sk_buff *skb, u16 start, u16 off)
skb->csum_offset = off;
return true;
}
EXPORT_SYMBOL_GPL(skb_partial_csum_set);
void __skb_warn_lro_forwarding(const struct sk_buff *skb)
{
@@ -2891,42 +3034,4 @@ void __skb_warn_lro_forwarding(const struct sk_buff *skb)
pr_warning("%s: received packets cannot be forwarded"
" while LRO is enabled\n", skb->dev->name);
}
EXPORT_SYMBOL(___pskb_trim);
EXPORT_SYMBOL(__kfree_skb);
EXPORT_SYMBOL(kfree_skb);
EXPORT_SYMBOL(__pskb_pull_tail);
EXPORT_SYMBOL(__alloc_skb);
EXPORT_SYMBOL(__netdev_alloc_skb);
EXPORT_SYMBOL(pskb_copy);
EXPORT_SYMBOL(pskb_expand_head);
EXPORT_SYMBOL(skb_checksum);
EXPORT_SYMBOL(skb_clone);
EXPORT_SYMBOL(skb_copy);
EXPORT_SYMBOL(skb_copy_and_csum_bits);
EXPORT_SYMBOL(skb_copy_and_csum_dev);
EXPORT_SYMBOL(skb_copy_bits);
EXPORT_SYMBOL(skb_copy_expand);
EXPORT_SYMBOL(skb_over_panic);
EXPORT_SYMBOL(skb_pad);
EXPORT_SYMBOL(skb_realloc_headroom);
EXPORT_SYMBOL(skb_under_panic);
EXPORT_SYMBOL(skb_dequeue);
EXPORT_SYMBOL(skb_dequeue_tail);
EXPORT_SYMBOL(skb_insert);
EXPORT_SYMBOL(skb_queue_purge);
EXPORT_SYMBOL(skb_queue_head);
EXPORT_SYMBOL(skb_queue_tail);
EXPORT_SYMBOL(skb_unlink);
EXPORT_SYMBOL(skb_append);
EXPORT_SYMBOL(skb_split);
EXPORT_SYMBOL(skb_prepare_seq_read);
EXPORT_SYMBOL(skb_seq_read);
EXPORT_SYMBOL(skb_abort_seq_read);
EXPORT_SYMBOL(skb_find_text);
EXPORT_SYMBOL(skb_append_datato_frags);
EXPORT_SYMBOL(__skb_warn_lro_forwarding);
EXPORT_SYMBOL_GPL(skb_to_sgvec);
EXPORT_SYMBOL_GPL(skb_cow_data);
EXPORT_SYMBOL_GPL(skb_partial_csum_set);
+76 -19
View File
@@ -120,6 +120,7 @@
#include <net/net_namespace.h>
#include <net/request_sock.h>
#include <net/sock.h>
#include <linux/net_tstamp.h>
#include <net/xfrm.h>
#include <linux/ipsec.h>
@@ -149,7 +150,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
"sk_lock-AF_DECnet", "sk_lock-AF_NETBEUI" , "sk_lock-AF_SECURITY" ,
"sk_lock-AF_KEY" , "sk_lock-AF_NETLINK" , "sk_lock-AF_PACKET" ,
"sk_lock-AF_ASH" , "sk_lock-AF_ECONET" , "sk_lock-AF_ATMSVC" ,
"sk_lock-21" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" ,
"sk_lock-AF_RDS" , "sk_lock-AF_SNA" , "sk_lock-AF_IRDA" ,
"sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE" , "sk_lock-AF_LLC" ,
"sk_lock-27" , "sk_lock-28" , "sk_lock-AF_CAN" ,
"sk_lock-AF_TIPC" , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV" ,
@@ -164,7 +165,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
"slock-AF_DECnet", "slock-AF_NETBEUI" , "slock-AF_SECURITY" ,
"slock-AF_KEY" , "slock-AF_NETLINK" , "slock-AF_PACKET" ,
"slock-AF_ASH" , "slock-AF_ECONET" , "slock-AF_ATMSVC" ,
"slock-21" , "slock-AF_SNA" , "slock-AF_IRDA" ,
"slock-AF_RDS" , "slock-AF_SNA" , "slock-AF_IRDA" ,
"slock-AF_PPPOX" , "slock-AF_WANPIPE" , "slock-AF_LLC" ,
"slock-27" , "slock-28" , "slock-AF_CAN" ,
"slock-AF_TIPC" , "slock-AF_BLUETOOTH", "slock-AF_IUCV" ,
@@ -179,7 +180,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
"clock-AF_DECnet", "clock-AF_NETBEUI" , "clock-AF_SECURITY" ,
"clock-AF_KEY" , "clock-AF_NETLINK" , "clock-AF_PACKET" ,
"clock-AF_ASH" , "clock-AF_ECONET" , "clock-AF_ATMSVC" ,
"clock-21" , "clock-AF_SNA" , "clock-AF_IRDA" ,
"clock-AF_RDS" , "clock-AF_SNA" , "clock-AF_IRDA" ,
"clock-AF_PPPOX" , "clock-AF_WANPIPE" , "clock-AF_LLC" ,
"clock-27" , "clock-28" , "clock-AF_CAN" ,
"clock-AF_TIPC" , "clock-AF_BLUETOOTH", "clock-AF_IUCV" ,
@@ -255,11 +256,14 @@ static void sock_warn_obsolete_bsdism(const char *name)
}
}
static void sock_disable_timestamp(struct sock *sk)
static void sock_disable_timestamp(struct sock *sk, int flag)
{
if (sock_flag(sk, SOCK_TIMESTAMP)) {
sock_reset_flag(sk, SOCK_TIMESTAMP);
net_disable_timestamp();
if (sock_flag(sk, flag)) {
sock_reset_flag(sk, flag);
if (!sock_flag(sk, SOCK_TIMESTAMP) &&
!sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE)) {
net_disable_timestamp();
}
}
}
@@ -614,13 +618,38 @@ set_rcvbuf:
else
sock_set_flag(sk, SOCK_RCVTSTAMPNS);
sock_set_flag(sk, SOCK_RCVTSTAMP);
sock_enable_timestamp(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
} else {
sock_reset_flag(sk, SOCK_RCVTSTAMP);
sock_reset_flag(sk, SOCK_RCVTSTAMPNS);
}
break;
case SO_TIMESTAMPING:
if (val & ~SOF_TIMESTAMPING_MASK) {
ret = EINVAL;
break;
}
sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE,
val & SOF_TIMESTAMPING_TX_HARDWARE);
sock_valbool_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE,
val & SOF_TIMESTAMPING_TX_SOFTWARE);
sock_valbool_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE,
val & SOF_TIMESTAMPING_RX_HARDWARE);
if (val & SOF_TIMESTAMPING_RX_SOFTWARE)
sock_enable_timestamp(sk,
SOCK_TIMESTAMPING_RX_SOFTWARE);
else
sock_disable_timestamp(sk,
SOCK_TIMESTAMPING_RX_SOFTWARE);
sock_valbool_flag(sk, SOCK_TIMESTAMPING_SOFTWARE,
val & SOF_TIMESTAMPING_SOFTWARE);
sock_valbool_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE,
val & SOF_TIMESTAMPING_SYS_HARDWARE);
sock_valbool_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE,
val & SOF_TIMESTAMPING_RAW_HARDWARE);
break;
case SO_RCVLOWAT:
if (val < 0)
val = INT_MAX;
@@ -768,6 +797,24 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
v.val = sock_flag(sk, SOCK_RCVTSTAMPNS);
break;
case SO_TIMESTAMPING:
v.val = 0;
if (sock_flag(sk, SOCK_TIMESTAMPING_TX_HARDWARE))
v.val |= SOF_TIMESTAMPING_TX_HARDWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_TX_SOFTWARE))
v.val |= SOF_TIMESTAMPING_TX_SOFTWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_RX_HARDWARE))
v.val |= SOF_TIMESTAMPING_RX_HARDWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_RX_SOFTWARE))
v.val |= SOF_TIMESTAMPING_RX_SOFTWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_SOFTWARE))
v.val |= SOF_TIMESTAMPING_SOFTWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_SYS_HARDWARE))
v.val |= SOF_TIMESTAMPING_SYS_HARDWARE;
if (sock_flag(sk, SOCK_TIMESTAMPING_RAW_HARDWARE))
v.val |= SOF_TIMESTAMPING_RAW_HARDWARE;
break;
case SO_RCVTIMEO:
lv=sizeof(struct timeval);
if (sk->sk_rcvtimeo == MAX_SCHEDULE_TIMEOUT) {
@@ -969,7 +1016,8 @@ void sk_free(struct sock *sk)
rcu_assign_pointer(sk->sk_filter, NULL);
}
sock_disable_timestamp(sk);
sock_disable_timestamp(sk, SOCK_TIMESTAMP);
sock_disable_timestamp(sk, SOCK_TIMESTAMPING_RX_SOFTWARE);
if (atomic_read(&sk->sk_omem_alloc))
printk(KERN_DEBUG "%s: optmem leakage (%d bytes) detected.\n",
@@ -1255,10 +1303,9 @@ static long sock_wait_for_wmem(struct sock * sk, long timeo)
* Generic send/receive buffer handlers
*/
static struct sk_buff *sock_alloc_send_pskb(struct sock *sk,
unsigned long header_len,
unsigned long data_len,
int noblock, int *errcode)
struct sk_buff *sock_alloc_send_pskb(struct sock *sk, unsigned long header_len,
unsigned long data_len, int noblock,
int *errcode)
{
struct sk_buff *skb;
gfp_t gfp_mask;
@@ -1338,6 +1385,7 @@ failure:
*errcode = err;
return NULL;
}
EXPORT_SYMBOL(sock_alloc_send_pskb);
struct sk_buff *sock_alloc_send_skb(struct sock *sk, unsigned long size,
int noblock, int *errcode)
@@ -1786,7 +1834,7 @@ int sock_get_timestamp(struct sock *sk, struct timeval __user *userstamp)
{
struct timeval tv;
if (!sock_flag(sk, SOCK_TIMESTAMP))
sock_enable_timestamp(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
tv = ktime_to_timeval(sk->sk_stamp);
if (tv.tv_sec == -1)
return -ENOENT;
@@ -1802,7 +1850,7 @@ int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
{
struct timespec ts;
if (!sock_flag(sk, SOCK_TIMESTAMP))
sock_enable_timestamp(sk);
sock_enable_timestamp(sk, SOCK_TIMESTAMP);
ts = ktime_to_timespec(sk->sk_stamp);
if (ts.tv_sec == -1)
return -ENOENT;
@@ -1814,11 +1862,20 @@ int sock_get_timestampns(struct sock *sk, struct timespec __user *userstamp)
}
EXPORT_SYMBOL(sock_get_timestampns);
void sock_enable_timestamp(struct sock *sk)
void sock_enable_timestamp(struct sock *sk, int flag)
{
if (!sock_flag(sk, SOCK_TIMESTAMP)) {
sock_set_flag(sk, SOCK_TIMESTAMP);
net_enable_timestamp();
if (!sock_flag(sk, flag)) {
sock_set_flag(sk, flag);
/*
* we just set one of the two flags which require net
* time stamping, but time stamping might have been on
* already because of the other one
*/
if (!sock_flag(sk,
flag == SOCK_TIMESTAMP ?
SOCK_TIMESTAMPING_RX_SOFTWARE :
SOCK_TIMESTAMP))
net_enable_timestamp();
}
}
+1
View File
@@ -11,6 +11,7 @@
#include <linux/socket.h>
#include <linux/netdevice.h>
#include <linux/init.h>
#include <net/ip.h>
#include <net/sock.h>
static struct ctl_table net_core_table[] = {
-1
View File
@@ -22,7 +22,6 @@
#include <linux/net.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/random.h>
#include <linux/percpu.h>
#include <linux/init.h>
#include <net/sock.h>
+3
View File
@@ -20,6 +20,9 @@
/* We can spread an ack vector across multiple options */
#define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
/* Estimated minimum average Ack Vector length - used for updating MPS */
#define DCCPAV_MIN_OPTLEN 16
#define DCCP_ACKVEC_STATE_RECEIVED 0
#define DCCP_ACKVEC_STATE_ECN_MARKED (1 << 6)
#define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6)
+13 -13
View File
@@ -42,9 +42,11 @@
extern int dccp_debug;
#define dccp_pr_debug(format, a...) DCCP_PR_DEBUG(dccp_debug, format, ##a)
#define dccp_pr_debug_cat(format, a...) DCCP_PRINTK(dccp_debug, format, ##a)
#define dccp_debug(fmt, a...) dccp_pr_debug_cat(KERN_DEBUG fmt, ##a)
#else
#define dccp_pr_debug(format, a...)
#define dccp_pr_debug_cat(format, a...)
#define dccp_debug(format, a...)
#endif
extern struct inet_hashinfo dccp_hashinfo;
@@ -61,11 +63,14 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
* - DCCP-Reset with ACK Subheader and 4 bytes of Reset Code fields
* Hence a safe upper bound for the maximum option length is 1020-28 = 992
*/
#define MAX_DCCP_SPECIFIC_HEADER (255 * sizeof(int))
#define MAX_DCCP_SPECIFIC_HEADER (255 * sizeof(uint32_t))
#define DCCP_MAX_PACKET_HDR 28
#define DCCP_MAX_OPT_LEN (MAX_DCCP_SPECIFIC_HEADER - DCCP_MAX_PACKET_HDR)
#define MAX_DCCP_HEADER (MAX_DCCP_SPECIFIC_HEADER + MAX_HEADER)
/* Upper bound for initial feature-negotiation overhead (padded to 32 bits) */
#define DCCP_FEATNEG_OVERHEAD (32 * sizeof(uint32_t))
#define DCCP_TIMEWAIT_LEN (60 * HZ) /* how long to wait to destroy TIME-WAIT
* state, about 60 seconds */
@@ -95,9 +100,6 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
extern int sysctl_dccp_request_retries;
extern int sysctl_dccp_retries1;
extern int sysctl_dccp_retries2;
extern int sysctl_dccp_feat_sequence_window;
extern int sysctl_dccp_feat_rx_ccid;
extern int sysctl_dccp_feat_tx_ccid;
extern int sysctl_dccp_tx_qlen;
extern int sysctl_dccp_sync_ratelimit;
@@ -409,23 +411,21 @@ static inline void dccp_hdr_set_ack(struct dccp_hdr_ack_bits *dhack,
static inline void dccp_update_gsr(struct sock *sk, u64 seq)
{
struct dccp_sock *dp = dccp_sk(sk);
const struct dccp_minisock *dmsk = dccp_msk(sk);
dp->dccps_gsr = seq;
dccp_set_seqno(&dp->dccps_swl,
dp->dccps_gsr + 1 - (dmsk->dccpms_sequence_window / 4));
dccp_set_seqno(&dp->dccps_swh,
dp->dccps_gsr + (3 * dmsk->dccpms_sequence_window) / 4);
/* Sequence validity window depends on remote Sequence Window (7.5.1) */
dp->dccps_swl = SUB48(ADD48(dp->dccps_gsr, 1), dp->dccps_r_seq_win / 4);
dp->dccps_swh = ADD48(dp->dccps_gsr, (3 * dp->dccps_r_seq_win) / 4);
}
static inline void dccp_update_gss(struct sock *sk, u64 seq)
{
struct dccp_sock *dp = dccp_sk(sk);
dp->dccps_awh = dp->dccps_gss = seq;
dccp_set_seqno(&dp->dccps_awl,
(dp->dccps_gss -
dccp_msk(sk)->dccpms_sequence_window + 1));
dp->dccps_gss = seq;
/* Ack validity window depends on local Sequence Window value (7.5.1) */
dp->dccps_awl = SUB48(ADD48(dp->dccps_gss, 1), dp->dccps_l_seq_win);
dp->dccps_awh = dp->dccps_gss;
}
static inline int dccp_ack_pending(const struct sock *sk)
+179 -53
View File
@@ -25,6 +25,11 @@
#include "ccid.h"
#include "feat.h"
/* feature-specific sysctls - initialised to the defaults from RFC 4340, 6.4 */
unsigned long sysctl_dccp_sequence_window __read_mostly = 100;
int sysctl_dccp_rx_ccid __read_mostly = 2,
sysctl_dccp_tx_ccid __read_mostly = 2;
/*
* Feature activation handlers.
*
@@ -51,8 +56,17 @@ static int dccp_hdlr_ccid(struct sock *sk, u64 ccid, bool rx)
static int dccp_hdlr_seq_win(struct sock *sk, u64 seq_win, bool rx)
{
if (!rx)
dccp_msk(sk)->dccpms_sequence_window = seq_win;
struct dccp_sock *dp = dccp_sk(sk);
if (rx) {
dp->dccps_r_seq_win = seq_win;
/* propagate changes to update SWL/SWH */
dccp_update_gsr(sk, dp->dccps_gsr);
} else {
dp->dccps_l_seq_win = seq_win;
/* propagate changes to update AWL */
dccp_update_gss(sk, dp->dccps_gss);
}
return 0;
}
@@ -194,6 +208,100 @@ static int dccp_feat_default_value(u8 feat_num)
return idx < 0 ? 0 : dccp_feat_table[idx].default_value;
}
/*
* Debugging and verbose-printing section
*/
static const char *dccp_feat_fname(const u8 feat)
{
static const char *feature_names[] = {
[DCCPF_RESERVED] = "Reserved",
[DCCPF_CCID] = "CCID",
[DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos",
[DCCPF_SEQUENCE_WINDOW] = "Sequence Window",
[DCCPF_ECN_INCAPABLE] = "ECN Incapable",
[DCCPF_ACK_RATIO] = "Ack Ratio",
[DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector",
[DCCPF_SEND_NDP_COUNT] = "Send NDP Count",
[DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage",
[DCCPF_DATA_CHECKSUM] = "Send Data Checksum",
};
if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
return feature_names[DCCPF_RESERVED];
if (feat == DCCPF_SEND_LEV_RATE)
return "Send Loss Event Rate";
if (feat >= DCCPF_MIN_CCID_SPECIFIC)
return "CCID-specific";
return feature_names[feat];
}
static const char *dccp_feat_sname[] = { "DEFAULT", "INITIALISING", "CHANGING",
"UNSTABLE", "STABLE" };
#ifdef CONFIG_IP_DCCP_DEBUG
static const char *dccp_feat_oname(const u8 opt)
{
switch (opt) {
case DCCPO_CHANGE_L: return "Change_L";
case DCCPO_CONFIRM_L: return "Confirm_L";
case DCCPO_CHANGE_R: return "Change_R";
case DCCPO_CONFIRM_R: return "Confirm_R";
}
return NULL;
}
static void dccp_feat_printval(u8 feat_num, dccp_feat_val const *val)
{
u8 i, type = dccp_feat_type(feat_num);
if (val == NULL || (type == FEAT_SP && val->sp.vec == NULL))
dccp_pr_debug_cat("(NULL)");
else if (type == FEAT_SP)
for (i = 0; i < val->sp.len; i++)
dccp_pr_debug_cat("%s%u", i ? " " : "", val->sp.vec[i]);
else if (type == FEAT_NN)
dccp_pr_debug_cat("%llu", (unsigned long long)val->nn);
else
dccp_pr_debug_cat("unknown type %u", type);
}
static void dccp_feat_printvals(u8 feat_num, u8 *list, u8 len)
{
u8 type = dccp_feat_type(feat_num);
dccp_feat_val fval = { .sp.vec = list, .sp.len = len };
if (type == FEAT_NN)
fval.nn = dccp_decode_value_var(list, len);
dccp_feat_printval(feat_num, &fval);
}
static void dccp_feat_print_entry(struct dccp_feat_entry const *entry)
{
dccp_debug(" * %s %s = ", entry->is_local ? "local" : "remote",
dccp_feat_fname(entry->feat_num));
dccp_feat_printval(entry->feat_num, &entry->val);
dccp_pr_debug_cat(", state=%s %s\n", dccp_feat_sname[entry->state],
entry->needs_confirm ? "(Confirm pending)" : "");
}
#define dccp_feat_print_opt(opt, feat, val, len, mandatory) do { \
dccp_pr_debug("%s(%s, ", dccp_feat_oname(opt), dccp_feat_fname(feat));\
dccp_feat_printvals(feat, val, len); \
dccp_pr_debug_cat(") %s\n", mandatory ? "!" : ""); } while (0)
#define dccp_feat_print_fnlist(fn_list) { \
const struct dccp_feat_entry *___entry; \
\
dccp_pr_debug("List Dump:\n"); \
list_for_each_entry(___entry, fn_list, node) \
dccp_feat_print_entry(___entry); \
}
#else /* ! CONFIG_IP_DCCP_DEBUG */
#define dccp_feat_print_opt(opt, feat, val, len, mandatory)
#define dccp_feat_print_fnlist(fn_list)
#endif
static int __dccp_feat_activate(struct sock *sk, const int idx,
const bool is_local, dccp_feat_val const *fval)
{
@@ -226,6 +334,10 @@ static int __dccp_feat_activate(struct sock *sk, const int idx,
/* Location is RX if this is a local-RX or remote-TX feature */
rx = (is_local == (dccp_feat_table[idx].rxtx == FEAT_AT_RX));
dccp_debug(" -> activating %s %s, %sval=%llu\n", rx ? "RX" : "TX",
dccp_feat_fname(dccp_feat_table[idx].feat_num),
fval ? "" : "default ", (unsigned long long)val);
return dccp_feat_table[idx].activation_hdlr(sk, val, rx);
}
@@ -530,6 +642,7 @@ int dccp_feat_insert_opts(struct dccp_sock *dp, struct dccp_request_sock *dreq,
return -1;
}
}
dccp_feat_print_opt(opt, pos->feat_num, ptr, len, 0);
if (dccp_insert_fn_opt(skb, opt, pos->feat_num, ptr, len, rpt))
return -1;
@@ -783,6 +896,7 @@ int dccp_feat_finalise_settings(struct dccp_sock *dp)
while (i--)
if (ccids[i] > 0 && dccp_feat_propagate_ccid(fn, ccids[i], i))
return -1;
dccp_feat_print_fnlist(fn);
return 0;
}
@@ -901,6 +1015,8 @@ static u8 dccp_feat_change_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
if (len == 0 || type == FEAT_UNKNOWN) /* 6.1 and 6.6.8 */
goto unknown_feature_or_value;
dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
/*
* Negotiation of NN features: Change R is invalid, so there is no
* simultaneous negotiation; hence we do not look up in the list.
@@ -1006,6 +1122,8 @@ static u8 dccp_feat_confirm_recv(struct list_head *fn, u8 is_mandatory, u8 opt,
const bool local = (opt == DCCPO_CONFIRM_R);
struct dccp_feat_entry *entry = dccp_feat_list_lookup(fn, feat, local);
dccp_feat_print_opt(opt, feat, val, len, is_mandatory);
if (entry == NULL) { /* nothing queued: ignore or handle error */
if (is_mandatory && type == FEAT_UNKNOWN)
return DCCP_RESET_CODE_MANDATORY_ERROR;
@@ -1115,23 +1233,70 @@ int dccp_feat_parse_options(struct sock *sk, struct dccp_request_sock *dreq,
return 0; /* ignore FN options in all other states */
}
/**
* dccp_feat_init - Seed feature negotiation with host-specific defaults
* This initialises global defaults, depending on the value of the sysctls.
* These can later be overridden by registering changes via setsockopt calls.
* The last link in the chain is finalise_settings, to make sure that between
* here and the start of actual feature negotiation no inconsistencies enter.
*
* All features not appearing below use either defaults or are otherwise
* later adjusted through dccp_feat_finalise_settings().
*/
int dccp_feat_init(struct sock *sk)
{
struct dccp_sock *dp = dccp_sk(sk);
struct dccp_minisock *dmsk = dccp_msk(sk);
struct list_head *fn = &dccp_sk(sk)->dccps_featneg;
u8 on = 1, off = 0;
int rc;
struct {
u8 *val;
u8 len;
} tx, rx;
INIT_LIST_HEAD(&dmsk->dccpms_pending); /* XXX no longer used */
INIT_LIST_HEAD(&dmsk->dccpms_conf); /* XXX no longer used */
/* Non-negotiable (NN) features */
rc = __feat_register_nn(fn, DCCPF_SEQUENCE_WINDOW, 0,
sysctl_dccp_sequence_window);
if (rc)
return rc;
/* Ack ratio */
rc = __feat_register_nn(&dp->dccps_featneg, DCCPF_ACK_RATIO, 0,
dp->dccps_l_ack_ratio);
/* Server-priority (SP) features */
/* Advertise that short seqnos are not supported (7.6.1) */
rc = __feat_register_sp(fn, DCCPF_SHORT_SEQNOS, true, true, &off, 1);
if (rc)
return rc;
/* RFC 4340 12.1: "If a DCCP is not ECN capable, ..." */
rc = __feat_register_sp(fn, DCCPF_ECN_INCAPABLE, true, true, &on, 1);
if (rc)
return rc;
/*
* We advertise the available list of CCIDs and reorder according to
* preferences, to avoid failure resulting from negotiating different
* singleton values (which always leads to failure).
* These settings can still (later) be overridden via sockopts.
*/
if (ccid_get_builtin_ccids(&tx.val, &tx.len) ||
ccid_get_builtin_ccids(&rx.val, &rx.len))
return -ENOBUFS;
if (!dccp_feat_prefer(sysctl_dccp_tx_ccid, tx.val, tx.len) ||
!dccp_feat_prefer(sysctl_dccp_rx_ccid, rx.val, rx.len))
goto free_ccid_lists;
rc = __feat_register_sp(fn, DCCPF_CCID, true, false, tx.val, tx.len);
if (rc)
goto free_ccid_lists;
rc = __feat_register_sp(fn, DCCPF_CCID, false, false, rx.val, rx.len);
free_ccid_lists:
kfree(tx.val);
kfree(rx.val);
return rc;
}
EXPORT_SYMBOL_GPL(dccp_feat_init);
int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
{
struct dccp_sock *dp = dccp_sk(sk);
@@ -1156,9 +1321,10 @@ int dccp_feat_activate_values(struct sock *sk, struct list_head *fn_list)
goto activation_failed;
}
if (cur->state != FEAT_STABLE) {
DCCP_CRIT("Negotiation of %s %u failed in state %u",
DCCP_CRIT("Negotiation of %s %s failed in state %s",
cur->is_local ? "local" : "remote",
cur->feat_num, cur->state);
dccp_feat_fname(cur->feat_num),
dccp_feat_sname[cur->state]);
goto activation_failed;
}
fvals[idx][cur->is_local] = &cur->val;
@@ -1199,43 +1365,3 @@ activation_failed:
dp->dccps_hc_rx_ackvec = NULL;
return -1;
}
#ifdef CONFIG_IP_DCCP_DEBUG
const char *dccp_feat_typename(const u8 type)
{
switch(type) {
case DCCPO_CHANGE_L: return("ChangeL");
case DCCPO_CONFIRM_L: return("ConfirmL");
case DCCPO_CHANGE_R: return("ChangeR");
case DCCPO_CONFIRM_R: return("ConfirmR");
/* the following case must not appear in feature negotation */
default: dccp_pr_debug("unknown type %d [BUG!]\n", type);
}
return NULL;
}
const char *dccp_feat_name(const u8 feat)
{
static const char *feature_names[] = {
[DCCPF_RESERVED] = "Reserved",
[DCCPF_CCID] = "CCID",
[DCCPF_SHORT_SEQNOS] = "Allow Short Seqnos",
[DCCPF_SEQUENCE_WINDOW] = "Sequence Window",
[DCCPF_ECN_INCAPABLE] = "ECN Incapable",
[DCCPF_ACK_RATIO] = "Ack Ratio",
[DCCPF_SEND_ACK_VECTOR] = "Send ACK Vector",
[DCCPF_SEND_NDP_COUNT] = "Send NDP Count",
[DCCPF_MIN_CSUM_COVER] = "Min. Csum Coverage",
[DCCPF_DATA_CHECKSUM] = "Send Data Checksum",
};
if (feat > DCCPF_DATA_CHECKSUM && feat < DCCPF_MIN_CCID_SPECIFIC)
return feature_names[DCCPF_RESERVED];
if (feat == DCCPF_SEND_LEV_RATE)
return "Send Loss Event Rate";
if (feat >= DCCPF_MIN_CCID_SPECIFIC)
return "CCID-specific";
return feature_names[feat];
}
#endif /* CONFIG_IP_DCCP_DEBUG */
+8 -13
View File
@@ -100,26 +100,21 @@ struct ccid_dependency {
u8 val;
};
#ifdef CONFIG_IP_DCCP_DEBUG
extern const char *dccp_feat_typename(const u8 type);
extern const char *dccp_feat_name(const u8 feat);
static inline void dccp_feat_debug(const u8 type, const u8 feat, const u8 val)
{
dccp_pr_debug("%s(%s (%d), %d)\n", dccp_feat_typename(type),
dccp_feat_name(feat), feat, val);
}
#else
#define dccp_feat_debug(type, feat, val)
#endif /* CONFIG_IP_DCCP_DEBUG */
/*
* Sysctls to seed defaults for feature negotiation
*/
extern unsigned long sysctl_dccp_sequence_window;
extern int sysctl_dccp_rx_ccid;
extern int sysctl_dccp_tx_ccid;
extern int dccp_feat_init(struct sock *sk);
extern void dccp_feat_initialise_sysctls(void);
extern int dccp_feat_register_sp(struct sock *sk, u8 feat, u8 is_local,
u8 const *list, u8 len);
extern int dccp_feat_register_nn(struct sock *sk, u8 feat, u64 val);
extern int dccp_feat_parse_options(struct sock *, struct dccp_request_sock *,
u8 mand, u8 opt, u8 feat, u8 *val, u8 len);
extern int dccp_feat_clone_list(struct list_head const *, struct list_head *);
extern int dccp_feat_init(struct sock *sk);
/*
* Encoding variable-length options and their maximum length.
-11
View File
@@ -42,11 +42,6 @@ struct inet_timewait_death_row dccp_death_row = {
EXPORT_SYMBOL_GPL(dccp_death_row);
void dccp_minisock_init(struct dccp_minisock *dmsk)
{
dmsk->dccpms_sequence_window = sysctl_dccp_feat_sequence_window;
}
void dccp_time_wait(struct sock *sk, int state, int timeo)
{
struct inet_timewait_sock *tw = NULL;
@@ -110,7 +105,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
struct dccp_request_sock *dreq = dccp_rsk(req);
struct inet_connection_sock *newicsk = inet_csk(newsk);
struct dccp_sock *newdp = dccp_sk(newsk);
struct dccp_minisock *newdmsk = dccp_msk(newsk);
newdp->dccps_role = DCCP_ROLE_SERVER;
newdp->dccps_hc_rx_ackvec = NULL;
@@ -128,10 +122,6 @@ struct sock *dccp_create_openreq_child(struct sock *sk,
* Initialize S.GAR := S.ISS
* Set S.ISR, S.GSR, S.SWL, S.SWH from packet or Init Cookies
*/
/* See dccp_v4_conn_request */
newdmsk->dccpms_sequence_window = req->rcv_wnd;
newdp->dccps_gar = newdp->dccps_iss = dreq->dreq_iss;
dccp_update_gss(newsk, dreq->dreq_iss);
@@ -290,7 +280,6 @@ int dccp_reqsk_init(struct request_sock *req,
inet_rsk(req)->rmt_port = dccp_hdr(skb)->dccph_sport;
inet_rsk(req)->loc_port = dccp_hdr(skb)->dccph_dport;
inet_rsk(req)->acked = 0;
req->rcv_wnd = sysctl_dccp_feat_sequence_window;
dreq->dreq_timestamp_echo = 0;
/* inherit feature negotiation options from listening socket */
-8
View File
@@ -23,10 +23,6 @@
#include "dccp.h"
#include "feat.h"
int sysctl_dccp_feat_sequence_window = DCCPF_INITIAL_SEQUENCE_WINDOW;
int sysctl_dccp_feat_rx_ccid = DCCPF_INITIAL_CCID;
int sysctl_dccp_feat_tx_ccid = DCCPF_INITIAL_CCID;
u64 dccp_decode_value_var(const u8 *bf, const u8 len)
{
u64 value = 0;
@@ -502,10 +498,6 @@ int dccp_insert_fn_opt(struct sk_buff *skb, u8 type, u8 feat,
*to++ = *val;
if (len)
memcpy(to, val, len);
dccp_pr_debug("%s(%s (%d), ...), length %d\n",
dccp_feat_typename(type),
dccp_feat_name(feat), feat, len);
return 0;
}
+28 -9
View File
@@ -161,21 +161,27 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
struct inet_connection_sock *icsk = inet_csk(sk);
struct dccp_sock *dp = dccp_sk(sk);
u32 ccmps = dccp_determine_ccmps(dp);
int cur_mps = ccmps ? min(pmtu, ccmps) : pmtu;
u32 cur_mps = ccmps ? min(pmtu, ccmps) : pmtu;
/* Account for header lengths and IPv4/v6 option overhead */
cur_mps -= (icsk->icsk_af_ops->net_header_len + icsk->icsk_ext_hdr_len +
sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
/*
* FIXME: this should come from the CCID infrastructure, where, say,
* TFRC will say it wants TIMESTAMPS, ELAPSED time, etc, for now lets
* put a rough estimate for NDP + TIMESTAMP + TIMESTAMP_ECHO + ELAPSED
* TIME + TFRC_OPT_LOSS_EVENT_RATE + TFRC_OPT_RECEIVE_RATE + padding to
* make it a multiple of 4
* Leave enough headroom for common DCCP header options.
* This only considers options which may appear on DCCP-Data packets, as
* per table 3 in RFC 4340, 5.8. When running out of space for other
* options (eg. Ack Vector which can take up to 255 bytes), it is better
* to schedule a separate Ack. Thus we leave headroom for the following:
* - 1 byte for Slow Receiver (11.6)
* - 6 bytes for Timestamp (13.1)
* - 10 bytes for Timestamp Echo (13.3)
* - 8 bytes for NDP count (7.7, when activated)
* - 6 bytes for Data Checksum (9.3)
* - %DCCPAV_MIN_OPTLEN bytes for Ack Vector size (11.4, when enabled)
*/
cur_mps -= roundup(5 + 6 + 10 + 6 + 6 + 6, 4);
cur_mps -= roundup(1 + 6 + 10 + dp->dccps_send_ndp_count * 8 + 6 +
(dp->dccps_hc_rx_ackvec ? DCCPAV_MIN_OPTLEN : 0), 4);
/* And store cached results */
icsk->icsk_pmtu_cookie = pmtu;
@@ -270,7 +276,20 @@ void dccp_write_xmit(struct sock *sk, int block)
const int len = skb->len;
if (sk->sk_state == DCCP_PARTOPEN) {
/* See 8.1.5. Handshake Completion */
const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD;
/*
* See 8.1.5 - Handshake Completion.
*
* For robustness we resend Confirm options until the client has
* entered OPEN. During the initial feature negotiation, the MPS
* is smaller than usual, reduced by the Change/Confirm options.
*/
if (!list_empty(&dp->dccps_featneg) && len > cur_mps) {
DCCP_WARN("Payload too large (%d) for featneg.\n", len);
dccp_send_ack(sk);
dccp_feat_list_purge(&dp->dccps_featneg);
}
inet_csk_schedule_ack(sk);
inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
inet_csk(sk)->icsk_rto,
-2
View File
@@ -174,8 +174,6 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
struct dccp_sock *dp = dccp_sk(sk);
struct inet_connection_sock *icsk = inet_csk(sk);
dccp_minisock_init(&dp->dccps_minisock);
icsk->icsk_rto = DCCP_TIMEOUT_INIT;
icsk->icsk_syn_retries = sysctl_dccp_request_retries;
sk->sk_state = DCCP_CLOSED;
+30 -13
View File
@@ -18,55 +18,72 @@
#error This file should not be compiled without CONFIG_SYSCTL defined
#endif
/* Boundary values */
static int zero = 0,
u8_max = 0xFF;
static unsigned long seqw_min = 32;
static struct ctl_table dccp_default_table[] = {
{
.procname = "seq_window",
.data = &sysctl_dccp_feat_sequence_window,
.maxlen = sizeof(sysctl_dccp_feat_sequence_window),
.data = &sysctl_dccp_sequence_window,
.maxlen = sizeof(sysctl_dccp_sequence_window),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_doulongvec_minmax,
.extra1 = &seqw_min, /* RFC 4340, 7.5.2 */
},
{
.procname = "rx_ccid",
.data = &sysctl_dccp_feat_rx_ccid,
.maxlen = sizeof(sysctl_dccp_feat_rx_ccid),
.data = &sysctl_dccp_rx_ccid,
.maxlen = sizeof(sysctl_dccp_rx_ccid),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &u8_max, /* RFC 4340, 10. */
},
{
.procname = "tx_ccid",
.data = &sysctl_dccp_feat_tx_ccid,
.maxlen = sizeof(sysctl_dccp_feat_tx_ccid),
.data = &sysctl_dccp_tx_ccid,
.maxlen = sizeof(sysctl_dccp_tx_ccid),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &u8_max, /* RFC 4340, 10. */
},
{
.procname = "request_retries",
.data = &sysctl_dccp_request_retries,
.maxlen = sizeof(sysctl_dccp_request_retries),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &u8_max,
},
{
.procname = "retries1",
.data = &sysctl_dccp_retries1,
.maxlen = sizeof(sysctl_dccp_retries1),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &u8_max,
},
{
.procname = "retries2",
.data = &sysctl_dccp_retries2,
.maxlen = sizeof(sysctl_dccp_retries2),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
.extra2 = &u8_max,
},
{
.procname = "tx_qlen",
.data = &sysctl_dccp_tx_qlen,
.maxlen = sizeof(sysctl_dccp_tx_qlen),
.mode = 0644,
.proc_handler = proc_dointvec,
.proc_handler = proc_dointvec_minmax,
.extra1 = &zero,
},
{
.procname = "sync_ratelimit",
+12 -13
View File
@@ -1246,11 +1246,12 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case TIOCINQ:
lock_sock(sk);
if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {
skb = skb_peek(&scp->other_receive_queue);
if (skb) {
amount = skb->len;
} else {
struct sk_buff *skb = sk->sk_receive_queue.next;
for(;;) {
skb = sk->sk_receive_queue.next;
for (;;) {
if (skb ==
(struct sk_buff *)&sk->sk_receive_queue)
break;
@@ -1579,16 +1580,16 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
default:
#ifdef CONFIG_NETFILTER
{
int val, len;
int ret, len;
if(get_user(len, optlen))
return -EFAULT;
val = nf_getsockopt(sk, PF_DECnet, optname,
ret = nf_getsockopt(sk, PF_DECnet, optname,
optval, &len);
if (val >= 0)
val = put_user(len, optlen);
return val;
if (ret >= 0)
ret = put_user(len, optlen);
return ret;
}
#endif
case DSO_STREAM:
@@ -2071,8 +2072,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
}
out:
if (skb)
kfree_skb(skb);
kfree_skb(skb);
release_sock(sk);
@@ -2112,9 +2112,8 @@ static struct notifier_block dn_dev_notifier = {
extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
static struct packet_type dn_dix_packet_type = {
.type = __constant_htons(ETH_P_DNA_RT),
.dev = NULL, /* All devices */
static struct packet_type dn_dix_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_DNA_RT),
.func = dn_route_rcv,
};
+4 -2
View File
@@ -684,7 +684,6 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
return -ENODEV;
if ((dn_db = dev->dn_ptr) == NULL) {
int err;
dn_db = dn_dev_create(dev, &err);
if (!dn_db)
return err;
@@ -769,7 +768,8 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
@@ -1322,6 +1322,7 @@ static inline int is_dn_dev(struct net_device *dev)
}
static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(&dev_base_lock)
{
int i;
struct net_device *dev;
@@ -1364,6 +1365,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
}
static void dn_dev_seq_stop(struct seq_file *seq, void *v)
__releases(&dev_base_lock)
{
read_unlock(&dev_base_lock);
}
+2 -6
View File
@@ -124,7 +124,7 @@ int decnet_dst_gc_interval = 2;
static struct dst_ops dn_dst_ops = {
.family = PF_DECnet,
.protocol = __constant_htons(ETH_P_DNA_RT),
.protocol = cpu_to_be16(ETH_P_DNA_RT),
.gc_thresh = 128,
.gc = dn_dst_gc,
.check = dn_dst_check,
@@ -380,7 +380,6 @@ static int dn_return_short(struct sk_buff *skb)
unsigned char *ptr;
__le16 *src;
__le16 *dst;
__le16 tmp;
/* Add back headers */
skb_push(skb, skb->data - skb_network_header(skb));
@@ -399,10 +398,7 @@ static int dn_return_short(struct sk_buff *skb)
ptr += 2;
*ptr = 0; /* Zero hop count */
/* Swap source and destination */
tmp = *src;
*src = *dst;
*dst = tmp;
swap(*src, *dst);
skb->pkt_type = PACKET_OUTGOING;
dn_rt_finish_output(skb, NULL, NULL);
+2 -1
View File
@@ -375,7 +375,8 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
+1 -1
View File
@@ -179,7 +179,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
}
if (write) {
int len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
if (copy_from_user(addr, buffer, len))
return -EFAULT;
+3 -3
View File
@@ -41,13 +41,13 @@ config NET_DSA_MV88E6XXX_NEED_PPU
default n
config NET_DSA_MV88E6131
bool "Marvell 88E6131 ethernet switch chip support"
bool "Marvell 88E6095/6095F/6131 ethernet switch chip support"
select NET_DSA_MV88E6XXX
select NET_DSA_MV88E6XXX_NEED_PPU
select NET_DSA_TAG_DSA
---help---
This enables support for the Marvell 88E6131 ethernet switch
chip.
This enables support for the Marvell 88E6095/6095F/6131
ethernet switch chips.
config NET_DSA_MV88E6123_61_65
bool "Marvell 88E6123/6161/6165 ethernet switch chip support"
+109 -68
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/dsa.c - Hardware switch handling
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -67,12 +67,13 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
/* basic switch operations **************************************************/
static struct dsa_switch *
dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
struct mii_bus *bus, struct net_device *dev)
dsa_switch_setup(struct dsa_switch_tree *dst, int index,
struct device *parent, struct mii_bus *bus)
{
struct dsa_chip_data *pd = dst->pd->chip + index;
struct dsa_switch_driver *drv;
struct dsa_switch *ds;
int ret;
struct dsa_switch_driver *drv;
char *name;
int i;
@@ -81,11 +82,12 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
*/
drv = dsa_switch_probe(bus, pd->sw_addr, &name);
if (drv == NULL) {
printk(KERN_ERR "%s: could not detect attached switch\n",
dev->name);
printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
dst->master_netdev->name, index);
return ERR_PTR(-EINVAL);
}
printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name);
printk(KERN_INFO "%s[%d]: detected a %s switch\n",
dst->master_netdev->name, index, name);
/*
@@ -95,18 +97,16 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
if (ds == NULL)
return ERR_PTR(-ENOMEM);
ds->pd = pd;
ds->master_netdev = dev;
ds->master_mii_bus = bus;
ds->dst = dst;
ds->index = index;
ds->pd = dst->pd->chip + index;
ds->drv = drv;
ds->tag_protocol = drv->tag_protocol;
ds->master_mii_bus = bus;
/*
* Validate supplied switch configuration.
*/
ds->cpu_port = -1;
for (i = 0; i < DSA_MAX_PORTS; i++) {
char *name;
@@ -115,32 +115,28 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
continue;
if (!strcmp(name, "cpu")) {
if (ds->cpu_port != -1) {
if (dst->cpu_switch != -1) {
printk(KERN_ERR "multiple cpu ports?!\n");
ret = -EINVAL;
goto out;
}
ds->cpu_port = i;
dst->cpu_switch = index;
dst->cpu_port = i;
} else if (!strcmp(name, "dsa")) {
ds->dsa_port_mask |= 1 << i;
} else {
ds->valid_port_mask |= 1 << i;
ds->phys_port_mask |= 1 << i;
}
}
if (ds->cpu_port == -1) {
printk(KERN_ERR "no cpu port?!\n");
ret = -EINVAL;
goto out;
}
/*
* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
* sent to the tag format's receive function. (Which will
* discard received packets until we set ds->ports[] below.)
* If the CPU connects to this switch, set the switch tree
* tagging protocol to the preferred tagging format of this
* switch.
*/
wmb();
dev->dsa_ptr = (void *)ds;
if (ds->dst->cpu_switch == index)
ds->dst->tag_protocol = drv->tag_protocol;
/*
@@ -150,7 +146,7 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
if (ret < 0)
goto out;
ret = drv->set_addr(ds, dev->dev_addr);
ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
if (ret < 0)
goto out;
@@ -169,18 +165,18 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
/*
* Create network devices for physical switch ports.
*/
wmb();
for (i = 0; i < DSA_MAX_PORTS; i++) {
struct net_device *slave_dev;
if (!(ds->valid_port_mask & (1 << i)))
if (!(ds->phys_port_mask & (1 << i)))
continue;
slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
if (slave_dev == NULL) {
printk(KERN_ERR "%s: can't create dsa slave "
"device for port %d(%s)\n",
dev->name, i, pd->port_names[i]);
printk(KERN_ERR "%s[%d]: can't create dsa "
"slave device for port %d(%s)\n",
dst->master_netdev->name,
index, i, pd->port_names[i]);
continue;
}
@@ -192,7 +188,6 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
out_free:
mdiobus_free(ds->slave_mii_bus);
out:
dev->dsa_ptr = NULL;
kfree(ds);
return ERR_PTR(ret);
}
@@ -212,35 +207,42 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
*/
bool dsa_uses_dsa_tags(void *dsa_ptr)
{
struct dsa_switch *ds = dsa_ptr;
struct dsa_switch_tree *dst = dsa_ptr;
return !!(ds->tag_protocol == htons(ETH_P_DSA));
return !!(dst->tag_protocol == htons(ETH_P_DSA));
}
bool dsa_uses_trailer_tags(void *dsa_ptr)
{
struct dsa_switch *ds = dsa_ptr;
struct dsa_switch_tree *dst = dsa_ptr;
return !!(ds->tag_protocol == htons(ETH_P_TRAILER));
return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
}
/* link polling *************************************************************/
static void dsa_link_poll_work(struct work_struct *ugly)
{
struct dsa_switch *ds;
struct dsa_switch_tree *dst;
int i;
ds = container_of(ugly, struct dsa_switch, link_poll_work);
dst = container_of(ugly, struct dsa_switch_tree, link_poll_work);
ds->drv->poll_link(ds);
mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ));
for (i = 0; i < dst->pd->nr_chips; i++) {
struct dsa_switch *ds = dst->ds[i];
if (ds != NULL && ds->drv->poll_link != NULL)
ds->drv->poll_link(ds);
}
mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));
}
static void dsa_link_poll_timer(unsigned long _ds)
static void dsa_link_poll_timer(unsigned long _dst)
{
struct dsa_switch *ds = (void *)_ds;
struct dsa_switch_tree *dst = (void *)_dst;
schedule_work(&ds->link_poll_work);
schedule_work(&dst->link_poll_work);
}
@@ -303,18 +305,14 @@ static int dsa_probe(struct platform_device *pdev)
static int dsa_version_printed;
struct dsa_platform_data *pd = pdev->dev.platform_data;
struct net_device *dev;
struct mii_bus *bus;
struct dsa_switch *ds;
struct dsa_switch_tree *dst;
int i;
if (!dsa_version_printed++)
printk(KERN_NOTICE "Distributed Switch Architecture "
"driver version %s\n", dsa_driver_version);
if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL)
return -EINVAL;
bus = dev_to_mii_bus(pd->mii_bus);
if (bus == NULL)
if (pd == NULL || pd->netdev == NULL)
return -EINVAL;
dev = dev_to_net_device(pd->netdev);
@@ -326,36 +324,79 @@ static int dsa_probe(struct platform_device *pdev)
return -EEXIST;
}
ds = dsa_switch_setup(&pdev->dev, pd, bus, dev);
if (IS_ERR(ds)) {
dst = kzalloc(sizeof(*dst), GFP_KERNEL);
if (dst == NULL) {
dev_put(dev);
return PTR_ERR(ds);
return -ENOMEM;
}
if (ds->drv->poll_link != NULL) {
INIT_WORK(&ds->link_poll_work, dsa_link_poll_work);
init_timer(&ds->link_poll_timer);
ds->link_poll_timer.data = (unsigned long)ds;
ds->link_poll_timer.function = dsa_link_poll_timer;
ds->link_poll_timer.expires = round_jiffies(jiffies + HZ);
add_timer(&ds->link_poll_timer);
platform_set_drvdata(pdev, dst);
dst->pd = pd;
dst->master_netdev = dev;
dst->cpu_switch = -1;
dst->cpu_port = -1;
for (i = 0; i < pd->nr_chips; i++) {
struct mii_bus *bus;
struct dsa_switch *ds;
bus = dev_to_mii_bus(pd->chip[i].mii_bus);
if (bus == NULL) {
printk(KERN_ERR "%s[%d]: no mii bus found for "
"dsa switch\n", dev->name, i);
continue;
}
ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
if (IS_ERR(ds)) {
printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
"instance (error %ld)\n", dev->name, i,
PTR_ERR(ds));
continue;
}
dst->ds[i] = ds;
if (ds->drv->poll_link != NULL)
dst->link_poll_needed = 1;
}
platform_set_drvdata(pdev, ds);
/*
* If we use a tagging format that doesn't have an ethertype
* field, make sure that all packets from this point on get
* sent to the tag format's receive function.
*/
wmb();
dev->dsa_ptr = (void *)dst;
if (dst->link_poll_needed) {
INIT_WORK(&dst->link_poll_work, dsa_link_poll_work);
init_timer(&dst->link_poll_timer);
dst->link_poll_timer.data = (unsigned long)dst;
dst->link_poll_timer.function = dsa_link_poll_timer;
dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
add_timer(&dst->link_poll_timer);
}
return 0;
}
static int dsa_remove(struct platform_device *pdev)
{
struct dsa_switch *ds = platform_get_drvdata(pdev);
struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
int i;
if (ds->drv->poll_link != NULL)
del_timer_sync(&ds->link_poll_timer);
if (dst->link_poll_needed)
del_timer_sync(&dst->link_poll_timer);
flush_scheduled_work();
dsa_switch_destroy(ds);
for (i = 0; i < dst->pd->nr_chips; i++) {
struct dsa_switch *ds = dst->ds[i];
if (ds != NULL)
dsa_switch_destroy(ds);
}
return 0;
}
+81 -16
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/dsa_priv.h - Hardware switch handling
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,42 +19,107 @@
struct dsa_switch {
/*
* Configuration data for the platform device that owns
* this dsa switch instance.
* Parent switch tree, and switch index.
*/
struct dsa_platform_data *pd;
struct dsa_switch_tree *dst;
int index;
/*
* References to network device and mii bus to use.
* Configuration data for this switch.
*/
struct net_device *master_netdev;
struct mii_bus *master_mii_bus;
struct dsa_chip_data *pd;
/*
* The used switch driver and frame tagging type.
* The used switch driver.
*/
struct dsa_switch_driver *drv;
__be16 tag_protocol;
/*
* Reference to mii bus to use.
*/
struct mii_bus *master_mii_bus;
/*
* Slave mii_bus and devices for the individual ports.
*/
int cpu_port;
u32 valid_port_mask;
struct mii_bus *slave_mii_bus;
struct net_device *ports[DSA_MAX_PORTS];
u32 dsa_port_mask;
u32 phys_port_mask;
struct mii_bus *slave_mii_bus;
struct net_device *ports[DSA_MAX_PORTS];
};
struct dsa_switch_tree {
/*
* Configuration data for the platform device that owns
* this dsa switch tree instance.
*/
struct dsa_platform_data *pd;
/*
* Reference to network device to use, and which tagging
* protocol to use.
*/
struct net_device *master_netdev;
__be16 tag_protocol;
/*
* The switch and port to which the CPU is attached.
*/
s8 cpu_switch;
s8 cpu_port;
/*
* Link state polling.
*/
struct work_struct link_poll_work;
struct timer_list link_poll_timer;
int link_poll_needed;
struct work_struct link_poll_work;
struct timer_list link_poll_timer;
/*
* Data for the individual switch chips.
*/
struct dsa_switch *ds[DSA_MAX_SWITCHES];
};
static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
{
return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
}
static inline u8 dsa_upstream_port(struct dsa_switch *ds)
{
struct dsa_switch_tree *dst = ds->dst;
/*
* If this is the root switch (i.e. the switch that connects
* to the CPU), return the cpu port number on this switch.
* Else return the (DSA) port number that connects to the
* switch that is one hop closer to the cpu.
*/
if (dst->cpu_switch == ds->index)
return dst->cpu_port;
else
return ds->pd->rtable[dst->cpu_switch];
}
struct dsa_slave_priv {
/*
* The linux network interface corresponding to this
* switch port.
*/
struct net_device *dev;
/*
* Which switch this port is a part of, and the port index
* for this port.
*/
struct dsa_switch *parent;
int port;
u8 port;
/*
* The phylib phy_device pointer for the PHY connected
* to this port.
*/
struct phy_device *phy;
};
+6 -6
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -81,7 +81,7 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
/*
* Reset the switch.
*/
REG_WRITE(REG_GLOBAL, 0x0A, 0xa130);
REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
/*
* Wait up to one second for reset to complete.
@@ -128,7 +128,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
* state to Forwarding. Additionally, if this is the CPU
* port, enable Ingress and Egress Trailer tagging mode.
*/
REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x4103 : 0x0003);
REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ? 0x4103 : 0x0003);
/*
* Port based VLAN map: give each port its own address
@@ -138,9 +138,9 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
*/
REG_WRITE(addr, 0x06,
((p & 0xf) << 12) |
((p == ds->cpu_port) ?
ds->valid_port_mask :
(1 << ds->cpu_port)));
(dsa_is_cpu_port(ds, p) ?
ds->phys_port_mask :
(1 << ds->dst->cpu_port)));
/*
* Port Association Vector: when learning source addresses
+58 -32
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -98,17 +98,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
return ret;
/*
* Configure the cpu port, and configure the cpu port as the
* port to which ingress and egress monitor frames are to be
* sent.
* Configure the upstream port, and configure the upstream
* port as the port to which ingress and egress monitor frames
* are to be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1110));
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
/*
* Disable remote management for now, and set the switch's
* DSA device number to zero.
* DSA device number.
*/
REG_WRITE(REG_GLOBAL, 0x1c, 0x0000);
REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
/*
* Send all frames with destination addresses matching
@@ -133,10 +133,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
/*
* Map all DSA device IDs to the CPU port.
* Program the DSA routing table.
*/
for (i = 0; i < 32; i++)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
for (i = 0; i < 32; i++) {
int nexthop;
nexthop = 0x1f;
if (i != ds->index && i < ds->dst->pd->nr_chips)
nexthop = ds->pd->rtable[i] & 0x1f;
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
/*
* Clear all trunk masks.
@@ -176,12 +183,18 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
{
int addr = REG_PORT(p);
u16 val;
/*
* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values.
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* full duplex.
*/
REG_WRITE(addr, 0x01, 0x0003);
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
REG_WRITE(addr, 0x01, 0x003e);
else
REG_WRITE(addr, 0x01, 0x0003);
/*
* Do not limit the period of time that this port can be
@@ -192,37 +205,50 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
/*
* Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
* configure the requested (DSA/EDSA) tagging mode if this is
* the CPU port, disable Header mode, enable IGMP/MLD snooping,
* disable VLAN tunneling, determine priority by looking at
* 802.1p and IP priority fields (IP prio has precedence), and
* set STP state to Forwarding. Finally, if this is the CPU
* port, additionally enable forwarding of unknown unicast and
* multicast addresses.
* disable Header mode, enable IGMP/MLD snooping, disable VLAN
* tunneling, determine priority by looking at 802.1p and IP
* priority fields (IP prio has precedence), and set STP state
* to Forwarding.
*
* If this is the CPU link, use DSA or EDSA tagging depending
* on which tagging mode was configured.
*
* If this is a link to another switch, use DSA tagging mode.
*
* If this is the upstream port for this switch, enable
* forwarding of unknown unicasts and multicasts.
*/
REG_WRITE(addr, 0x04,
(p == ds->cpu_port) ?
(ds->tag_protocol == htons(ETH_P_DSA)) ?
0x053f : 0x373f :
0x0433);
val = 0x0433;
if (dsa_is_cpu_port(ds, p)) {
if (ds->dst->tag_protocol == htons(ETH_P_EDSA))
val |= 0x3300;
else
val |= 0x0100;
}
if (ds->dsa_port_mask & (1 << p))
val |= 0x0100;
if (p == dsa_upstream_port(ds))
val |= 0x000c;
REG_WRITE(addr, 0x04, val);
/*
* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
/*
* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the CPU port.
* the upstream port.
*/
REG_WRITE(addr, 0x06,
((p & 0xf) << 12) |
((p == ds->cpu_port) ?
ds->valid_port_mask :
(1 << ds->cpu_port)));
val = (p & 0xf) << 12;
if (dsa_is_cpu_port(ds, p))
val |= ds->phys_port_mask;
else
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
/*
* Default VLAN ID and priority: don't set a default VLAN
@@ -394,7 +420,7 @@ static int mv88e6123_61_65_get_sset_count(struct dsa_switch *ds)
}
static struct dsa_switch_driver mv88e6123_61_65_switch_driver = {
.tag_protocol = __constant_htons(ETH_P_EDSA),
.tag_protocol = cpu_to_be16(ETH_P_EDSA),
.priv_size = sizeof(struct mv88e6xxx_priv_state),
.probe = mv88e6123_61_65_probe,
.setup = mv88e6123_61_65_setup,
+63 -35
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/mv88e6131.c - Marvell 88e6131 switch chip support
* Copyright (c) 2008 Marvell Semiconductor
* net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 switch chip support
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -21,6 +21,8 @@ static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
if (ret >= 0) {
ret &= 0xfff0;
if (ret == 0x0950)
return "Marvell 88E6095/88E6095F";
if (ret == 0x1060)
return "Marvell 88E6131";
}
@@ -36,7 +38,7 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
/*
* Set all ports to the disabled state.
*/
for (i = 0; i < 8; i++) {
for (i = 0; i < 11; i++) {
ret = REG_READ(REG_PORT(i), 0x04);
REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
}
@@ -100,17 +102,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
/*
* Disable ARP mirroring, and configure the cpu port as the
* port to which ingress and egress monitor frames are to be
* sent.
* Disable ARP mirroring, and configure the upstream port as
* the port to which ingress and egress monitor frames are to
* be sent.
*/
REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0);
REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
/*
* Disable cascade port functionality, and set the switch's
* DSA device number to zero.
* DSA device number.
*/
REG_WRITE(REG_GLOBAL, 0x1c, 0xe000);
REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
/*
* Send all frames with destination addresses matching
@@ -127,16 +129,23 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
/*
* Map all DSA device IDs to the CPU port.
* Program the DSA routing table.
*/
for (i = 0; i < 32; i++)
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
for (i = 0; i < 32; i++) {
int nexthop;
nexthop = 0x1f;
if (i != ds->index && i < ds->dst->pd->nr_chips)
nexthop = ds->pd->rtable[i] & 0x1f;
REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
}
/*
* Clear all trunk masks.
*/
for (i = 0; i < 8; i++)
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
/*
* Clear all trunk mappings.
@@ -156,12 +165,18 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
{
int addr = REG_PORT(p);
u16 val;
/*
* MAC Forcing register: don't force link, speed, duplex
* or flow control state to any particular values.
* or flow control state to any particular values on physical
* ports, but force the CPU port and all DSA ports to 1000 Mb/s
* full duplex.
*/
REG_WRITE(addr, 0x01, 0x0003);
if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
REG_WRITE(addr, 0x01, 0x003e);
else
REG_WRITE(addr, 0x01, 0x0003);
/*
* Port Control: disable Core Tag, disable Drop-on-Lock,
@@ -169,29 +184,40 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
* tunneling, determine priority by looking at 802.1p and
* IP priority fields (IP prio has precedence), and set STP
* state to Forwarding. Finally, if this is the CPU port,
* additionally enable DSA tagging and forwarding of unknown
* unicast addresses.
* state to Forwarding.
*
* If this is the upstream port for this switch, enable
* forwarding of unknown unicasts, and enable DSA tagging
* mode.
*
* If this is the link to another switch, use DSA tagging
* mode, but do not enable forwarding of unknown unicasts.
*/
REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433);
val = 0x0433;
if (p == dsa_upstream_port(ds))
val |= 0x0104;
if (ds->dsa_port_mask & (1 << p))
val |= 0x0100;
REG_WRITE(addr, 0x04, val);
/*
* Port Control 1: disable trunking. Also, if this is the
* CPU port, enable learn messages to be sent to this port.
*/
REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
/*
* Port based VLAN map: give each port its own address
* database, allow the CPU port to talk to each of the 'real'
* ports, and allow each of the 'real' ports to only talk to
* the CPU port.
* the upstream port.
*/
REG_WRITE(addr, 0x06,
((p & 0xf) << 12) |
((p == ds->cpu_port) ?
ds->valid_port_mask :
(1 << ds->cpu_port)));
val = (p & 0xf) << 12;
if (dsa_is_cpu_port(ds, p))
val |= ds->phys_port_mask;
else
val |= 1 << dsa_upstream_port(ds);
REG_WRITE(addr, 0x06, val);
/*
* Default VLAN ID and priority: don't set a default VLAN
@@ -207,13 +233,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
* untagged frames on this port, do a destination address
* lookup on received packets as usual, don't send a copy
* of all transmitted/received frames on this port to the
* CPU, and configure the CPU port number. Also, if this
* is the CPU port, enable forwarding of unknown multicast
* addresses.
* CPU, and configure the upstream port number.
*
* If this is the upstream port for this switch, enable
* forwarding of unknown multicast addresses.
*/
REG_WRITE(addr, 0x08,
((p == ds->cpu_port) ? 0x00c0 : 0x0080) |
ds->cpu_port);
val = 0x0080 | dsa_upstream_port(ds);
if (p == dsa_upstream_port(ds))
val |= 0x0040;
REG_WRITE(addr, 0x08, val);
/*
* Rate Control: disable ingress rate limiting.
@@ -268,7 +296,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
if (ret < 0)
return ret;
for (i = 0; i < 6; i++) {
for (i = 0; i < 11; i++) {
ret = mv88e6131_setup_port(ds, i);
if (ret < 0)
return ret;
@@ -279,7 +307,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
static int mv88e6131_port_to_phy_addr(int port)
{
if (port >= 0 && port != 3 && port <= 7)
if (port >= 0 && port <= 11)
return port;
return -1;
}
@@ -353,7 +381,7 @@ static int mv88e6131_get_sset_count(struct dsa_switch *ds)
}
static struct dsa_switch_driver mv88e6131_switch_driver = {
.tag_protocol = __constant_htons(ETH_P_DSA),
.tag_protocol = cpu_to_be16(ETH_P_DSA),
.priv_size = sizeof(struct mv88e6xxx_priv_state),
.probe = mv88e6131_probe,
.setup = mv88e6131_setup,
+23 -11
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/slave.c - Slave device handling
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -19,7 +19,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
{
struct dsa_switch *ds = bus->priv;
if (ds->valid_port_mask & (1 << addr))
if (ds->phys_port_mask & (1 << addr))
return ds->drv->phy_read(ds, addr, reg);
return 0xffff;
@@ -29,7 +29,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
{
struct dsa_switch *ds = bus->priv;
if (ds->valid_port_mask & (1 << addr))
if (ds->phys_port_mask & (1 << addr))
return ds->drv->phy_write(ds, addr, reg, val);
return 0;
@@ -43,15 +43,24 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
ds->slave_mii_bus->write = dsa_slave_phy_write;
snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
ds->master_mii_bus->id, ds->pd->sw_addr);
ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev);
ds->slave_mii_bus->parent = &ds->master_mii_bus->dev;
}
/* slave device handling ****************************************************/
static int dsa_slave_init(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
dev->iflink = p->parent->dst->master_netdev->ifindex;
return 0;
}
static int dsa_slave_open(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->master_netdev;
struct net_device *master = p->parent->dst->master_netdev;
int err;
if (!(master->flags & IFF_UP))
@@ -89,7 +98,7 @@ out:
static int dsa_slave_close(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->master_netdev;
struct net_device *master = p->parent->dst->master_netdev;
dev_mc_unsync(master, dev);
dev_unicast_unsync(master, dev);
@@ -107,7 +116,7 @@ static int dsa_slave_close(struct net_device *dev)
static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->master_netdev;
struct net_device *master = p->parent->dst->master_netdev;
if (change & IFF_ALLMULTI)
dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
@@ -118,7 +127,7 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
static void dsa_slave_set_rx_mode(struct net_device *dev)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->master_netdev;
struct net_device *master = p->parent->dst->master_netdev;
dev_mc_sync(master, dev);
dev_unicast_sync(master, dev);
@@ -127,7 +136,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev)
static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
{
struct dsa_slave_priv *p = netdev_priv(dev);
struct net_device *master = p->parent->master_netdev;
struct net_device *master = p->parent->dst->master_netdev;
struct sockaddr *addr = a;
int err;
@@ -288,6 +297,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
#ifdef CONFIG_NET_DSA_TAG_DSA
static const struct net_device_ops dsa_netdev_ops = {
.ndo_init = dsa_slave_init,
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
.ndo_start_xmit = dsa_xmit,
@@ -300,6 +310,7 @@ static const struct net_device_ops dsa_netdev_ops = {
#endif
#ifdef CONFIG_NET_DSA_TAG_EDSA
static const struct net_device_ops edsa_netdev_ops = {
.ndo_init = dsa_slave_init,
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
.ndo_start_xmit = edsa_xmit,
@@ -312,6 +323,7 @@ static const struct net_device_ops edsa_netdev_ops = {
#endif
#ifdef CONFIG_NET_DSA_TAG_TRAILER
static const struct net_device_ops trailer_netdev_ops = {
.ndo_init = dsa_slave_init,
.ndo_open = dsa_slave_open,
.ndo_stop = dsa_slave_close,
.ndo_start_xmit = trailer_xmit,
@@ -328,7 +340,7 @@ struct net_device *
dsa_slave_create(struct dsa_switch *ds, struct device *parent,
int port, char *name)
{
struct net_device *master = ds->master_netdev;
struct net_device *master = ds->dst->master_netdev;
struct net_device *slave_dev;
struct dsa_slave_priv *p;
int ret;
@@ -343,7 +355,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
slave_dev->tx_queue_len = 0;
switch (ds->tag_protocol) {
switch (ds->dst->tag_protocol) {
#ifdef CONFIG_NET_DSA_TAG_DSA
case htons(ETH_P_DSA):
slave_dev->netdev_ops = &dsa_netdev_ops;
+22 -12
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -36,7 +36,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
* Construct tagged FROM_CPU DSA tag from 802.1q tag.
*/
dsa_header = skb->data + 2 * ETH_ALEN;
dsa_header[0] = 0x60;
dsa_header[0] = 0x60 | p->parent->index;
dsa_header[1] = p->port << 3;
/*
@@ -57,7 +57,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
* Construct untagged FROM_CPU DSA tag.
*/
dsa_header = skb->data + 2 * ETH_ALEN;
dsa_header[0] = 0x40;
dsa_header[0] = 0x40 | p->parent->index;
dsa_header[1] = p->port << 3;
dsa_header[2] = 0x00;
dsa_header[3] = 0x00;
@@ -65,7 +65,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = htons(ETH_P_DSA);
skb->dev = p->parent->master_netdev;
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
@@ -78,11 +78,13 @@ out_free:
static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dsa_switch *ds = dev->dsa_ptr;
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
u8 *dsa_header;
int source_device;
int source_port;
if (unlikely(ds == NULL))
if (unlikely(dst == NULL))
goto out_drop;
skb = skb_unshare(skb, GFP_ATOMIC);
@@ -98,16 +100,24 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
dsa_header = skb->data - 2;
/*
* Check that frame type is either TO_CPU or FORWARD, and
* that the source device is zero.
* Check that frame type is either TO_CPU or FORWARD.
*/
if ((dsa_header[0] & 0xdf) != 0x00 && (dsa_header[0] & 0xdf) != 0xc0)
if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
goto out_drop;
/*
* Check that the source port is a registered DSA port.
* Determine source device and port.
*/
source_device = dsa_header[0] & 0x1f;
source_port = (dsa_header[1] >> 3) & 0x1f;
/*
* Check that the source device exists and that the source
* port is a registered DSA port.
*/
if (source_device >= dst->pd->nr_chips)
goto out_drop;
ds = dst->ds[source_device];
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
goto out_drop;
@@ -175,8 +185,8 @@ out:
return 0;
}
static struct packet_type dsa_packet_type = {
.type = __constant_htons(ETH_P_DSA),
static struct packet_type dsa_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_DSA),
.func = dsa_rcv,
};
+22 -12
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/tag_edsa.c - Ethertype DSA tagging
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -45,7 +45,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
edsa_header[1] = ETH_P_EDSA & 0xff;
edsa_header[2] = 0x00;
edsa_header[3] = 0x00;
edsa_header[4] = 0x60;
edsa_header[4] = 0x60 | p->parent->index;
edsa_header[5] = p->port << 3;
/*
@@ -70,7 +70,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
edsa_header[1] = ETH_P_EDSA & 0xff;
edsa_header[2] = 0x00;
edsa_header[3] = 0x00;
edsa_header[4] = 0x40;
edsa_header[4] = 0x40 | p->parent->index;
edsa_header[5] = p->port << 3;
edsa_header[6] = 0x00;
edsa_header[7] = 0x00;
@@ -78,7 +78,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
skb->protocol = htons(ETH_P_EDSA);
skb->dev = p->parent->master_netdev;
skb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(skb);
return NETDEV_TX_OK;
@@ -91,11 +91,13 @@ out_free:
static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dsa_switch *ds = dev->dsa_ptr;
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
u8 *edsa_header;
int source_device;
int source_port;
if (unlikely(ds == NULL))
if (unlikely(dst == NULL))
goto out_drop;
skb = skb_unshare(skb, GFP_ATOMIC);
@@ -111,16 +113,24 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
edsa_header = skb->data + 2;
/*
* Check that frame type is either TO_CPU or FORWARD, and
* that the source device is zero.
* Check that frame type is either TO_CPU or FORWARD.
*/
if ((edsa_header[0] & 0xdf) != 0x00 && (edsa_header[0] & 0xdf) != 0xc0)
if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
goto out_drop;
/*
* Check that the source port is a registered DSA port.
* Determine source device and port.
*/
source_device = edsa_header[0] & 0x1f;
source_port = (edsa_header[1] >> 3) & 0x1f;
/*
* Check that the source device exists and that the source
* port is a registered DSA port.
*/
if (source_device >= dst->pd->nr_chips)
goto out_drop;
ds = dst->ds[source_device];
if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
goto out_drop;
@@ -194,8 +204,8 @@ out:
return 0;
}
static struct packet_type edsa_packet_type = {
.type = __constant_htons(ETH_P_EDSA),
static struct packet_type edsa_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_EDSA),
.func = edsa_rcv,
};
+8 -6
View File
@@ -1,6 +1,6 @@
/*
* net/dsa/tag_trailer.c - Trailer tag format handling
* Copyright (c) 2008 Marvell Semiconductor
* Copyright (c) 2008-2009 Marvell Semiconductor
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -59,7 +59,7 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
nskb->protocol = htons(ETH_P_TRAILER);
nskb->dev = p->parent->master_netdev;
nskb->dev = p->parent->dst->master_netdev;
dev_queue_xmit(nskb);
return NETDEV_TX_OK;
@@ -68,12 +68,14 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
struct packet_type *pt, struct net_device *orig_dev)
{
struct dsa_switch *ds = dev->dsa_ptr;
struct dsa_switch_tree *dst = dev->dsa_ptr;
struct dsa_switch *ds;
u8 *trailer;
int source_port;
if (unlikely(ds == NULL))
if (unlikely(dst == NULL))
goto out_drop;
ds = dst->ds[0];
skb = skb_unshare(skb, GFP_ATOMIC);
if (skb == NULL)
@@ -111,8 +113,8 @@ out:
return 0;
}
static struct packet_type trailer_packet_type = {
.type = __constant_htons(ETH_P_TRAILER),
static struct packet_type trailer_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_TRAILER),
.func = trailer_rcv,
};
+2 -2
View File
@@ -1102,8 +1102,8 @@ drop:
return NET_RX_DROP;
}
static struct packet_type econet_packet_type = {
.type = __constant_htons(ETH_P_ECONET),
static struct packet_type econet_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_ECONET),
.func = econet_rcv,
};
+28 -22
View File
@@ -35,7 +35,7 @@ config IP_ADVANCED_ROUTER
at boot time after the /proc file system has been mounted.
If you turn on IP forwarding, you will also get the rp_filter, which
If you turn on IP forwarding, you should consider the rp_filter, which
automatically rejects incoming packets if the routing table entry
for their source address doesn't match the network interface they're
arriving on. This has security advantages because it prevents the
@@ -46,12 +46,16 @@ config IP_ADVANCED_ROUTER
rp_filter on use:
echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter
or
and
echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
Note that some distributions enable it in startup scripts.
For details about rp_filter strict and loose mode read
<file:Documentation/networking/ip-sysctl.txt>.
If unsure, say N here.
choice
choice
prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)"
depends on IP_ADVANCED_ROUTER
default ASK_IP_FIB_HASH
@@ -59,27 +63,29 @@ choice
config ASK_IP_FIB_HASH
bool "FIB_HASH"
---help---
Current FIB is very proven and good enough for most users.
Current FIB is very proven and good enough for most users.
config IP_FIB_TRIE
bool "FIB_TRIE"
---help---
Use new experimental LC-trie as FIB lookup algorithm.
This improves lookup performance if you have a large
number of routes.
Use new experimental LC-trie as FIB lookup algorithm.
This improves lookup performance if you have a large
number of routes.
LC-trie is a longest matching prefix lookup algorithm which
performs better than FIB_HASH for large routing tables.
But, it consumes more memory and is more complex.
LC-trie is described in:
IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
IEEE Journal on Selected Areas in Communications, 17(6):1083-1092,
June 1999
An experimental study of compression methods for dynamic tries
Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
LC-trie is a longest matching prefix lookup algorithm which
performs better than FIB_HASH for large routing tables.
But, it consumes more memory and is more complex.
LC-trie is described in:
IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
An experimental study of compression methods for dynamic tries
Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
endchoice
config IP_FIB_HASH
@@ -191,7 +197,7 @@ config IP_PNP_RARP
<file:Documentation/filesystems/nfsroot.txt> for details.
# not yet ready..
# bool ' IP: ARP support' CONFIG_IP_PNP_ARP
# bool ' IP: ARP support' CONFIG_IP_PNP_ARP
config NET_IPIP
tristate "IP: tunneling"
select INET_TUNNEL
@@ -361,7 +367,7 @@ config INET_IPCOMP
---help---
Support for IP Payload Compression Protocol (IPComp) (RFC3173),
typically needed for IPsec.
If unsure, say Y.
config INET_XFRM_TUNNEL
@@ -415,7 +421,7 @@ config INET_DIAG
Support for INET (TCP, DCCP, etc) socket monitoring interface used by
native Linux tools such as ss. ss is included in iproute2, currently
downloadable at <http://linux-net.osdl.org/index.php/Iproute2>.
If unsure, say Y.
config INET_TCP_DIAG
+14 -14
View File
@@ -369,7 +369,6 @@ lookup_protocol:
sock_init_data(sock, sk);
sk->sk_destruct = inet_sock_destruct;
sk->sk_family = PF_INET;
sk->sk_protocol = protocol;
sk->sk_backlog_rcv = sk->sk_prot->backlog_rcv;
@@ -1253,10 +1252,10 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
int proto;
int id;
if (unlikely(!pskb_may_pull(skb, sizeof(*iph))))
iph = skb_gro_header(skb, sizeof(*iph));
if (unlikely(!iph))
goto out;
iph = ip_hdr(skb);
proto = iph->protocol & (MAX_INET_PROTOS - 1);
rcu_read_lock();
@@ -1264,13 +1263,13 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
if (!ops || !ops->gro_receive)
goto out_unlock;
if (iph->version != 4 || iph->ihl != 5)
if (*(u8 *)iph != 0x45)
goto out_unlock;
if (unlikely(ip_fast_csum((u8 *)iph, iph->ihl)))
goto out_unlock;
flush = ntohs(iph->tot_len) != skb->len ||
flush = ntohs(iph->tot_len) != skb_gro_len(skb) ||
iph->frag_off != htons(IP_DF);
id = ntohs(iph->id);
@@ -1282,24 +1281,25 @@ static struct sk_buff **inet_gro_receive(struct sk_buff **head,
iph2 = ip_hdr(p);
if (iph->protocol != iph2->protocol ||
iph->tos != iph2->tos ||
memcmp(&iph->saddr, &iph2->saddr, 8)) {
if ((iph->protocol ^ iph2->protocol) |
(iph->tos ^ iph2->tos) |
(iph->saddr ^ iph2->saddr) |
(iph->daddr ^ iph2->daddr)) {
NAPI_GRO_CB(p)->same_flow = 0;
continue;
}
/* All fields must match except length and checksum. */
NAPI_GRO_CB(p)->flush |=
memcmp(&iph->frag_off, &iph2->frag_off, 4) ||
(u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) != id;
(iph->ttl ^ iph2->ttl) |
((u16)(ntohs(iph2->id) + NAPI_GRO_CB(p)->count) ^ id);
NAPI_GRO_CB(p)->flush |= flush;
}
NAPI_GRO_CB(skb)->flush |= flush;
__skb_pull(skb, sizeof(*iph));
skb_reset_transport_header(skb);
skb_gro_pull(skb, sizeof(*iph));
skb_set_transport_header(skb, skb_gro_offset(skb));
pp = ops->gro_receive(head, skb);
@@ -1500,8 +1500,8 @@ static int ipv4_proc_init(void);
* IP protocol layer initialiser
*/
static struct packet_type ip_packet_type = {
.type = __constant_htons(ETH_P_IP),
static struct packet_type ip_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_IP),
.func = ip_rcv,
.gso_send_check = inet_gso_send_check,
.gso_segment = inet_gso_segment,
+8 -5
View File
@@ -801,8 +801,11 @@ static int arp_process(struct sk_buff *skb)
* cache.
*/
/* Special case: IPv4 duplicate address detection packet (RFC2131) */
if (sip == 0) {
/*
* Special case: IPv4 duplicate address detection packet (RFC2131)
* and Gratuitous ARP/ARP Announce. (RFC3927, Section 2.4)
*/
if (sip == 0 || tip == sip) {
if (arp->ar_op == htons(ARPOP_REQUEST) &&
inet_addr_type(net, tip) == RTN_LOCAL &&
!arp_ignore(in_dev, sip, tip))
@@ -892,7 +895,7 @@ static int arp_process(struct sk_buff *skb)
out:
if (in_dev)
in_dev_put(in_dev);
kfree_skb(skb);
consume_skb(skb);
return 0;
}
@@ -1225,8 +1228,8 @@ void arp_ifdown(struct net_device *dev)
* Called once on startup.
*/
static struct packet_type arp_packet_type = {
.type = __constant_htons(ETH_P_ARP),
static struct packet_type arp_packet_type __read_mostly = {
.type = cpu_to_be16(ETH_P_ARP),
.func = arp_rcv,
};
+118 -12
View File
@@ -1942,23 +1942,85 @@ socket_setattr_failure:
}
/**
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
* @sk: the socket
* cipso_v4_req_setattr - Add a CIPSO option to a connection request socket
* @req: the connection request socket
* @doi_def: the CIPSO DOI to use
* @secattr: the specific security attributes of the socket
*
* Description:
* Removes the CIPSO option from a socket, if present.
* Set the CIPSO option on the given socket using the DOI definition and
* security attributes passed to the function. Returns zero on success and
* negative values on failure.
*
*/
void cipso_v4_sock_delattr(struct sock *sk)
int cipso_v4_req_setattr(struct request_sock *req,
const struct cipso_v4_doi *doi_def,
const struct netlbl_lsm_secattr *secattr)
{
u8 hdr_delta;
struct ip_options *opt;
struct inet_sock *sk_inet;
int ret_val = -EPERM;
unsigned char *buf = NULL;
u32 buf_len;
u32 opt_len;
struct ip_options *opt = NULL;
struct inet_request_sock *req_inet;
sk_inet = inet_sk(sk);
opt = sk_inet->opt;
if (opt == NULL || opt->cipso == 0)
return;
/* We allocate the maximum CIPSO option size here so we are probably
* being a little wasteful, but it makes our life _much_ easier later
* on and after all we are only talking about 40 bytes. */
buf_len = CIPSO_V4_OPT_LEN_MAX;
buf = kmalloc(buf_len, GFP_ATOMIC);
if (buf == NULL) {
ret_val = -ENOMEM;
goto req_setattr_failure;
}
ret_val = cipso_v4_genopt(buf, buf_len, doi_def, secattr);
if (ret_val < 0)
goto req_setattr_failure;
buf_len = ret_val;
/* We can't use ip_options_get() directly because it makes a call to
* ip_options_get_alloc() which allocates memory with GFP_KERNEL and
* we won't always have CAP_NET_RAW even though we _always_ want to
* set the IPOPT_CIPSO option. */
opt_len = (buf_len + 3) & ~3;
opt = kzalloc(sizeof(*opt) + opt_len, GFP_ATOMIC);
if (opt == NULL) {
ret_val = -ENOMEM;
goto req_setattr_failure;
}
memcpy(opt->__data, buf, buf_len);
opt->optlen = opt_len;
opt->cipso = sizeof(struct iphdr);
kfree(buf);
buf = NULL;
req_inet = inet_rsk(req);
opt = xchg(&req_inet->opt, opt);
kfree(opt);
return 0;
req_setattr_failure:
kfree(buf);
kfree(opt);
return ret_val;
}
/**
* cipso_v4_delopt - Delete the CIPSO option from a set of IP options
* @opt_ptr: IP option pointer
*
* Description:
* Deletes the CIPSO IP option from a set of IP options and makes the necessary
* adjustments to the IP option structure. Returns zero on success, negative
* values on failure.
*
*/
int cipso_v4_delopt(struct ip_options **opt_ptr)
{
int hdr_delta = 0;
struct ip_options *opt = *opt_ptr;
if (opt->srr || opt->rr || opt->ts || opt->router_alert) {
u8 cipso_len;
@@ -2003,11 +2065,34 @@ void cipso_v4_sock_delattr(struct sock *sk)
} else {
/* only the cipso option was present on the socket so we can
* remove the entire option struct */
sk_inet->opt = NULL;
*opt_ptr = NULL;
hdr_delta = opt->optlen;
kfree(opt);
}
return hdr_delta;
}
/**
* cipso_v4_sock_delattr - Delete the CIPSO option from a socket
* @sk: the socket
*
* Description:
* Removes the CIPSO option from a socket, if present.
*
*/
void cipso_v4_sock_delattr(struct sock *sk)
{
int hdr_delta;
struct ip_options *opt;
struct inet_sock *sk_inet;
sk_inet = inet_sk(sk);
opt = sk_inet->opt;
if (opt == NULL || opt->cipso == 0)
return;
hdr_delta = cipso_v4_delopt(&sk_inet->opt);
if (sk_inet->is_icsk && hdr_delta > 0) {
struct inet_connection_sock *sk_conn = inet_csk(sk);
sk_conn->icsk_ext_hdr_len -= hdr_delta;
@@ -2015,6 +2100,27 @@ void cipso_v4_sock_delattr(struct sock *sk)
}
}
/**
* cipso_v4_req_delattr - Delete the CIPSO option from a request socket
* @reg: the request socket
*
* Description:
* Removes the CIPSO option from a request socket, if present.
*
*/
void cipso_v4_req_delattr(struct request_sock *req)
{
struct ip_options *opt;
struct inet_request_sock *req_inet;
req_inet = inet_rsk(req);
opt = req_inet->opt;
if (opt == NULL || opt->cipso == 0)
return;
cipso_v4_delopt(&req_inet->opt);
}
/**
* cipso_v4_getattr - Helper function for the cipso_v4_*_getattr functions
* @cipso: the CIPSO v4 option
+11 -1
View File
@@ -1075,6 +1075,14 @@ static int inetdev_event(struct notifier_block *this, unsigned long event,
}
}
ip_mc_up(in_dev);
/* fall through */
case NETDEV_CHANGEADDR:
if (IN_DEV_ARP_NOTIFY(in_dev))
arp_send(ARPOP_REQUEST, ETH_P_ARP,
in_dev->ifa_list->ifa_address,
dev,
in_dev->ifa_list->ifa_address,
NULL, dev->dev_addr, NULL);
break;
case NETDEV_DOWN:
ip_mc_down(in_dev);
@@ -1208,7 +1216,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
@@ -1439,6 +1448,7 @@ static struct devinet_sysctl_table {
DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"),
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_FLUSHING_ENTRY(NOXFRM, "disable_xfrm"),
DEVINET_SYSCTL_FLUSHING_ENTRY(NOPOLICY, "disable_policy"),
+1 -1
View File
@@ -275,7 +275,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
fib_res_put(&res);
if (no_addr)
goto last_resort;
if (rpf)
if (rpf == 1)
goto e_inval;
fl.oif = dev->ifindex;
+3 -2
View File
@@ -322,8 +322,9 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
kfree_skb(skb);
goto errout;
}
err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);
rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
info->nlh, GFP_KERNEL);
return;
errout:
if (err < 0)
rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
+2
View File
@@ -375,6 +375,7 @@ static void icmp_reply(struct icmp_bxm *icmp_param, struct sk_buff *skb)
inet->tos = ip_hdr(skb)->tos;
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
ipc.shtx.flags = 0;
if (icmp_param->replyopts.optlen) {
ipc.opt = &icmp_param->replyopts;
if (ipc.opt->srr)
@@ -532,6 +533,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, __be32 info)
inet_sk(sk)->tos = tos;
ipc.addr = iph->saddr;
ipc.opt = &icmp_param.replyopts;
ipc.shtx.flags = 0;
{
struct flowi fl = {
+35 -7
View File
@@ -93,24 +93,40 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
struct inet_bind_hashbucket *head;
struct hlist_node *node;
struct inet_bind_bucket *tb;
int ret;
int ret, attempts = 5;
struct net *net = sock_net(sk);
int smallest_size = -1, smallest_rover;
local_bh_disable();
if (!snum) {
int remaining, rover, low, high;
again:
inet_get_local_port_range(&low, &high);
remaining = (high - low) + 1;
rover = net_random() % remaining + low;
smallest_rover = rover = net_random() % remaining + low;
smallest_size = -1;
do {
head = &hashinfo->bhash[inet_bhashfn(net, rover,
hashinfo->bhash_size)];
spin_lock(&head->lock);
inet_bind_bucket_for_each(tb, node, &head->chain)
if (ib_net(tb) == net && tb->port == rover)
if (ib_net(tb) == net && tb->port == rover) {
if (tb->fastreuse > 0 &&
sk->sk_reuse &&
sk->sk_state != TCP_LISTEN &&
(tb->num_owners < smallest_size || smallest_size == -1)) {
smallest_size = tb->num_owners;
smallest_rover = rover;
if (atomic_read(&hashinfo->bsockets) > (high - low) + 1) {
spin_unlock(&head->lock);
snum = smallest_rover;
goto have_snum;
}
}
goto next;
}
break;
next:
spin_unlock(&head->lock);
@@ -125,14 +141,19 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
* the top level, not from the 'break;' statement.
*/
ret = 1;
if (remaining <= 0)
if (remaining <= 0) {
if (smallest_size != -1) {
snum = smallest_rover;
goto have_snum;
}
goto fail;
}
/* OK, here is the one we will use. HEAD is
* non-NULL and we hold it's mutex.
*/
snum = rover;
} else {
have_snum:
head = &hashinfo->bhash[inet_bhashfn(net, snum,
hashinfo->bhash_size)];
spin_lock(&head->lock);
@@ -145,12 +166,19 @@ int inet_csk_get_port(struct sock *sk, unsigned short snum)
tb_found:
if (!hlist_empty(&tb->owners)) {
if (tb->fastreuse > 0 &&
sk->sk_reuse && sk->sk_state != TCP_LISTEN) {
sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
smallest_size == -1) {
goto success;
} else {
ret = 1;
if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb))
if (inet_csk(sk)->icsk_af_ops->bind_conflict(sk, tb)) {
if (sk->sk_reuse && sk->sk_state != TCP_LISTEN &&
smallest_size != -1 && --attempts >= 0) {
spin_unlock(&head->lock);
goto again;
}
goto fail_unlock;
}
}
}
tb_not_found:
+1
View File
@@ -267,6 +267,7 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
struct inet_frags *f, void *key, unsigned int hash)
__releases(&f->lock)
{
struct inet_frag_queue *q;
struct hlist_node *n;
+11 -1
View File
@@ -38,6 +38,7 @@ struct inet_bind_bucket *inet_bind_bucket_create(struct kmem_cache *cachep,
write_pnet(&tb->ib_net, hold_net(net));
tb->port = snum;
tb->fastreuse = 0;
tb->num_owners = 0;
INIT_HLIST_HEAD(&tb->owners);
hlist_add_head(&tb->node, &head->chain);
}
@@ -59,8 +60,13 @@ void inet_bind_bucket_destroy(struct kmem_cache *cachep, struct inet_bind_bucket
void inet_bind_hash(struct sock *sk, struct inet_bind_bucket *tb,
const unsigned short snum)
{
struct inet_hashinfo *hashinfo = sk->sk_prot->h.hashinfo;
atomic_inc(&hashinfo->bsockets);
inet_sk(sk)->num = snum;
sk_add_bind_node(sk, &tb->owners);
tb->num_owners++;
inet_csk(sk)->icsk_bind_hash = tb;
}
@@ -75,9 +81,12 @@ static void __inet_put_port(struct sock *sk)
struct inet_bind_hashbucket *head = &hashinfo->bhash[bhash];
struct inet_bind_bucket *tb;
atomic_dec(&hashinfo->bsockets);
spin_lock(&head->lock);
tb = inet_csk(sk)->icsk_bind_hash;
__sk_del_bind_node(sk);
tb->num_owners--;
inet_csk(sk)->icsk_bind_hash = NULL;
inet_sk(sk)->num = 0;
inet_bind_bucket_destroy(hashinfo->bind_bucket_cachep, tb);
@@ -444,9 +453,9 @@ int __inet_hash_connect(struct inet_timewait_death_row *death_row,
*/
inet_bind_bucket_for_each(tb, node, &head->chain) {
if (ib_net(tb) == net && tb->port == port) {
WARN_ON(hlist_empty(&tb->owners));
if (tb->fastreuse >= 0)
goto next_port;
WARN_ON(hlist_empty(&tb->owners));
if (!check_established(death_row, sk,
port, &tw))
goto ok;
@@ -523,6 +532,7 @@ void inet_hashinfo_init(struct inet_hashinfo *h)
{
int i;
atomic_set(&h->bsockets, 0);
for (i = 0; i < INET_LHTABLE_SIZE; i++) {
spin_lock_init(&h->listening_hash[i].lock);
INIT_HLIST_NULLS_HEAD(&h->listening_hash[i].head,
+2 -1
View File
@@ -463,6 +463,7 @@ err:
static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
struct net_device *dev)
{
struct net *net = container_of(qp->q.net, struct net, ipv4.frags);
struct iphdr *iph;
struct sk_buff *fp, *head = qp->q.fragments;
int len;
@@ -548,7 +549,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
iph = ip_hdr(head);
iph->frag_off = 0;
iph->tot_len = htons(len);
IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMOKS);
IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
qp->q.fragments = NULL;
return 0;
+98 -38
View File
@@ -164,67 +164,124 @@ static DEFINE_RWLOCK(ipgre_lock);
/* Given src, dst and key, find appropriate for input tunnel. */
static struct ip_tunnel * ipgre_tunnel_lookup(struct net *net,
static struct ip_tunnel * ipgre_tunnel_lookup(struct net_device *dev,
__be32 remote, __be32 local,
__be32 key, __be16 gre_proto)
{
struct net *net = dev_net(dev);
int link = dev->ifindex;
unsigned h0 = HASH(remote);
unsigned h1 = HASH(key);
struct ip_tunnel *t;
struct ip_tunnel *t2 = NULL;
struct ip_tunnel *t, *cand = NULL;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
int dev_type = (gre_proto == htons(ETH_P_TEB)) ?
ARPHRD_ETHER : ARPHRD_IPGRE;
int score, cand_score = 4;
for (t = ign->tunnels_r_l[h0^h1]; t; t = t->next) {
if (local == t->parms.iph.saddr && remote == t->parms.iph.daddr) {
if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
if (t->dev->type == dev_type)
return t;
if (t->dev->type == ARPHRD_IPGRE && !t2)
t2 = t;
}
if (local != t->parms.iph.saddr ||
remote != t->parms.iph.daddr ||
key != t->parms.i_key ||
!(t->dev->flags & IFF_UP))
continue;
if (t->dev->type != ARPHRD_IPGRE &&
t->dev->type != dev_type)
continue;
score = 0;
if (t->parms.link != link)
score |= 1;
if (t->dev->type != dev_type)
score |= 2;
if (score == 0)
return t;
if (score < cand_score) {
cand = t;
cand_score = score;
}
}
for (t = ign->tunnels_r[h0^h1]; t; t = t->next) {
if (remote == t->parms.iph.daddr) {
if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
if (t->dev->type == dev_type)
return t;
if (t->dev->type == ARPHRD_IPGRE && !t2)
t2 = t;
}
if (remote != t->parms.iph.daddr ||
key != t->parms.i_key ||
!(t->dev->flags & IFF_UP))
continue;
if (t->dev->type != ARPHRD_IPGRE &&
t->dev->type != dev_type)
continue;
score = 0;
if (t->parms.link != link)
score |= 1;
if (t->dev->type != dev_type)
score |= 2;
if (score == 0)
return t;
if (score < cand_score) {
cand = t;
cand_score = score;
}
}
for (t = ign->tunnels_l[h1]; t; t = t->next) {
if (local == t->parms.iph.saddr ||
(local == t->parms.iph.daddr &&
ipv4_is_multicast(local))) {
if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
if (t->dev->type == dev_type)
return t;
if (t->dev->type == ARPHRD_IPGRE && !t2)
t2 = t;
}
if ((local != t->parms.iph.saddr &&
(local != t->parms.iph.daddr ||
!ipv4_is_multicast(local))) ||
key != t->parms.i_key ||
!(t->dev->flags & IFF_UP))
continue;
if (t->dev->type != ARPHRD_IPGRE &&
t->dev->type != dev_type)
continue;
score = 0;
if (t->parms.link != link)
score |= 1;
if (t->dev->type != dev_type)
score |= 2;
if (score == 0)
return t;
if (score < cand_score) {
cand = t;
cand_score = score;
}
}
for (t = ign->tunnels_wc[h1]; t; t = t->next) {
if (t->parms.i_key == key && t->dev->flags & IFF_UP) {
if (t->dev->type == dev_type)
return t;
if (t->dev->type == ARPHRD_IPGRE && !t2)
t2 = t;
if (t->parms.i_key != key ||
!(t->dev->flags & IFF_UP))
continue;
if (t->dev->type != ARPHRD_IPGRE &&
t->dev->type != dev_type)
continue;
score = 0;
if (t->parms.link != link)
score |= 1;
if (t->dev->type != dev_type)
score |= 2;
if (score == 0)
return t;
if (score < cand_score) {
cand = t;
cand_score = score;
}
}
if (t2)
return t2;
if (cand != NULL)
return cand;
if (ign->fb_tunnel_dev->flags&IFF_UP)
if (ign->fb_tunnel_dev->flags & IFF_UP)
return netdev_priv(ign->fb_tunnel_dev);
return NULL;
}
@@ -284,6 +341,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
__be32 remote = parms->iph.daddr;
__be32 local = parms->iph.saddr;
__be32 key = parms->i_key;
int link = parms->link;
struct ip_tunnel *t, **tp;
struct ipgre_net *ign = net_generic(net, ipgre_net_id);
@@ -291,6 +349,7 @@ static struct ip_tunnel *ipgre_tunnel_find(struct net *net,
if (local == t->parms.iph.saddr &&
remote == t->parms.iph.daddr &&
key == t->parms.i_key &&
link == t->parms.link &&
type == t->dev->type)
break;
@@ -421,7 +480,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
}
read_lock(&ipgre_lock);
t = ipgre_tunnel_lookup(dev_net(skb->dev), iph->daddr, iph->saddr,
t = ipgre_tunnel_lookup(skb->dev, iph->daddr, iph->saddr,
flags & GRE_KEY ?
*(((__be32 *)p) + (grehlen / 4) - 1) : 0,
p[1]);
@@ -432,7 +491,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
goto out;
if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
t->err_count++;
else
t->err_count = 1;
@@ -518,7 +577,7 @@ static int ipgre_rcv(struct sk_buff *skb)
gre_proto = *(__be16 *)(h + 2);
read_lock(&ipgre_lock);
if ((tunnel = ipgre_tunnel_lookup(dev_net(skb->dev),
if ((tunnel = ipgre_tunnel_lookup(skb->dev,
iph->saddr, iph->daddr, key,
gre_proto))) {
struct net_device_stats *stats = &tunnel->dev->stats;
@@ -744,7 +803,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
#endif
if (tunnel->err_count > 0) {
if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
if (time_before(jiffies,
tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
tunnel->err_count--;
dst_link_failure(skb);
+6
View File
@@ -935,6 +935,10 @@ alloc_new_skb:
sk->sk_allocation);
if (unlikely(skb == NULL))
err = -ENOBUFS;
else
/* only the initial fragment is
time stamped */
ipc->shtx.flags = 0;
}
if (skb == NULL)
goto error;
@@ -945,6 +949,7 @@ alloc_new_skb:
skb->ip_summed = csummode;
skb->csum = 0;
skb_reserve(skb, hh_len);
*skb_tx(skb) = ipc->shtx;
/*
* Find where to start putting bytes.
@@ -1364,6 +1369,7 @@ void ip_send_reply(struct sock *sk, struct sk_buff *skb, struct ip_reply_arg *ar
daddr = ipc.addr = rt->rt_src;
ipc.opt = NULL;
ipc.shtx.flags = 0;
if (replyopts.opt.optlen) {
ipc.opt = &replyopts.opt;
+4 -4
View File
@@ -100,8 +100,8 @@
#define CONF_NAMESERVERS_MAX 3 /* Maximum number of nameservers
- '3' from resolv.h */
#define NONE __constant_htonl(INADDR_NONE)
#define ANY __constant_htonl(INADDR_ANY)
#define NONE cpu_to_be32(INADDR_NONE)
#define ANY cpu_to_be32(INADDR_ANY)
/*
* Public IP configuration
@@ -406,7 +406,7 @@ static int __init ic_defaults(void)
static int ic_rarp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
static struct packet_type rarp_packet_type __initdata = {
.type = __constant_htons(ETH_P_RARP),
.type = cpu_to_be16(ETH_P_RARP),
.func = ic_rarp_recv,
};
@@ -568,7 +568,7 @@ struct bootp_pkt { /* BOOTP packet format */
static int ic_bootp_recv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev);
static struct packet_type bootp_packet_type __initdata = {
.type = __constant_htons(ETH_P_IP),
.type = cpu_to_be16(ETH_P_IP),
.func = ic_bootp_recv,
};
+4 -3
View File
@@ -327,7 +327,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
goto out;
if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
t->err_count++;
else
t->err_count = 1;
@@ -466,7 +466,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
}
if (tunnel->err_count > 0) {
if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
if (time_before(jiffies,
tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
tunnel->err_count--;
dst_link_failure(skb);
} else
@@ -750,7 +751,7 @@ static struct xfrm_tunnel ipip_handler = {
.priority = 1,
};
static char banner[] __initdata =
static const char banner[] __initconst =
KERN_INFO "IPv4 over IPv4 tunneling driver\n";
static void ipip_destroy_tunnels(struct ipip_net *ipn)
+282 -182
View File
File diff suppressed because it is too large Load Diff
+12 -18
View File
@@ -31,7 +31,7 @@ config NF_CONNTRACK_PROC_COMPAT
default y
help
This option enables /proc and sysctl compatibility with the old
layer 3 dependant connection tracking. This is needed to keep
layer 3 dependent connection tracking. This is needed to keep
old programs that have not been adapted to the new names working.
If unsure, say Y.
@@ -95,11 +95,11 @@ config IP_NF_MATCH_ECN
config IP_NF_MATCH_TTL
tristate '"ttl" match support'
depends on NETFILTER_ADVANCED
help
This adds CONFIG_IP_NF_MATCH_TTL option, which enabled the user
to match packets by their TTL value.
To compile it as a module, choose M here. If unsure, say N.
select NETFILTER_XT_MATCH_HL
---help---
This is a backwards-compat option for the user's convenience
(e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_MATCH_HL.
# `filter', generic and specific targets
config IP_NF_FILTER
@@ -323,19 +323,13 @@ config IP_NF_TARGET_ECN
To compile it as a module, choose M here. If unsure, say N.
config IP_NF_TARGET_TTL
tristate 'TTL target support'
depends on IP_NF_MANGLE
tristate '"TTL" target support'
depends on NETFILTER_ADVANCED
help
This option adds a `TTL' target, which enables the user to modify
the TTL value of the IP header.
While it is safe to decrement/lower the TTL, this target also enables
functionality to increment and set the TTL value of the IP header to
arbitrary values. This is EXTREMELY DANGEROUS since you can easily
create immortal packets that loop forever on the network.
To compile it as a module, choose M here. If unsure, say N.
select NETFILTER_XT_TARGET_HL
---help---
This is a backwards-compat option for the user's convenience
(e.g. when running oldconfig). It selects
CONFIG_NETFILTER_XT_TARGET_HL.
# raw + specific targets
config IP_NF_RAW
-2
View File
@@ -51,7 +51,6 @@ obj-$(CONFIG_IP_NF_SECURITY) += iptable_security.o
obj-$(CONFIG_IP_NF_MATCH_ADDRTYPE) += ipt_addrtype.o
obj-$(CONFIG_IP_NF_MATCH_AH) += ipt_ah.o
obj-$(CONFIG_IP_NF_MATCH_ECN) += ipt_ecn.o
obj-$(CONFIG_IP_NF_MATCH_TTL) += ipt_ttl.o
# targets
obj-$(CONFIG_IP_NF_TARGET_CLUSTERIP) += ipt_CLUSTERIP.o
@@ -61,7 +60,6 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += ipt_MASQUERADE.o
obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o
obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o
obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o
obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o
obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o
# generic ARP tables
+117 -38
View File
@@ -73,6 +73,28 @@ static inline int arp_devaddr_compare(const struct arpt_devaddr_info *ap,
return (ret != 0);
}
/*
* Unfortunatly, _b and _mask are not aligned to an int (or long int)
* Some arches dont care, unrolling the loop is a win on them.
* For other arches, we only have a 16bit alignement.
*/
static unsigned long ifname_compare(const char *_a, const char *_b, const char *_mask)
{
#ifdef CONFIG_HAVE_EFFICIENT_UNALIGNED_ACCESS
unsigned long ret = ifname_compare_aligned(_a, _b, _mask);
#else
unsigned long ret = 0;
const u16 *a = (const u16 *)_a;
const u16 *b = (const u16 *)_b;
const u16 *mask = (const u16 *)_mask;
int i;
for (i = 0; i < IFNAMSIZ/sizeof(u16); i++)
ret |= (a[i] ^ b[i]) & mask[i];
#endif
return ret;
}
/* Returns whether packet matches rule or not. */
static inline int arp_packet_match(const struct arphdr *arphdr,
struct net_device *dev,
@@ -83,7 +105,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
const char *arpptr = (char *)(arphdr + 1);
const char *src_devaddr, *tgt_devaddr;
__be32 src_ipaddr, tgt_ipaddr;
int i, ret;
long ret;
#define FWINV(bool, invflg) ((bool) ^ !!(arpinfo->invflags & (invflg)))
@@ -156,10 +178,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
}
/* Look for ifname matches. */
for (i = 0, ret = 0; i < IFNAMSIZ; i++) {
ret |= (indev[i] ^ arpinfo->iniface[i])
& arpinfo->iniface_mask[i];
}
ret = ifname_compare(indev, arpinfo->iniface, arpinfo->iniface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_IN)) {
dprintf("VIA in mismatch (%s vs %s).%s\n",
@@ -168,10 +187,7 @@ static inline int arp_packet_match(const struct arphdr *arphdr,
return 0;
}
for (i = 0, ret = 0; i < IFNAMSIZ; i++) {
ret |= (outdev[i] ^ arpinfo->outiface[i])
& arpinfo->outiface_mask[i];
}
ret = ifname_compare(outdev, arpinfo->outiface, arpinfo->outiface_mask);
if (FWINV(ret != 0, ARPT_INV_VIA_OUT)) {
dprintf("VIA out mismatch (%s vs %s).%s\n",
@@ -221,7 +237,7 @@ unsigned int arpt_do_table(struct sk_buff *skb,
const struct net_device *out,
struct xt_table *table)
{
static const char nulldevname[IFNAMSIZ];
static const char nulldevname[IFNAMSIZ] __attribute__((aligned(sizeof(long))));
unsigned int verdict = NF_DROP;
const struct arphdr *arp;
bool hotdrop = false;
@@ -237,9 +253,10 @@ unsigned int arpt_do_table(struct sk_buff *skb,
indev = in ? in->name : nulldevname;
outdev = out ? out->name : nulldevname;
read_lock_bh(&table->lock);
private = table->private;
table_base = (void *)private->entries[smp_processor_id()];
rcu_read_lock();
private = rcu_dereference(table->private);
table_base = rcu_dereference(private->entries[smp_processor_id()]);
e = get_entry(table_base, private->hook_entry[hook]);
back = get_entry(table_base, private->underflow[hook]);
@@ -311,7 +328,8 @@ unsigned int arpt_do_table(struct sk_buff *skb,
e = (void *)e + e->next_offset;
}
} while (!hotdrop);
read_unlock_bh(&table->lock);
rcu_read_unlock();
if (hotdrop)
return NF_DROP;
@@ -374,7 +392,9 @@ static int mark_source_chains(struct xt_table_info *newinfo,
&& unconditional(&e->arp)) || visited) {
unsigned int oldpos, size;
if (t->verdict < -NF_MAX_VERDICT - 1) {
if ((strcmp(t->target.u.user.name,
ARPT_STANDARD_TARGET) == 0) &&
t->verdict < -NF_MAX_VERDICT - 1) {
duprintf("mark_source_chains: bad "
"negative verdict (%i)\n",
t->verdict);
@@ -714,11 +734,65 @@ static void get_counters(const struct xt_table_info *t,
}
}
static inline struct xt_counters *alloc_counters(struct xt_table *table)
/* We're lazy, and add to the first CPU; overflow works its fey magic
* and everything is OK. */
static int
add_counter_to_entry(struct arpt_entry *e,
const struct xt_counters addme[],
unsigned int *i)
{
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
(*i)++;
return 0;
}
/* Take values from counters and add them back onto the current cpu */
static void put_counters(struct xt_table_info *t,
const struct xt_counters counters[])
{
unsigned int i, cpu;
local_bh_disable();
cpu = smp_processor_id();
i = 0;
ARPT_ENTRY_ITERATE(t->entries[cpu],
t->size,
add_counter_to_entry,
counters,
&i);
local_bh_enable();
}
static inline int
zero_entry_counter(struct arpt_entry *e, void *arg)
{
e->counters.bcnt = 0;
e->counters.pcnt = 0;
return 0;
}
static void
clone_counters(struct xt_table_info *newinfo, const struct xt_table_info *info)
{
unsigned int cpu;
const void *loc_cpu_entry = info->entries[raw_smp_processor_id()];
memcpy(newinfo, info, offsetof(struct xt_table_info, entries));
for_each_possible_cpu(cpu) {
memcpy(newinfo->entries[cpu], loc_cpu_entry, info->size);
ARPT_ENTRY_ITERATE(newinfo->entries[cpu], newinfo->size,
zero_entry_counter, NULL);
}
}
static struct xt_counters *alloc_counters(struct xt_table *table)
{
unsigned int countersize;
struct xt_counters *counters;
const struct xt_table_info *private = table->private;
struct xt_table_info *private = table->private;
struct xt_table_info *info;
/* We need atomic snapshot of counters: rest doesn't change
* (other than comefrom, which userspace doesn't care
@@ -728,14 +802,30 @@ static inline struct xt_counters *alloc_counters(struct xt_table *table)
counters = vmalloc_node(countersize, numa_node_id());
if (counters == NULL)
return ERR_PTR(-ENOMEM);
goto nomem;
/* First, sum counters... */
write_lock_bh(&table->lock);
get_counters(private, counters);
write_unlock_bh(&table->lock);
info = xt_alloc_table_info(private->size);
if (!info)
goto free_counters;
clone_counters(info, private);
mutex_lock(&table->lock);
xt_table_entry_swap_rcu(private, info);
synchronize_net(); /* Wait until smoke has cleared */
get_counters(info, counters);
put_counters(private, counters);
mutex_unlock(&table->lock);
xt_free_table_info(info);
return counters;
free_counters:
vfree(counters);
nomem:
return ERR_PTR(-ENOMEM);
}
static int copy_entries_to_user(unsigned int total_size,
@@ -1075,20 +1165,6 @@ static int do_replace(struct net *net, void __user *user, unsigned int len)
return ret;
}
/* We're lazy, and add to the first CPU; overflow works its fey magic
* and everything is OK.
*/
static inline int add_counter_to_entry(struct arpt_entry *e,
const struct xt_counters addme[],
unsigned int *i)
{
ADD_COUNTER(e->counters, addme[*i].bcnt, addme[*i].pcnt);
(*i)++;
return 0;
}
static int do_add_counters(struct net *net, void __user *user, unsigned int len,
int compat)
{
@@ -1148,13 +1224,14 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
goto free;
}
write_lock_bh(&t->lock);
mutex_lock(&t->lock);
private = t->private;
if (private->number != num_counters) {
ret = -EINVAL;
goto unlock_up_free;
}
preempt_disable();
i = 0;
/* Choose the copy that is on our node */
loc_cpu_entry = private->entries[smp_processor_id()];
@@ -1163,8 +1240,10 @@ static int do_add_counters(struct net *net, void __user *user, unsigned int len,
add_counter_to_entry,
paddc,
&i);
preempt_enable();
unlock_up_free:
write_unlock_bh(&t->lock);
mutex_unlock(&t->lock);
xt_table_unlock(t);
module_put(t->me);
free:
-2
View File
@@ -48,8 +48,6 @@ static struct
static struct xt_table packet_filter = {
.name = "filter",
.valid_hooks = FILTER_VALID_HOOKS,
.lock = __RW_LOCK_UNLOCKED(packet_filter.lock),
.private = NULL,
.me = THIS_MODULE,
.af = NFPROTO_ARP,
};

Some files were not shown because too many files have changed in this diff Show More