Merge branch 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
* 'upstream-linus' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6: (48 commits) [PATCH] bonding: update version number [PATCH] git-netdev-all: pc300_tty build fix [PATCH] Make PC300 WAN driver compile again [PATCH] Modularize generic HDLC [PATCH] more s2io __iomem annotations [PATCH] restore __iomem annotations in e1000 [PATCH] 64bit bugs in s2io [PATCH] bonding: Fix primary selection error at enslavement time [PATCH] bonding: Don't mangle LACPDUs [PATCH] bonding: Validate probe replies in ARP monitor [PATCH] bonding: Don't release slaves when master is admin down [PATCH] bonding: Add priv_flag to avoid event mishandling [PATCH] bonding: Handle large hard_header_len [PATCH] bonding: Remove unneeded NULL test [PATCH] bonding: Format fix in seq_printf call [PATCH] bonding: Convert delay value from s16 to int [PATCH] bonding: Allow bonding to enslave a 10 Gig adapter Delete unused drivers/net/gt64240eth.h [PATCH] skge: fiber support [PATCH] fix possible NULL ptr deref in forcedeth ...
This commit is contained in:
commit
a77c64c1a6
@ -192,6 +192,17 @@ or, for backwards compatibility, the option value. E.g.,
|
||||
arp_interval
|
||||
|
||||
Specifies the ARP link monitoring frequency in milliseconds.
|
||||
|
||||
The ARP monitor works by periodically checking the slave
|
||||
devices to determine whether they have sent or received
|
||||
traffic recently (the precise criteria depends upon the
|
||||
bonding mode, and the state of the slave). Regular traffic is
|
||||
generated via ARP probes issued for the addresses specified by
|
||||
the arp_ip_target option.
|
||||
|
||||
This behavior can be modified by the arp_validate option,
|
||||
below.
|
||||
|
||||
If ARP monitoring is used in an etherchannel compatible mode
|
||||
(modes 0 and 2), the switch should be configured in a mode
|
||||
that evenly distributes packets across all links. If the
|
||||
@ -213,6 +224,54 @@ arp_ip_target
|
||||
maximum number of targets that can be specified is 16. The
|
||||
default value is no IP addresses.
|
||||
|
||||
arp_validate
|
||||
|
||||
Specifies whether or not ARP probes and replies should be
|
||||
validated in the active-backup mode. This causes the ARP
|
||||
monitor to examine the incoming ARP requests and replies, and
|
||||
only consider a slave to be up if it is receiving the
|
||||
appropriate ARP traffic.
|
||||
|
||||
Possible values are:
|
||||
|
||||
none or 0
|
||||
|
||||
No validation is performed. This is the default.
|
||||
|
||||
active or 1
|
||||
|
||||
Validation is performed only for the active slave.
|
||||
|
||||
backup or 2
|
||||
|
||||
Validation is performed only for backup slaves.
|
||||
|
||||
all or 3
|
||||
|
||||
Validation is performed for all slaves.
|
||||
|
||||
For the active slave, the validation checks ARP replies to
|
||||
confirm that they were generated by an arp_ip_target. Since
|
||||
backup slaves do not typically receive these replies, the
|
||||
validation performed for backup slaves is on the ARP request
|
||||
sent out via the active slave. It is possible that some
|
||||
switch or network configurations may result in situations
|
||||
wherein the backup slaves do not receive the ARP requests; in
|
||||
such a situation, validation of backup slaves must be
|
||||
disabled.
|
||||
|
||||
This option is useful in network configurations in which
|
||||
multiple bonding hosts are concurrently issuing ARPs to one or
|
||||
more targets beyond a common switch. Should the link between
|
||||
the switch and target fail (but not the switch itself), the
|
||||
probe traffic generated by the multiple bonding instances will
|
||||
fool the standard ARP monitor into considering the links as
|
||||
still up. Use of the arp_validate option can resolve this, as
|
||||
the ARP monitor will only consider ARP requests and replies
|
||||
associated with its own instance of bonding.
|
||||
|
||||
This option was added in bonding version 3.1.0.
|
||||
|
||||
downdelay
|
||||
|
||||
Specifies the time, in milliseconds, to wait before disabling
|
||||
|
@ -2679,7 +2679,6 @@ M: josejx@gentoo.org
|
||||
P: Daniel Drake
|
||||
M: dsd@gentoo.org
|
||||
W: http://softmac.sipsolutions.net/
|
||||
L: softmac-dev@sipsolutions.net
|
||||
L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
|
||||
|
@ -163,11 +163,7 @@ MODULE_DEVICE_TABLE(pci, acenic_pci_tbl);
|
||||
#define SET_NETDEV_DEV(net, pdev) do{} while(0)
|
||||
#endif
|
||||
|
||||
#if LINUX_VERSION_CODE >= 0x2051c
|
||||
#define ace_sync_irq(irq) synchronize_irq(irq)
|
||||
#else
|
||||
#define ace_sync_irq(irq) synchronize_irq()
|
||||
#endif
|
||||
|
||||
#ifndef offset_in_page
|
||||
#define offset_in_page(ptr) ((unsigned long)(ptr) & ~PAGE_MASK)
|
||||
|
@ -85,6 +85,7 @@
|
||||
#define AD_LINK_SPEED_BITMASK_10MBPS 0x2
|
||||
#define AD_LINK_SPEED_BITMASK_100MBPS 0x4
|
||||
#define AD_LINK_SPEED_BITMASK_1000MBPS 0x8
|
||||
#define AD_LINK_SPEED_BITMASK_10000MBPS 0x10
|
||||
//endalloun
|
||||
|
||||
// compare MAC addresses
|
||||
@ -99,7 +100,7 @@ static u16 __get_link_speed(struct port *port);
|
||||
static u8 __get_duplex(struct port *port);
|
||||
static inline void __initialize_port_locks(struct port *port);
|
||||
//conversions
|
||||
static void __ntohs_lacpdu(struct lacpdu *lacpdu);
|
||||
static void __htons_lacpdu(struct lacpdu *lacpdu);
|
||||
static u16 __ad_timer_to_ticks(u16 timer_type, u16 Par);
|
||||
|
||||
|
||||
@ -330,7 +331,8 @@ static inline void __release_rx_machine_lock(struct port *port)
|
||||
* 0,
|
||||
* %AD_LINK_SPEED_BITMASK_10MBPS,
|
||||
* %AD_LINK_SPEED_BITMASK_100MBPS,
|
||||
* %AD_LINK_SPEED_BITMASK_1000MBPS
|
||||
* %AD_LINK_SPEED_BITMASK_1000MBPS,
|
||||
* %AD_LINK_SPEED_BITMASK_10000MBPS
|
||||
*/
|
||||
static u16 __get_link_speed(struct port *port)
|
||||
{
|
||||
@ -357,6 +359,10 @@ static u16 __get_link_speed(struct port *port)
|
||||
speed = AD_LINK_SPEED_BITMASK_1000MBPS;
|
||||
break;
|
||||
|
||||
case SPEED_10000:
|
||||
speed = AD_LINK_SPEED_BITMASK_10000MBPS;
|
||||
break;
|
||||
|
||||
default:
|
||||
speed = 0; // unknown speed value from ethtool. shouldn't happen
|
||||
break;
|
||||
@ -414,23 +420,23 @@ static inline void __initialize_port_locks(struct port *port)
|
||||
|
||||
//conversions
|
||||
/**
|
||||
* __ntohs_lacpdu - convert the contents of a LACPDU to host byte order
|
||||
* __htons_lacpdu - convert the contents of a LACPDU to network byte order
|
||||
* @lacpdu: the speicifed lacpdu
|
||||
*
|
||||
* For each multi-byte field in the lacpdu, convert its content
|
||||
*/
|
||||
static void __ntohs_lacpdu(struct lacpdu *lacpdu)
|
||||
static void __htons_lacpdu(struct lacpdu *lacpdu)
|
||||
{
|
||||
if (lacpdu) {
|
||||
lacpdu->actor_system_priority = ntohs(lacpdu->actor_system_priority);
|
||||
lacpdu->actor_key = ntohs(lacpdu->actor_key);
|
||||
lacpdu->actor_port_priority = ntohs(lacpdu->actor_port_priority);
|
||||
lacpdu->actor_port = ntohs(lacpdu->actor_port);
|
||||
lacpdu->partner_system_priority = ntohs(lacpdu->partner_system_priority);
|
||||
lacpdu->partner_key = ntohs(lacpdu->partner_key);
|
||||
lacpdu->partner_port_priority = ntohs(lacpdu->partner_port_priority);
|
||||
lacpdu->partner_port = ntohs(lacpdu->partner_port);
|
||||
lacpdu->collector_max_delay = ntohs(lacpdu->collector_max_delay);
|
||||
lacpdu->actor_system_priority = htons(lacpdu->actor_system_priority);
|
||||
lacpdu->actor_key = htons(lacpdu->actor_key);
|
||||
lacpdu->actor_port_priority = htons(lacpdu->actor_port_priority);
|
||||
lacpdu->actor_port = htons(lacpdu->actor_port);
|
||||
lacpdu->partner_system_priority = htons(lacpdu->partner_system_priority);
|
||||
lacpdu->partner_key = htons(lacpdu->partner_key);
|
||||
lacpdu->partner_port_priority = htons(lacpdu->partner_port_priority);
|
||||
lacpdu->partner_port = htons(lacpdu->partner_port);
|
||||
lacpdu->collector_max_delay = htons(lacpdu->collector_max_delay);
|
||||
}
|
||||
}
|
||||
|
||||
@ -490,11 +496,11 @@ static void __record_pdu(struct lacpdu *lacpdu, struct port *port)
|
||||
// validate lacpdu and port
|
||||
if (lacpdu && port) {
|
||||
// record the new parameter values for the partner operational
|
||||
port->partner_oper_port_number = lacpdu->actor_port;
|
||||
port->partner_oper_port_priority = lacpdu->actor_port_priority;
|
||||
port->partner_oper_port_number = ntohs(lacpdu->actor_port);
|
||||
port->partner_oper_port_priority = ntohs(lacpdu->actor_port_priority);
|
||||
port->partner_oper_system = lacpdu->actor_system;
|
||||
port->partner_oper_system_priority = lacpdu->actor_system_priority;
|
||||
port->partner_oper_key = lacpdu->actor_key;
|
||||
port->partner_oper_system_priority = ntohs(lacpdu->actor_system_priority);
|
||||
port->partner_oper_key = ntohs(lacpdu->actor_key);
|
||||
// zero partener's lase states
|
||||
port->partner_oper_port_state = 0;
|
||||
port->partner_oper_port_state |= (lacpdu->actor_state & AD_STATE_LACP_ACTIVITY);
|
||||
@ -561,11 +567,11 @@ static void __update_selected(struct lacpdu *lacpdu, struct port *port)
|
||||
// validate lacpdu and port
|
||||
if (lacpdu && port) {
|
||||
// check if any parameter is different
|
||||
if ((lacpdu->actor_port != port->partner_oper_port_number) ||
|
||||
(lacpdu->actor_port_priority != port->partner_oper_port_priority) ||
|
||||
if ((ntohs(lacpdu->actor_port) != port->partner_oper_port_number) ||
|
||||
(ntohs(lacpdu->actor_port_priority) != port->partner_oper_port_priority) ||
|
||||
MAC_ADDRESS_COMPARE(&(lacpdu->actor_system), &(port->partner_oper_system)) ||
|
||||
(lacpdu->actor_system_priority != port->partner_oper_system_priority) ||
|
||||
(lacpdu->actor_key != port->partner_oper_key) ||
|
||||
(ntohs(lacpdu->actor_system_priority) != port->partner_oper_system_priority) ||
|
||||
(ntohs(lacpdu->actor_key) != port->partner_oper_key) ||
|
||||
((lacpdu->actor_state & AD_STATE_AGGREGATION) != (port->partner_oper_port_state & AD_STATE_AGGREGATION))
|
||||
) {
|
||||
// update the state machine Selected variable
|
||||
@ -628,11 +634,11 @@ static void __choose_matched(struct lacpdu *lacpdu, struct port *port)
|
||||
// validate lacpdu and port
|
||||
if (lacpdu && port) {
|
||||
// check if all parameters are alike
|
||||
if (((lacpdu->partner_port == port->actor_port_number) &&
|
||||
(lacpdu->partner_port_priority == port->actor_port_priority) &&
|
||||
if (((ntohs(lacpdu->partner_port) == port->actor_port_number) &&
|
||||
(ntohs(lacpdu->partner_port_priority) == port->actor_port_priority) &&
|
||||
!MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) &&
|
||||
(lacpdu->partner_system_priority == port->actor_system_priority) &&
|
||||
(lacpdu->partner_key == port->actor_oper_port_key) &&
|
||||
(ntohs(lacpdu->partner_system_priority) == port->actor_system_priority) &&
|
||||
(ntohs(lacpdu->partner_key) == port->actor_oper_port_key) &&
|
||||
((lacpdu->partner_state & AD_STATE_AGGREGATION) == (port->actor_oper_port_state & AD_STATE_AGGREGATION))) ||
|
||||
// or this is individual link(aggregation == FALSE)
|
||||
((lacpdu->actor_state & AD_STATE_AGGREGATION) == 0)
|
||||
@ -662,11 +668,11 @@ static void __update_ntt(struct lacpdu *lacpdu, struct port *port)
|
||||
// validate lacpdu and port
|
||||
if (lacpdu && port) {
|
||||
// check if any parameter is different
|
||||
if ((lacpdu->partner_port != port->actor_port_number) ||
|
||||
(lacpdu->partner_port_priority != port->actor_port_priority) ||
|
||||
if ((ntohs(lacpdu->partner_port) != port->actor_port_number) ||
|
||||
(ntohs(lacpdu->partner_port_priority) != port->actor_port_priority) ||
|
||||
MAC_ADDRESS_COMPARE(&(lacpdu->partner_system), &(port->actor_system)) ||
|
||||
(lacpdu->partner_system_priority != port->actor_system_priority) ||
|
||||
(lacpdu->partner_key != port->actor_oper_port_key) ||
|
||||
(ntohs(lacpdu->partner_system_priority) != port->actor_system_priority) ||
|
||||
(ntohs(lacpdu->partner_key) != port->actor_oper_port_key) ||
|
||||
((lacpdu->partner_state & AD_STATE_LACP_ACTIVITY) != (port->actor_oper_port_state & AD_STATE_LACP_ACTIVITY)) ||
|
||||
((lacpdu->partner_state & AD_STATE_LACP_TIMEOUT) != (port->actor_oper_port_state & AD_STATE_LACP_TIMEOUT)) ||
|
||||
((lacpdu->partner_state & AD_STATE_SYNCHRONIZATION) != (port->actor_oper_port_state & AD_STATE_SYNCHRONIZATION)) ||
|
||||
@ -775,6 +781,9 @@ static u32 __get_agg_bandwidth(struct aggregator *aggregator)
|
||||
case AD_LINK_SPEED_BITMASK_1000MBPS:
|
||||
bandwidth = aggregator->num_of_ports * 1000;
|
||||
break;
|
||||
case AD_LINK_SPEED_BITMASK_10000MBPS:
|
||||
bandwidth = aggregator->num_of_ports * 10000;
|
||||
break;
|
||||
default:
|
||||
bandwidth=0; // to silent the compilor ....
|
||||
}
|
||||
@ -847,7 +856,7 @@ static inline void __update_lacpdu_from_port(struct port *port)
|
||||
*/
|
||||
|
||||
/* Convert all non u8 parameters to Big Endian for transmit */
|
||||
__ntohs_lacpdu(lacpdu);
|
||||
__htons_lacpdu(lacpdu);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////////
|
||||
@ -2171,7 +2180,6 @@ static void bond_3ad_rx_indication(struct lacpdu *lacpdu, struct slave *slave, u
|
||||
|
||||
switch (lacpdu->subtype) {
|
||||
case AD_TYPE_LACPDU:
|
||||
__ntohs_lacpdu(lacpdu);
|
||||
dprintk("Received LACPDU on port %d\n", port->actor_port_number);
|
||||
ad_rx_machine(lacpdu, port);
|
||||
break;
|
||||
|
@ -96,6 +96,7 @@ static char *lacp_rate = NULL;
|
||||
static char *xmit_hash_policy = NULL;
|
||||
static int arp_interval = BOND_LINK_ARP_INTERV;
|
||||
static char *arp_ip_target[BOND_MAX_ARP_TARGETS] = { NULL, };
|
||||
static char *arp_validate = NULL;
|
||||
struct bond_params bonding_defaults;
|
||||
|
||||
module_param(max_bonds, int, 0);
|
||||
@ -127,6 +128,8 @@ module_param(arp_interval, int, 0);
|
||||
MODULE_PARM_DESC(arp_interval, "arp interval in milliseconds");
|
||||
module_param_array(arp_ip_target, charp, NULL, 0);
|
||||
MODULE_PARM_DESC(arp_ip_target, "arp targets in n.n.n.n form");
|
||||
module_param(arp_validate, charp, 0);
|
||||
MODULE_PARM_DESC(arp_validate, "validate src/dst of ARP probes: none (default), active, backup or all");
|
||||
|
||||
/*----------------------------- Global variables ----------------------------*/
|
||||
|
||||
@ -170,6 +173,14 @@ struct bond_parm_tbl xmit_hashtype_tbl[] = {
|
||||
{ NULL, -1},
|
||||
};
|
||||
|
||||
struct bond_parm_tbl arp_validate_tbl[] = {
|
||||
{ "none", BOND_ARP_VALIDATE_NONE},
|
||||
{ "active", BOND_ARP_VALIDATE_ACTIVE},
|
||||
{ "backup", BOND_ARP_VALIDATE_BACKUP},
|
||||
{ "all", BOND_ARP_VALIDATE_ALL},
|
||||
{ NULL, -1},
|
||||
};
|
||||
|
||||
/*-------------------------- Forward declarations ---------------------------*/
|
||||
|
||||
static void bond_send_gratuitous_arp(struct bonding *bond);
|
||||
@ -638,6 +649,7 @@ verify:
|
||||
case SPEED_10:
|
||||
case SPEED_100:
|
||||
case SPEED_1000:
|
||||
case SPEED_10000:
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
@ -1210,10 +1222,14 @@ static int bond_compute_features(struct bonding *bond)
|
||||
unsigned long features = BOND_INTERSECT_FEATURES;
|
||||
struct slave *slave;
|
||||
struct net_device *bond_dev = bond->dev;
|
||||
unsigned short max_hard_header_len = ETH_HLEN;
|
||||
int i;
|
||||
|
||||
bond_for_each_slave(bond, slave, i)
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
features &= (slave->dev->features & BOND_INTERSECT_FEATURES);
|
||||
if (slave->dev->hard_header_len > max_hard_header_len)
|
||||
max_hard_header_len = slave->dev->hard_header_len;
|
||||
}
|
||||
|
||||
if ((features & NETIF_F_SG) &&
|
||||
!(features & NETIF_F_ALL_CSUM))
|
||||
@ -1231,6 +1247,7 @@ static int bond_compute_features(struct bonding *bond)
|
||||
|
||||
features |= (bond_dev->features & ~BOND_INTERSECT_FEATURES);
|
||||
bond_dev->features = features;
|
||||
bond_dev->hard_header_len = max_hard_header_len;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -1365,6 +1382,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
}
|
||||
|
||||
new_slave->dev = slave_dev;
|
||||
slave_dev->priv_flags |= IFF_BONDING;
|
||||
|
||||
if ((bond->params.mode == BOND_MODE_TLB) ||
|
||||
(bond->params.mode == BOND_MODE_ALB)) {
|
||||
@ -1417,6 +1435,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
|
||||
bond_compute_features(bond);
|
||||
|
||||
new_slave->last_arp_rx = jiffies;
|
||||
|
||||
if (bond->params.miimon && !bond->params.use_carrier) {
|
||||
link_reporting = bond_check_dev_link(bond, slave_dev, 1);
|
||||
|
||||
@ -1493,29 +1513,8 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
|
||||
switch (bond->params.mode) {
|
||||
case BOND_MODE_ACTIVEBACKUP:
|
||||
/* if we're in active-backup mode, we need one and
|
||||
* only one active interface. The backup interfaces
|
||||
* will have their SLAVE_INACTIVE flag set because we
|
||||
* need them to be drop all packets. Thus, since we
|
||||
* guarantee that curr_active_slave always point to
|
||||
* the last usable interface, we just have to verify
|
||||
* this interface's flag.
|
||||
*/
|
||||
if (((!bond->curr_active_slave) ||
|
||||
(bond->curr_active_slave->dev->priv_flags & IFF_SLAVE_INACTIVE)) &&
|
||||
(new_slave->link != BOND_LINK_DOWN)) {
|
||||
/* first slave or no active slave yet, and this link
|
||||
is OK, so make this interface the active one */
|
||||
bond_change_active_slave(bond, new_slave);
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": %s: first active interface up!\n",
|
||||
bond->dev->name);
|
||||
netif_carrier_on(bond->dev);
|
||||
|
||||
} else {
|
||||
dprintk("This is just a backup slave\n");
|
||||
bond_set_slave_inactive_flags(new_slave);
|
||||
}
|
||||
bond_set_slave_inactive_flags(new_slave);
|
||||
bond_select_active_slave(bond);
|
||||
break;
|
||||
case BOND_MODE_8023AD:
|
||||
/* in 802.3ad mode, the internal mechanism
|
||||
@ -1778,7 +1777,8 @@ int bond_release(struct net_device *bond_dev, struct net_device *slave_dev)
|
||||
dev_set_mac_address(slave_dev, &addr);
|
||||
|
||||
slave_dev->priv_flags &= ~(IFF_MASTER_8023AD | IFF_MASTER_ALB |
|
||||
IFF_SLAVE_INACTIVE);
|
||||
IFF_SLAVE_INACTIVE | IFF_BONDING |
|
||||
IFF_SLAVE_NEEDARP);
|
||||
|
||||
kfree(slave);
|
||||
|
||||
@ -2291,6 +2291,25 @@ static int bond_has_ip(struct bonding *bond)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bond_has_this_ip(struct bonding *bond, u32 ip)
|
||||
{
|
||||
struct vlan_entry *vlan, *vlan_next;
|
||||
|
||||
if (ip == bond->master_ip)
|
||||
return 1;
|
||||
|
||||
if (list_empty(&bond->vlan_list))
|
||||
return 0;
|
||||
|
||||
list_for_each_entry_safe(vlan, vlan_next, &bond->vlan_list,
|
||||
vlan_list) {
|
||||
if (ip == vlan->vlan_ip)
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* We go to the (large) trouble of VLAN tagging ARP frames because
|
||||
* switches in VLAN mode (especially if ports are configured as
|
||||
@ -2429,6 +2448,93 @@ static void bond_send_gratuitous_arp(struct bonding *bond)
|
||||
}
|
||||
}
|
||||
|
||||
static void bond_validate_arp(struct bonding *bond, struct slave *slave, u32 sip, u32 tip)
|
||||
{
|
||||
int i;
|
||||
u32 *targets = bond->params.arp_targets;
|
||||
|
||||
targets = bond->params.arp_targets;
|
||||
for (i = 0; (i < BOND_MAX_ARP_TARGETS) && targets[i]; i++) {
|
||||
dprintk("bva: sip %u.%u.%u.%u tip %u.%u.%u.%u t[%d] "
|
||||
"%u.%u.%u.%u bhti(tip) %d\n",
|
||||
NIPQUAD(sip), NIPQUAD(tip), i, NIPQUAD(targets[i]),
|
||||
bond_has_this_ip(bond, tip));
|
||||
if (sip == targets[i]) {
|
||||
if (bond_has_this_ip(bond, tip))
|
||||
slave->last_arp_rx = jiffies;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int bond_arp_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
|
||||
{
|
||||
struct arphdr *arp;
|
||||
struct slave *slave;
|
||||
struct bonding *bond;
|
||||
unsigned char *arp_ptr;
|
||||
u32 sip, tip;
|
||||
|
||||
if (!(dev->priv_flags & IFF_BONDING) || !(dev->flags & IFF_MASTER))
|
||||
goto out;
|
||||
|
||||
bond = dev->priv;
|
||||
read_lock(&bond->lock);
|
||||
|
||||
dprintk("bond_arp_rcv: bond %s skb->dev %s orig_dev %s\n",
|
||||
bond->dev->name, skb->dev ? skb->dev->name : "NULL",
|
||||
orig_dev ? orig_dev->name : "NULL");
|
||||
|
||||
slave = bond_get_slave_by_dev(bond, orig_dev);
|
||||
if (!slave || !slave_do_arp_validate(bond, slave))
|
||||
goto out_unlock;
|
||||
|
||||
/* ARP header, plus 2 device addresses, plus 2 IP addresses. */
|
||||
if (!pskb_may_pull(skb, (sizeof(struct arphdr) +
|
||||
(2 * dev->addr_len) +
|
||||
(2 * sizeof(u32)))))
|
||||
goto out_unlock;
|
||||
|
||||
arp = skb->nh.arph;
|
||||
if (arp->ar_hln != dev->addr_len ||
|
||||
skb->pkt_type == PACKET_OTHERHOST ||
|
||||
skb->pkt_type == PACKET_LOOPBACK ||
|
||||
arp->ar_hrd != htons(ARPHRD_ETHER) ||
|
||||
arp->ar_pro != htons(ETH_P_IP) ||
|
||||
arp->ar_pln != 4)
|
||||
goto out_unlock;
|
||||
|
||||
arp_ptr = (unsigned char *)(arp + 1);
|
||||
arp_ptr += dev->addr_len;
|
||||
memcpy(&sip, arp_ptr, 4);
|
||||
arp_ptr += 4 + dev->addr_len;
|
||||
memcpy(&tip, arp_ptr, 4);
|
||||
|
||||
dprintk("bond_arp_rcv: %s %s/%d av %d sv %d sip %u.%u.%u.%u"
|
||||
" tip %u.%u.%u.%u\n", bond->dev->name, slave->dev->name,
|
||||
slave->state, bond->params.arp_validate,
|
||||
slave_do_arp_validate(bond, slave), NIPQUAD(sip), NIPQUAD(tip));
|
||||
|
||||
/*
|
||||
* Backup slaves won't see the ARP reply, but do come through
|
||||
* here for each ARP probe (so we swap the sip/tip to validate
|
||||
* the probe). In a "redundant switch, common router" type of
|
||||
* configuration, the ARP probe will (hopefully) travel from
|
||||
* the active, through one switch, the router, then the other
|
||||
* switch before reaching the backup.
|
||||
*/
|
||||
if (slave->state == BOND_STATE_ACTIVE)
|
||||
bond_validate_arp(bond, slave, sip, tip);
|
||||
else
|
||||
bond_validate_arp(bond, slave, tip, sip);
|
||||
|
||||
out_unlock:
|
||||
read_unlock(&bond->lock);
|
||||
out:
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
}
|
||||
|
||||
/*
|
||||
* this function is called regularly to monitor each slave's link
|
||||
* ensuring that traffic is being sent and received when arp monitoring
|
||||
@ -2593,7 +2699,8 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
|
||||
*/
|
||||
bond_for_each_slave(bond, slave, i) {
|
||||
if (slave->link != BOND_LINK_UP) {
|
||||
if ((jiffies - slave->dev->last_rx) <= delta_in_ticks) {
|
||||
if ((jiffies - slave_last_rx(bond, slave)) <=
|
||||
delta_in_ticks) {
|
||||
|
||||
slave->link = BOND_LINK_UP;
|
||||
|
||||
@ -2638,7 +2745,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
|
||||
|
||||
if ((slave != bond->curr_active_slave) &&
|
||||
(!bond->current_arp_slave) &&
|
||||
(((jiffies - slave->dev->last_rx) >= 3*delta_in_ticks) &&
|
||||
(((jiffies - slave_last_rx(bond, slave)) >= 3*delta_in_ticks) &&
|
||||
bond_has_ip(bond))) {
|
||||
/* a backup slave has gone down; three times
|
||||
* the delta allows the current slave to be
|
||||
@ -2685,7 +2792,7 @@ void bond_activebackup_arp_mon(struct net_device *bond_dev)
|
||||
* if it is up and needs to take over as the curr_active_slave
|
||||
*/
|
||||
if ((((jiffies - slave->dev->trans_start) >= (2*delta_in_ticks)) ||
|
||||
(((jiffies - slave->dev->last_rx) >= (2*delta_in_ticks)) &&
|
||||
(((jiffies - slave_last_rx(bond, slave)) >= (2*delta_in_ticks)) &&
|
||||
bond_has_ip(bond))) &&
|
||||
((jiffies - slave->jiffies) >= 2*delta_in_ticks)) {
|
||||
|
||||
@ -2950,7 +3057,7 @@ static void bond_info_show_slave(struct seq_file *seq, const struct slave *slave
|
||||
seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name);
|
||||
seq_printf(seq, "MII Status: %s\n",
|
||||
(slave->link == BOND_LINK_UP) ? "up" : "down");
|
||||
seq_printf(seq, "Link Failure Count: %d\n",
|
||||
seq_printf(seq, "Link Failure Count: %u\n",
|
||||
slave->link_failure_count);
|
||||
|
||||
seq_printf(seq,
|
||||
@ -3210,6 +3317,9 @@ static int bond_netdev_event(struct notifier_block *this, unsigned long event, v
|
||||
(event_dev ? event_dev->name : "None"),
|
||||
event);
|
||||
|
||||
if (!(event_dev->priv_flags & IFF_BONDING))
|
||||
return NOTIFY_DONE;
|
||||
|
||||
if (event_dev->flags & IFF_MASTER) {
|
||||
dprintk("IFF_MASTER\n");
|
||||
return bond_master_netdev_event(event, event_dev);
|
||||
@ -3305,6 +3415,21 @@ static void bond_unregister_lacpdu(struct bonding *bond)
|
||||
dev_remove_pack(&(BOND_AD_INFO(bond).ad_pkt_type));
|
||||
}
|
||||
|
||||
void bond_register_arp(struct bonding *bond)
|
||||
{
|
||||
struct packet_type *pt = &bond->arp_mon_pt;
|
||||
|
||||
pt->type = htons(ETH_P_ARP);
|
||||
pt->dev = NULL; /*bond->dev;XXX*/
|
||||
pt->func = bond_arp_rcv;
|
||||
dev_add_pack(pt);
|
||||
}
|
||||
|
||||
void bond_unregister_arp(struct bonding *bond)
|
||||
{
|
||||
dev_remove_pack(&bond->arp_mon_pt);
|
||||
}
|
||||
|
||||
/*---------------------------- Hashing Policies -----------------------------*/
|
||||
|
||||
/*
|
||||
@ -3391,6 +3516,9 @@ static int bond_open(struct net_device *bond_dev)
|
||||
} else {
|
||||
arp_timer->function = (void *)&bond_loadbalance_arp_mon;
|
||||
}
|
||||
if (bond->params.arp_validate)
|
||||
bond_register_arp(bond);
|
||||
|
||||
add_timer(arp_timer);
|
||||
}
|
||||
|
||||
@ -3418,9 +3546,11 @@ static int bond_close(struct net_device *bond_dev)
|
||||
bond_unregister_lacpdu(bond);
|
||||
}
|
||||
|
||||
if (bond->params.arp_validate)
|
||||
bond_unregister_arp(bond);
|
||||
|
||||
write_lock_bh(&bond->lock);
|
||||
|
||||
bond_mc_list_destroy(bond);
|
||||
|
||||
/* signal timers not to re-arm */
|
||||
bond->kill_timers = 1;
|
||||
@ -3451,8 +3581,6 @@ static int bond_close(struct net_device *bond_dev)
|
||||
break;
|
||||
}
|
||||
|
||||
/* Release the bonded slaves */
|
||||
bond_release_all(bond_dev);
|
||||
|
||||
if ((bond->params.mode == BOND_MODE_TLB) ||
|
||||
(bond->params.mode == BOND_MODE_ALB)) {
|
||||
@ -4179,6 +4307,7 @@ static int bond_init(struct net_device *bond_dev, struct bond_params *params)
|
||||
/* Initialize the device options */
|
||||
bond_dev->tx_queue_len = 0;
|
||||
bond_dev->flags |= IFF_MASTER|IFF_MULTICAST;
|
||||
bond_dev->priv_flags |= IFF_BONDING;
|
||||
|
||||
/* At first, we block adding VLANs. That's the only way to
|
||||
* prevent problems that occur when adding VLANs over an
|
||||
@ -4237,6 +4366,9 @@ static void bond_free_all(void)
|
||||
list_for_each_entry_safe(bond, nxt, &bond_dev_list, bond_list) {
|
||||
struct net_device *bond_dev = bond->dev;
|
||||
|
||||
bond_mc_list_destroy(bond);
|
||||
/* Release the bonded slaves */
|
||||
bond_release_all(bond_dev);
|
||||
unregister_netdevice(bond_dev);
|
||||
bond_deinit(bond_dev);
|
||||
}
|
||||
@ -4270,6 +4402,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl)
|
||||
|
||||
static int bond_check_params(struct bond_params *params)
|
||||
{
|
||||
int arp_validate_value;
|
||||
|
||||
/*
|
||||
* Convert string parameters.
|
||||
*/
|
||||
@ -4473,6 +4607,29 @@ static int bond_check_params(struct bond_params *params)
|
||||
arp_interval = 0;
|
||||
}
|
||||
|
||||
if (arp_validate) {
|
||||
if (bond_mode != BOND_MODE_ACTIVEBACKUP) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": arp_validate only supported in active-backup mode\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
if (!arp_interval) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": arp_validate requires arp_interval\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
arp_validate_value = bond_parse_parm(arp_validate,
|
||||
arp_validate_tbl);
|
||||
if (arp_validate_value == -1) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": Error: invalid arp_validate \"%s\"\n",
|
||||
arp_validate == NULL ? "NULL" : arp_validate);
|
||||
return -EINVAL;
|
||||
}
|
||||
} else
|
||||
arp_validate_value = 0;
|
||||
|
||||
if (miimon) {
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": MII link monitoring set to %d ms\n",
|
||||
@ -4481,8 +4638,10 @@ static int bond_check_params(struct bond_params *params)
|
||||
int i;
|
||||
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": ARP monitoring set to %d ms with %d target(s):",
|
||||
arp_interval, arp_ip_count);
|
||||
": ARP monitoring set to %d ms, validate %s, with %d target(s):",
|
||||
arp_interval,
|
||||
arp_validate_tbl[arp_validate_value].modename,
|
||||
arp_ip_count);
|
||||
|
||||
for (i = 0; i < arp_ip_count; i++)
|
||||
printk (" %s", arp_ip_target[i]);
|
||||
@ -4516,6 +4675,7 @@ static int bond_check_params(struct bond_params *params)
|
||||
params->xmit_policy = xmit_hashtype;
|
||||
params->miimon = miimon;
|
||||
params->arp_interval = arp_interval;
|
||||
params->arp_validate = arp_validate_value;
|
||||
params->updelay = updelay;
|
||||
params->downdelay = downdelay;
|
||||
params->use_carrier = use_carrier;
|
||||
|
@ -51,6 +51,7 @@ extern struct bond_params bonding_defaults;
|
||||
extern struct bond_parm_tbl bond_mode_tbl[];
|
||||
extern struct bond_parm_tbl bond_lacp_tbl[];
|
||||
extern struct bond_parm_tbl xmit_hashtype_tbl[];
|
||||
extern struct bond_parm_tbl arp_validate_tbl[];
|
||||
|
||||
static int expected_refcount = -1;
|
||||
static struct class *netdev_class;
|
||||
@ -502,6 +503,53 @@ out:
|
||||
}
|
||||
static CLASS_DEVICE_ATTR(xmit_hash_policy, S_IRUGO | S_IWUSR, bonding_show_xmit_hash, bonding_store_xmit_hash);
|
||||
|
||||
/*
|
||||
* Show and set arp_validate.
|
||||
*/
|
||||
static ssize_t bonding_show_arp_validate(struct class_device *cd, char *buf)
|
||||
{
|
||||
struct bonding *bond = to_bond(cd);
|
||||
|
||||
return sprintf(buf, "%s %d\n",
|
||||
arp_validate_tbl[bond->params.arp_validate].modename,
|
||||
bond->params.arp_validate) + 1;
|
||||
}
|
||||
|
||||
static ssize_t bonding_store_arp_validate(struct class_device *cd, const char *buf, size_t count)
|
||||
{
|
||||
int new_value;
|
||||
struct bonding *bond = to_bond(cd);
|
||||
|
||||
new_value = bond_parse_parm((char *)buf, arp_validate_tbl);
|
||||
if (new_value < 0) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": %s: Ignoring invalid arp_validate value %s\n",
|
||||
bond->dev->name, buf);
|
||||
return -EINVAL;
|
||||
}
|
||||
if (new_value && (bond->params.mode != BOND_MODE_ACTIVEBACKUP)) {
|
||||
printk(KERN_ERR DRV_NAME
|
||||
": %s: arp_validate only supported in active-backup mode.\n",
|
||||
bond->dev->name);
|
||||
return -EINVAL;
|
||||
}
|
||||
printk(KERN_INFO DRV_NAME ": %s: setting arp_validate to %s (%d).\n",
|
||||
bond->dev->name, arp_validate_tbl[new_value].modename,
|
||||
new_value);
|
||||
|
||||
if (!bond->params.arp_validate && new_value) {
|
||||
bond_register_arp(bond);
|
||||
} else if (bond->params.arp_validate && !new_value) {
|
||||
bond_unregister_arp(bond);
|
||||
}
|
||||
|
||||
bond->params.arp_validate = new_value;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static CLASS_DEVICE_ATTR(arp_validate, S_IRUGO | S_IWUSR, bonding_show_arp_validate, bonding_store_arp_validate);
|
||||
|
||||
/*
|
||||
* Show and set the arp timer interval. There are two tricky bits
|
||||
* here. First, if ARP monitoring is activated, then we must disable
|
||||
@ -914,6 +962,11 @@ static ssize_t bonding_store_miimon(struct class_device *cd, const char *buf, si
|
||||
"ARP monitoring. Disabling ARP monitoring...\n",
|
||||
bond->dev->name);
|
||||
bond->params.arp_interval = 0;
|
||||
if (bond->params.arp_validate) {
|
||||
bond_unregister_arp(bond);
|
||||
bond->params.arp_validate =
|
||||
BOND_ARP_VALIDATE_NONE;
|
||||
}
|
||||
/* Kill ARP timer, else it brings bond's link down */
|
||||
if (bond->mii_timer.function) {
|
||||
printk(KERN_INFO DRV_NAME
|
||||
@ -1093,7 +1146,7 @@ static ssize_t bonding_store_active_slave(struct class_device *cd, const char *b
|
||||
strlen(slave->dev->name)) == 0) {
|
||||
old_active = bond->curr_active_slave;
|
||||
new_active = slave;
|
||||
if (new_active && (new_active == old_active)) {
|
||||
if (new_active == old_active) {
|
||||
/* do nothing */
|
||||
printk(KERN_INFO DRV_NAME
|
||||
": %s: %s is already the current active slave.\n",
|
||||
@ -1273,6 +1326,7 @@ static CLASS_DEVICE_ATTR(ad_partner_mac, S_IRUGO, bonding_show_ad_partner_mac, N
|
||||
static struct attribute *per_bond_attrs[] = {
|
||||
&class_device_attr_slaves.attr,
|
||||
&class_device_attr_mode.attr,
|
||||
&class_device_attr_arp_validate.attr,
|
||||
&class_device_attr_arp_interval.attr,
|
||||
&class_device_attr_arp_ip_target.attr,
|
||||
&class_device_attr_downdelay.attr,
|
||||
|
@ -22,8 +22,8 @@
|
||||
#include "bond_3ad.h"
|
||||
#include "bond_alb.h"
|
||||
|
||||
#define DRV_VERSION "3.0.3"
|
||||
#define DRV_RELDATE "March 23, 2006"
|
||||
#define DRV_VERSION "3.1.1"
|
||||
#define DRV_RELDATE "September 26, 2006"
|
||||
#define DRV_NAME "bonding"
|
||||
#define DRV_DESCRIPTION "Ethernet Channel Bonding Driver"
|
||||
|
||||
@ -126,6 +126,7 @@ struct bond_params {
|
||||
int xmit_policy;
|
||||
int miimon;
|
||||
int arp_interval;
|
||||
int arp_validate;
|
||||
int use_carrier;
|
||||
int updelay;
|
||||
int downdelay;
|
||||
@ -149,8 +150,9 @@ struct slave {
|
||||
struct net_device *dev; /* first - useful for panic debug */
|
||||
struct slave *next;
|
||||
struct slave *prev;
|
||||
s16 delay;
|
||||
int delay;
|
||||
u32 jiffies;
|
||||
u32 last_arp_rx;
|
||||
s8 link; /* one of BOND_LINK_XXXX */
|
||||
s8 state; /* one of BOND_STATE_XXXX */
|
||||
u32 original_flags;
|
||||
@ -198,6 +200,7 @@ struct bonding {
|
||||
struct bond_params params;
|
||||
struct list_head vlan_list;
|
||||
struct vlan_group *vlgrp;
|
||||
struct packet_type arp_mon_pt;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -228,6 +231,25 @@ static inline struct bonding *bond_get_bond_by_slave(struct slave *slave)
|
||||
return (struct bonding *)slave->dev->master->priv;
|
||||
}
|
||||
|
||||
#define BOND_ARP_VALIDATE_NONE 0
|
||||
#define BOND_ARP_VALIDATE_ACTIVE (1 << BOND_STATE_ACTIVE)
|
||||
#define BOND_ARP_VALIDATE_BACKUP (1 << BOND_STATE_BACKUP)
|
||||
#define BOND_ARP_VALIDATE_ALL (BOND_ARP_VALIDATE_ACTIVE | \
|
||||
BOND_ARP_VALIDATE_BACKUP)
|
||||
|
||||
extern inline int slave_do_arp_validate(struct bonding *bond, struct slave *slave)
|
||||
{
|
||||
return bond->params.arp_validate & (1 << slave->state);
|
||||
}
|
||||
|
||||
extern inline u32 slave_last_rx(struct bonding *bond, struct slave *slave)
|
||||
{
|
||||
if (slave_do_arp_validate(bond, slave))
|
||||
return slave->last_arp_rx;
|
||||
|
||||
return slave->dev->last_rx;
|
||||
}
|
||||
|
||||
static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
||||
{
|
||||
struct bonding *bond = slave->dev->master->priv;
|
||||
@ -235,12 +257,14 @@ static inline void bond_set_slave_inactive_flags(struct slave *slave)
|
||||
bond->params.mode != BOND_MODE_ALB)
|
||||
slave->state = BOND_STATE_BACKUP;
|
||||
slave->dev->priv_flags |= IFF_SLAVE_INACTIVE;
|
||||
if (slave_do_arp_validate(bond, slave))
|
||||
slave->dev->priv_flags |= IFF_SLAVE_NEEDARP;
|
||||
}
|
||||
|
||||
static inline void bond_set_slave_active_flags(struct slave *slave)
|
||||
{
|
||||
slave->state = BOND_STATE_ACTIVE;
|
||||
slave->dev->priv_flags &= ~IFF_SLAVE_INACTIVE;
|
||||
slave->dev->priv_flags &= ~(IFF_SLAVE_INACTIVE | IFF_SLAVE_NEEDARP);
|
||||
}
|
||||
|
||||
static inline void bond_set_master_3ad_flags(struct bonding *bond)
|
||||
@ -284,6 +308,8 @@ int bond_parse_parm(char *mode_arg, struct bond_parm_tbl *tbl);
|
||||
const char *bond_mode_name(int mode);
|
||||
void bond_select_active_slave(struct bonding *bond);
|
||||
void bond_change_active_slave(struct bonding *bond, struct slave *new_active);
|
||||
void bond_register_arp(struct bonding *);
|
||||
void bond_unregister_arp(struct bonding *);
|
||||
|
||||
#endif /* _LINUX_BONDING_H */
|
||||
|
||||
|
@ -1367,8 +1367,8 @@ struct e1000_hw_stats {
|
||||
|
||||
/* Structure containing variables used by the shared code (e1000_hw.c) */
|
||||
struct e1000_hw {
|
||||
uint8_t *hw_addr;
|
||||
uint8_t *flash_address;
|
||||
uint8_t __iomem *hw_addr;
|
||||
uint8_t __iomem *flash_address;
|
||||
e1000_mac_type mac_type;
|
||||
e1000_phy_type phy_type;
|
||||
uint32_t phy_init_script;
|
||||
|
@ -3789,6 +3789,12 @@ static int nv_loopback_test(struct net_device *dev)
|
||||
/* setup packet for tx */
|
||||
pkt_len = ETH_DATA_LEN;
|
||||
tx_skb = dev_alloc_skb(pkt_len);
|
||||
if (!tx_skb) {
|
||||
printk(KERN_ERR "dev_alloc_skb() failed during loopback test"
|
||||
" of %s\n", dev->name);
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
pkt_data = skb_put(tx_skb, pkt_len);
|
||||
for (i = 0; i < pkt_len; i++)
|
||||
pkt_data[i] = (u8)(i & 0xff);
|
||||
@ -3853,7 +3859,7 @@ static int nv_loopback_test(struct net_device *dev)
|
||||
tx_skb->end-tx_skb->data,
|
||||
PCI_DMA_TODEVICE);
|
||||
dev_kfree_skb_any(tx_skb);
|
||||
|
||||
out:
|
||||
/* stop engines */
|
||||
nv_stop_rx(dev);
|
||||
nv_stop_tx(dev);
|
||||
|
@ -1,402 +0,0 @@
|
||||
/*
|
||||
* This file is subject to the terms and conditions of the GNU General Public
|
||||
* License. See the file "COPYING" in the main directory of this archive
|
||||
* for more details.
|
||||
*
|
||||
* Copyright (C) 2001 Patton Electronics Company
|
||||
* Copyright (C) 2002 Momentum Computer
|
||||
*
|
||||
* Copyright 2000 MontaVista Software Inc.
|
||||
* Author: MontaVista Software, Inc.
|
||||
* stevel@mvista.com or support@mvista.com
|
||||
*
|
||||
* This program is free software; you can distribute it and/or modify it
|
||||
* under the terms of the GNU General Public License (Version 2) as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
|
||||
*
|
||||
* Ethernet driver definitions for the MIPS GT96100 Advanced
|
||||
* Communication Controller.
|
||||
*
|
||||
* Modified for the Marvellous GT64240 Retarded Communication Controller.
|
||||
*/
|
||||
#ifndef _GT64240ETH_H
|
||||
#define _GT64240ETH_H
|
||||
|
||||
#include <asm/gt64240.h>
|
||||
|
||||
#define ETHERNET_PORTS_DIFFERENCE_OFFSETS 0x400
|
||||
|
||||
/* Translate those weanie names from Galileo/VxWorks header files: */
|
||||
|
||||
#define GT64240_MRR MAIN_ROUTING_REGISTER
|
||||
#define GT64240_CIU_ARBITER_CONFIG COMM_UNIT_ARBITER_CONFIGURATION_REGISTER
|
||||
#define GT64240_CIU_ARBITER_CONTROL COMM_UNIT_ARBITER_CONTROL
|
||||
#define GT64240_MAIN_LOW_CAUSE LOW_INTERRUPT_CAUSE_REGISTER
|
||||
#define GT64240_MAIN_HIGH_CAUSE HIGH_INTERRUPT_CAUSE_REGISTER
|
||||
#define GT64240_CPU_LOW_MASK CPU_INTERRUPT_MASK_REGISTER_LOW
|
||||
#define GT64240_CPU_HIGH_MASK CPU_INTERRUPT_MASK_REGISTER_HIGH
|
||||
#define GT64240_CPU_SELECT_CAUSE CPU_SELECT_CAUSE_REGISTER
|
||||
|
||||
#define GT64240_ETH_PHY_ADDR_REG ETHERNET_PHY_ADDRESS_REGISTER
|
||||
#define GT64240_ETH_PORT_CONFIG ETHERNET0_PORT_CONFIGURATION_REGISTER
|
||||
#define GT64240_ETH_PORT_CONFIG_EXT ETHERNET0_PORT_CONFIGURATION_EXTEND_REGISTER
|
||||
#define GT64240_ETH_PORT_COMMAND ETHERNET0_PORT_COMMAND_REGISTER
|
||||
#define GT64240_ETH_PORT_STATUS ETHERNET0_PORT_STATUS_REGISTER
|
||||
#define GT64240_ETH_IO_SIZE ETHERNET_PORTS_DIFFERENCE_OFFSETS
|
||||
#define GT64240_ETH_SMI_REG ETHERNET_SMI_REGISTER
|
||||
#define GT64240_ETH_MIB_COUNT_BASE ETHERNET0_MIB_COUNTER_BASE
|
||||
#define GT64240_ETH_SDMA_CONFIG ETHERNET0_SDMA_CONFIGURATION_REGISTER
|
||||
#define GT64240_ETH_SDMA_COMM ETHERNET0_SDMA_COMMAND_REGISTER
|
||||
#define GT64240_ETH_INT_MASK ETHERNET0_INTERRUPT_MASK_REGISTER
|
||||
#define GT64240_ETH_INT_CAUSE ETHERNET0_INTERRUPT_CAUSE_REGISTER
|
||||
#define GT64240_ETH_CURR_TX_DESC_PTR0 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER0
|
||||
#define GT64240_ETH_CURR_TX_DESC_PTR1 ETHERNET0_CURRENT_TX_DESCRIPTOR_POINTER1
|
||||
#define GT64240_ETH_1ST_RX_DESC_PTR0 ETHERNET0_FIRST_RX_DESCRIPTOR_POINTER0
|
||||
#define GT64240_ETH_CURR_RX_DESC_PTR0 ETHERNET0_CURRENT_RX_DESCRIPTOR_POINTER0
|
||||
#define GT64240_ETH_HASH_TBL_PTR ETHERNET0_HASH_TABLE_POINTER_REGISTER
|
||||
|
||||
/* Turn on NAPI by default */
|
||||
|
||||
#define GT64240_NAPI 1
|
||||
|
||||
/* Some 64240 settings that SHOULD eventually be setup in PROM monitor: */
|
||||
/* (Board-specific to the DSL3224 Rev A board ONLY!) */
|
||||
#define D3224_MPP_CTRL0_SETTING 0x66669900
|
||||
#define D3224_MPP_CTRL1_SETTING 0x00000000
|
||||
#define D3224_MPP_CTRL2_SETTING 0x00887700
|
||||
#define D3224_MPP_CTRL3_SETTING 0x00000044
|
||||
#define D3224_GPP_IO_CTRL_SETTING 0x0000e800
|
||||
#define D3224_GPP_LEVEL_CTRL_SETTING 0xf001f703
|
||||
#define D3224_GPP_VALUE_SETTING 0x00000000
|
||||
|
||||
/* Keep the ring sizes a power of two for efficiency. */
|
||||
//-#define TX_RING_SIZE 16
|
||||
#define TX_RING_SIZE 64 /* TESTING !!! */
|
||||
#define RX_RING_SIZE 32
|
||||
#define PKT_BUF_SZ 1536 /* Size of each temporary Rx buffer. */
|
||||
|
||||
#define RX_HASH_TABLE_SIZE 16384
|
||||
#define HASH_HOP_NUMBER 12
|
||||
|
||||
#define NUM_INTERFACES 3
|
||||
|
||||
#define GT64240ETH_TX_TIMEOUT HZ/4
|
||||
|
||||
#define MIPS_GT64240_BASE 0xf4000000
|
||||
#define GT64240_ETH0_BASE (MIPS_GT64240_BASE + GT64240_ETH_PORT_CONFIG)
|
||||
#define GT64240_ETH1_BASE (GT64240_ETH0_BASE + GT64240_ETH_IO_SIZE)
|
||||
#define GT64240_ETH2_BASE (GT64240_ETH1_BASE + GT64240_ETH_IO_SIZE)
|
||||
|
||||
#if defined(CONFIG_MIPS_DSL3224)
|
||||
#define GT64240_ETHER0_IRQ 4
|
||||
#define GT64240_ETHER1_IRQ 4
|
||||
#else
|
||||
#define GT64240_ETHER0_IRQ -1
|
||||
#define GT64240_ETHER1_IRQ -1
|
||||
#endif
|
||||
|
||||
#define REV_GT64240 0x1
|
||||
#define REV_GT64240A 0x10
|
||||
|
||||
#define GT64240ETH_READ(gp, offset) \
|
||||
GT_READ((gp)->port_offset + (offset))
|
||||
|
||||
#define GT64240ETH_WRITE(gp, offset, data) \
|
||||
GT_WRITE((gp)->port_offset + (offset), (data))
|
||||
|
||||
#define GT64240ETH_SETBIT(gp, offset, bits) \
|
||||
GT64240ETH_WRITE((gp), (offset), \
|
||||
GT64240ETH_READ((gp), (offset)) | (bits))
|
||||
|
||||
#define GT64240ETH_CLRBIT(gp, offset, bits) \
|
||||
GT64240ETH_WRITE((gp), (offset), \
|
||||
GT64240ETH_READ((gp), (offset)) & ~(bits))
|
||||
|
||||
#define GT64240_READ(ofs) GT_READ(ofs)
|
||||
#define GT64240_WRITE(ofs, data) GT_WRITE((ofs), (data))
|
||||
|
||||
/* Bit definitions of the SMI Reg */
|
||||
enum {
|
||||
smirDataMask = 0xffff,
|
||||
smirPhyAdMask = 0x1f << 16,
|
||||
smirPhyAdBit = 16,
|
||||
smirRegAdMask = 0x1f << 21,
|
||||
smirRegAdBit = 21,
|
||||
smirOpCode = 1 << 26,
|
||||
smirReadValid = 1 << 27,
|
||||
smirBusy = 1 << 28
|
||||
};
|
||||
|
||||
/* Bit definitions of the Port Config Reg */
|
||||
enum pcr_bits {
|
||||
pcrPM = 1 << 0,
|
||||
pcrRBM = 1 << 1,
|
||||
pcrPBF = 1 << 2,
|
||||
pcrEN = 1 << 7,
|
||||
pcrLPBKMask = 0x3 << 8,
|
||||
pcrLPBKBit = 1 << 8,
|
||||
pcrFC = 1 << 10,
|
||||
pcrHS = 1 << 12,
|
||||
pcrHM = 1 << 13,
|
||||
pcrHDM = 1 << 14,
|
||||
pcrHD = 1 << 15,
|
||||
pcrISLMask = 0x7 << 28,
|
||||
pcrISLBit = 28,
|
||||
pcrACCS = 1 << 31
|
||||
};
|
||||
|
||||
/* Bit definitions of the Port Config Extend Reg */
|
||||
enum pcxr_bits {
|
||||
pcxrIGMP = 1,
|
||||
pcxrSPAN = 2,
|
||||
pcxrPAR = 4,
|
||||
pcxrPRIOtxMask = 0x7 << 3,
|
||||
pcxrPRIOtxBit = 3,
|
||||
pcxrPRIOrxMask = 0x3 << 6,
|
||||
pcxrPRIOrxBit = 6,
|
||||
pcxrPRIOrxOverride = 1 << 8,
|
||||
pcxrDPLXen = 1 << 9,
|
||||
pcxrFCTLen = 1 << 10,
|
||||
pcxrFLP = 1 << 11,
|
||||
pcxrFCTL = 1 << 12,
|
||||
pcxrMFLMask = 0x3 << 14,
|
||||
pcxrMFLBit = 14,
|
||||
pcxrMIBclrMode = 1 << 16,
|
||||
pcxrSpeed = 1 << 18,
|
||||
pcxrSpeeden = 1 << 19,
|
||||
pcxrRMIIen = 1 << 20,
|
||||
pcxrDSCPen = 1 << 21
|
||||
};
|
||||
|
||||
/* Bit definitions of the Port Command Reg */
|
||||
enum pcmr_bits {
|
||||
pcmrFJ = 1 << 15
|
||||
};
|
||||
|
||||
|
||||
/* Bit definitions of the Port Status Reg */
|
||||
enum psr_bits {
|
||||
psrSpeed = 1,
|
||||
psrDuplex = 2,
|
||||
psrFctl = 4,
|
||||
psrLink = 8,
|
||||
psrPause = 1 << 4,
|
||||
psrTxLow = 1 << 5,
|
||||
psrTxHigh = 1 << 6,
|
||||
psrTxInProg = 1 << 7
|
||||
};
|
||||
|
||||
/* Bit definitions of the SDMA Config Reg */
|
||||
enum sdcr_bits {
|
||||
sdcrRCMask = 0xf << 2,
|
||||
sdcrRCBit = 2,
|
||||
sdcrBLMR = 1 << 6,
|
||||
sdcrBLMT = 1 << 7,
|
||||
sdcrPOVR = 1 << 8,
|
||||
sdcrRIFB = 1 << 9,
|
||||
sdcrBSZMask = 0x3 << 12,
|
||||
sdcrBSZBit = 12
|
||||
};
|
||||
|
||||
/* Bit definitions of the SDMA Command Reg */
|
||||
enum sdcmr_bits {
|
||||
sdcmrERD = 1 << 7,
|
||||
sdcmrAR = 1 << 15,
|
||||
sdcmrSTDH = 1 << 16,
|
||||
sdcmrSTDL = 1 << 17,
|
||||
sdcmrTXDH = 1 << 23,
|
||||
sdcmrTXDL = 1 << 24,
|
||||
sdcmrAT = 1 << 31
|
||||
};
|
||||
|
||||
/* Bit definitions of the Interrupt Cause Reg */
|
||||
enum icr_bits {
|
||||
icrRxBuffer = 1,
|
||||
icrTxBufferHigh = 1 << 2,
|
||||
icrTxBufferLow = 1 << 3,
|
||||
icrTxEndHigh = 1 << 6,
|
||||
icrTxEndLow = 1 << 7,
|
||||
icrRxError = 1 << 8,
|
||||
icrTxErrorHigh = 1 << 10,
|
||||
icrTxErrorLow = 1 << 11,
|
||||
icrRxOVR = 1 << 12,
|
||||
icrTxUdr = 1 << 13,
|
||||
icrRxBufferQ0 = 1 << 16,
|
||||
icrRxBufferQ1 = 1 << 17,
|
||||
icrRxBufferQ2 = 1 << 18,
|
||||
icrRxBufferQ3 = 1 << 19,
|
||||
icrRxErrorQ0 = 1 << 20,
|
||||
icrRxErrorQ1 = 1 << 21,
|
||||
icrRxErrorQ2 = 1 << 22,
|
||||
icrRxErrorQ3 = 1 << 23,
|
||||
icrMIIPhySTC = 1 << 28,
|
||||
icrSMIdone = 1 << 29,
|
||||
icrEtherIntSum = 1 << 31
|
||||
};
|
||||
|
||||
|
||||
/* The Rx and Tx descriptor lists. */
|
||||
#ifdef __LITTLE_ENDIAN
|
||||
typedef struct {
|
||||
u32 cmdstat;
|
||||
u16 reserved; //-prk21aug01 u32 reserved:16;
|
||||
u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
|
||||
u32 buff_ptr;
|
||||
u32 next;
|
||||
} gt64240_td_t;
|
||||
|
||||
typedef struct {
|
||||
u32 cmdstat;
|
||||
u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
|
||||
u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
|
||||
u32 buff_ptr;
|
||||
u32 next;
|
||||
} gt64240_rd_t;
|
||||
#elif defined(__BIG_ENDIAN)
|
||||
typedef struct {
|
||||
u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
|
||||
u16 reserved; //-prk21aug01 u32 reserved:16;
|
||||
u32 cmdstat;
|
||||
u32 next;
|
||||
u32 buff_ptr;
|
||||
} gt64240_td_t;
|
||||
|
||||
typedef struct {
|
||||
u16 buff_sz; //-prk21aug01 u32 buff_sz:16;
|
||||
u16 byte_cnt; //-prk21aug01 u32 byte_cnt:16;
|
||||
u32 cmdstat;
|
||||
u32 next;
|
||||
u32 buff_ptr;
|
||||
} gt64240_rd_t;
|
||||
#else
|
||||
#error Either __BIG_ENDIAN or __LITTLE_ENDIAN must be defined!
|
||||
#endif
|
||||
|
||||
|
||||
/* Values for the Tx command-status descriptor entry. */
|
||||
enum td_cmdstat {
|
||||
txOwn = 1 << 31,
|
||||
txAutoMode = 1 << 30,
|
||||
txEI = 1 << 23,
|
||||
txGenCRC = 1 << 22,
|
||||
txPad = 1 << 18,
|
||||
txFirst = 1 << 17,
|
||||
txLast = 1 << 16,
|
||||
txErrorSummary = 1 << 15,
|
||||
txReTxCntMask = 0x0f << 10,
|
||||
txReTxCntBit = 10,
|
||||
txCollision = 1 << 9,
|
||||
txReTxLimit = 1 << 8,
|
||||
txUnderrun = 1 << 6,
|
||||
txLateCollision = 1 << 5
|
||||
};
|
||||
|
||||
|
||||
/* Values for the Rx command-status descriptor entry. */
|
||||
enum rd_cmdstat {
|
||||
rxOwn = 1 << 31,
|
||||
rxAutoMode = 1 << 30,
|
||||
rxEI = 1 << 23,
|
||||
rxFirst = 1 << 17,
|
||||
rxLast = 1 << 16,
|
||||
rxErrorSummary = 1 << 15,
|
||||
rxIGMP = 1 << 14,
|
||||
rxHashExpired = 1 << 13,
|
||||
rxMissedFrame = 1 << 12,
|
||||
rxFrameType = 1 << 11,
|
||||
rxShortFrame = 1 << 8,
|
||||
rxMaxFrameLen = 1 << 7,
|
||||
rxOverrun = 1 << 6,
|
||||
rxCollision = 1 << 4,
|
||||
rxCRCError = 1
|
||||
};
|
||||
|
||||
/* Bit fields of a Hash Table Entry */
|
||||
enum hash_table_entry {
|
||||
hteValid = 1,
|
||||
hteSkip = 2,
|
||||
hteRD = 4
|
||||
};
|
||||
|
||||
// The MIB counters
|
||||
typedef struct {
|
||||
u32 byteReceived;
|
||||
u32 byteSent;
|
||||
u32 framesReceived;
|
||||
u32 framesSent;
|
||||
u32 totalByteReceived;
|
||||
u32 totalFramesReceived;
|
||||
u32 broadcastFramesReceived;
|
||||
u32 multicastFramesReceived;
|
||||
u32 cRCError;
|
||||
u32 oversizeFrames;
|
||||
u32 fragments;
|
||||
u32 jabber;
|
||||
u32 collision;
|
||||
u32 lateCollision;
|
||||
u32 frames64;
|
||||
u32 frames65_127;
|
||||
u32 frames128_255;
|
||||
u32 frames256_511;
|
||||
u32 frames512_1023;
|
||||
u32 frames1024_MaxSize;
|
||||
u32 macRxError;
|
||||
u32 droppedFrames;
|
||||
u32 outMulticastFrames;
|
||||
u32 outBroadcastFrames;
|
||||
u32 undersizeFrames;
|
||||
} mib_counters_t;
|
||||
|
||||
|
||||
struct gt64240_private {
|
||||
gt64240_rd_t *rx_ring;
|
||||
gt64240_td_t *tx_ring;
|
||||
// The Rx and Tx rings must be 16-byte aligned
|
||||
dma_addr_t rx_ring_dma;
|
||||
dma_addr_t tx_ring_dma;
|
||||
char *hash_table;
|
||||
// The Hash Table must be 8-byte aligned
|
||||
dma_addr_t hash_table_dma;
|
||||
int hash_mode;
|
||||
|
||||
// The Rx buffers must be 8-byte aligned
|
||||
char *rx_buff;
|
||||
dma_addr_t rx_buff_dma;
|
||||
// Tx buffers (tx_skbuff[i]->data) with less than 8 bytes
|
||||
// of payload must be 8-byte aligned
|
||||
struct sk_buff *tx_skbuff[TX_RING_SIZE];
|
||||
int rx_next_out; /* The next free ring entry to receive */
|
||||
int tx_next_in; /* The next free ring entry to send */
|
||||
int tx_next_out; /* The last ring entry the ISR processed */
|
||||
int tx_count; /* current # of pkts waiting to be sent in Tx ring */
|
||||
int intr_work_done; /* number of Rx and Tx pkts processed in the isr */
|
||||
int tx_full; /* Tx ring is full */
|
||||
|
||||
mib_counters_t mib;
|
||||
struct net_device_stats stats;
|
||||
|
||||
int io_size;
|
||||
int port_num; // 0 or 1
|
||||
u32 port_offset;
|
||||
|
||||
int phy_addr; // PHY address
|
||||
u32 last_psr; // last value of the port status register
|
||||
|
||||
int options; /* User-settable misc. driver options. */
|
||||
int drv_flags;
|
||||
spinlock_t lock; /* Serialise access to device */
|
||||
struct mii_if_info mii_if;
|
||||
|
||||
u32 msg_enable;
|
||||
};
|
||||
|
||||
#endif /* _GT64240ETH_H */
|
@ -522,7 +522,7 @@ EXPORT_SYMBOL(genphy_read_status);
|
||||
|
||||
static int genphy_config_init(struct phy_device *phydev)
|
||||
{
|
||||
u32 val;
|
||||
int val;
|
||||
u32 features;
|
||||
|
||||
/* For now, I'll claim that the generic driver supports
|
||||
|
@ -2904,7 +2904,7 @@ static void s2io_mdio_write(u32 mmd_type, u64 addr, u16 value, struct net_device
|
||||
{
|
||||
u64 val64 = 0x0;
|
||||
nic_t *sp = dev->priv;
|
||||
XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
|
||||
XENA_dev_config_t __iomem *bar0 = sp->bar0;
|
||||
|
||||
//address transaction
|
||||
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
|
||||
@ -2953,7 +2953,7 @@ static u64 s2io_mdio_read(u32 mmd_type, u64 addr, struct net_device *dev)
|
||||
u64 val64 = 0x0;
|
||||
u64 rval64 = 0x0;
|
||||
nic_t *sp = dev->priv;
|
||||
XENA_dev_config_t *bar0 = (XENA_dev_config_t *)sp->bar0;
|
||||
XENA_dev_config_t __iomem *bar0 = sp->bar0;
|
||||
|
||||
/* address transaction */
|
||||
val64 = val64 | MDIO_MMD_INDX_ADDR(addr)
|
||||
@ -3276,7 +3276,7 @@ static void alarm_intr_handler(struct s2io_nic *nic)
|
||||
* SUCCESS on success and FAILURE on failure.
|
||||
*/
|
||||
|
||||
static int wait_for_cmd_complete(void *addr, u64 busy_bit)
|
||||
static int wait_for_cmd_complete(void __iomem *addr, u64 busy_bit)
|
||||
{
|
||||
int ret = FAILURE, cnt = 0;
|
||||
u64 val64;
|
||||
@ -4303,11 +4303,11 @@ static struct net_device_stats *s2io_get_stats(struct net_device *dev)
|
||||
sp->stats.tx_errors =
|
||||
le32_to_cpu(mac_control->stats_info->tmac_any_err_frms);
|
||||
sp->stats.rx_errors =
|
||||
le32_to_cpu(mac_control->stats_info->rmac_drop_frms);
|
||||
le64_to_cpu(mac_control->stats_info->rmac_drop_frms);
|
||||
sp->stats.multicast =
|
||||
le32_to_cpu(mac_control->stats_info->rmac_vld_mcst_frms);
|
||||
sp->stats.rx_length_errors =
|
||||
le32_to_cpu(mac_control->stats_info->rmac_long_frms);
|
||||
le64_to_cpu(mac_control->stats_info->rmac_long_frms);
|
||||
|
||||
return (&sp->stats);
|
||||
}
|
||||
|
@ -58,6 +58,7 @@
|
||||
#define TX_WATCHDOG (5 * HZ)
|
||||
#define NAPI_WEIGHT 64
|
||||
#define BLINK_MS 250
|
||||
#define LINK_HZ (HZ/2)
|
||||
|
||||
MODULE_DESCRIPTION("SysKonnect Gigabit Ethernet driver");
|
||||
MODULE_AUTHOR("Stephen Hemminger <shemminger@osdl.org>");
|
||||
@ -605,7 +606,12 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
|
||||
if (hw->chip_id == CHIP_ID_GENESIS) {
|
||||
switch (mode) {
|
||||
case LED_MODE_OFF:
|
||||
xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
|
||||
if (hw->phy_type == SK_PHY_BCOM)
|
||||
xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_OFF);
|
||||
else {
|
||||
skge_write32(hw, SK_REG(port, TX_LED_VAL), 0);
|
||||
skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_T_OFF);
|
||||
}
|
||||
skge_write8(hw, SK_REG(port, LNK_LED_REG), LINKLED_OFF);
|
||||
skge_write32(hw, SK_REG(port, RX_LED_VAL), 0);
|
||||
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_T_OFF);
|
||||
@ -625,8 +631,14 @@ static void skge_led(struct skge_port *skge, enum led_mode mode)
|
||||
skge_write32(hw, SK_REG(port, RX_LED_VAL), 100);
|
||||
skge_write8(hw, SK_REG(port, RX_LED_CTRL), LED_START);
|
||||
|
||||
xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
|
||||
break;
|
||||
if (hw->phy_type == SK_PHY_BCOM)
|
||||
xm_phy_write(hw, port, PHY_BCOM_P_EXT_CTRL, PHY_B_PEC_LED_ON);
|
||||
else {
|
||||
skge_write8(hw, SK_REG(port, TX_LED_TST), LED_T_ON);
|
||||
skge_write32(hw, SK_REG(port, TX_LED_VAL), 100);
|
||||
skge_write8(hw, SK_REG(port, TX_LED_CTRL), LED_START);
|
||||
}
|
||||
|
||||
}
|
||||
} else {
|
||||
switch (mode) {
|
||||
@ -879,6 +891,9 @@ static int __xm_phy_read(struct skge_hw *hw, int port, u16 reg, u16 *val)
|
||||
xm_write16(hw, port, XM_PHY_ADDR, reg | hw->phy_addr);
|
||||
*val = xm_read16(hw, port, XM_PHY_DATA);
|
||||
|
||||
if (hw->phy_type == SK_PHY_XMAC)
|
||||
goto ready;
|
||||
|
||||
for (i = 0; i < PHY_RETRIES; i++) {
|
||||
if (xm_read16(hw, port, XM_MMU_CMD) & XM_MMU_PHY_RDY)
|
||||
goto ready;
|
||||
@ -965,7 +980,8 @@ static void genesis_reset(struct skge_hw *hw, int port)
|
||||
xm_write16(hw, port, XM_RX_CMD, 0); /* reset RX CMD Reg */
|
||||
|
||||
/* disable Broadcom PHY IRQ */
|
||||
xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
|
||||
if (hw->phy_type == SK_PHY_BCOM)
|
||||
xm_write16(hw, port, PHY_BCOM_INT_MASK, 0xffff);
|
||||
|
||||
xm_outhash(hw, port, XM_HSM, zero);
|
||||
}
|
||||
@ -1000,60 +1016,64 @@ static void bcom_check_link(struct skge_hw *hw, int port)
|
||||
|
||||
if (netif_carrier_ok(dev))
|
||||
skge_link_down(skge);
|
||||
} else {
|
||||
if (skge->autoneg == AUTONEG_ENABLE &&
|
||||
(status & PHY_ST_AN_OVER)) {
|
||||
u16 lpa = xm_phy_read(hw, port, PHY_BCOM_AUNE_LP);
|
||||
u16 aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
|
||||
return;
|
||||
}
|
||||
|
||||
if (lpa & PHY_B_AN_RF) {
|
||||
printk(KERN_NOTICE PFX "%s: remote fault\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
if (skge->autoneg == AUTONEG_ENABLE) {
|
||||
u16 lpa, aux;
|
||||
|
||||
/* Check Duplex mismatch */
|
||||
switch (aux & PHY_B_AS_AN_RES_MSK) {
|
||||
case PHY_B_RES_1000FD:
|
||||
skge->duplex = DUPLEX_FULL;
|
||||
break;
|
||||
case PHY_B_RES_1000HD:
|
||||
skge->duplex = DUPLEX_HALF;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
if (!(status & PHY_ST_AN_OVER))
|
||||
return;
|
||||
|
||||
|
||||
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
||||
switch (aux & PHY_B_AS_PAUSE_MSK) {
|
||||
case PHY_B_AS_PAUSE_MSK:
|
||||
skge->flow_control = FLOW_MODE_SYMMETRIC;
|
||||
break;
|
||||
case PHY_B_AS_PRR:
|
||||
skge->flow_control = FLOW_MODE_REM_SEND;
|
||||
break;
|
||||
case PHY_B_AS_PRT:
|
||||
skge->flow_control = FLOW_MODE_LOC_SEND;
|
||||
break;
|
||||
default:
|
||||
skge->flow_control = FLOW_MODE_NONE;
|
||||
}
|
||||
|
||||
skge->speed = SPEED_1000;
|
||||
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
||||
if (lpa & PHY_B_AN_RF) {
|
||||
printk(KERN_NOTICE PFX "%s: remote fault\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
genesis_link_up(skge);
|
||||
aux = xm_phy_read(hw, port, PHY_BCOM_AUX_STAT);
|
||||
|
||||
/* Check Duplex mismatch */
|
||||
switch (aux & PHY_B_AS_AN_RES_MSK) {
|
||||
case PHY_B_RES_1000FD:
|
||||
skge->duplex = DUPLEX_FULL;
|
||||
break;
|
||||
case PHY_B_RES_1000HD:
|
||||
skge->duplex = DUPLEX_HALF;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
||||
switch (aux & PHY_B_AS_PAUSE_MSK) {
|
||||
case PHY_B_AS_PAUSE_MSK:
|
||||
skge->flow_control = FLOW_MODE_SYMMETRIC;
|
||||
break;
|
||||
case PHY_B_AS_PRR:
|
||||
skge->flow_control = FLOW_MODE_REM_SEND;
|
||||
break;
|
||||
case PHY_B_AS_PRT:
|
||||
skge->flow_control = FLOW_MODE_LOC_SEND;
|
||||
break;
|
||||
default:
|
||||
skge->flow_control = FLOW_MODE_NONE;
|
||||
}
|
||||
skge->speed = SPEED_1000;
|
||||
}
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
genesis_link_up(skge);
|
||||
}
|
||||
|
||||
/* Broadcom 5400 only supports giagabit! SysKonnect did not put an additional
|
||||
* Phy on for 100 or 10Mbit operation
|
||||
*/
|
||||
static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
||||
static void bcom_phy_init(struct skge_port *skge)
|
||||
{
|
||||
struct skge_hw *hw = skge->hw;
|
||||
int port = skge->port;
|
||||
@ -1144,7 +1164,7 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
||||
phy_pause_map[skge->flow_control] | PHY_AN_CSMA);
|
||||
|
||||
/* Handle Jumbo frames */
|
||||
if (jumbo) {
|
||||
if (hw->dev[port]->mtu > ETH_DATA_LEN) {
|
||||
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
||||
PHY_B_AC_TX_TST | PHY_B_AC_LONG_PACK);
|
||||
|
||||
@ -1157,8 +1177,154 @@ static void bcom_phy_init(struct skge_port *skge, int jumbo)
|
||||
|
||||
/* Use link status change interrupt */
|
||||
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
||||
}
|
||||
|
||||
bcom_check_link(hw, port);
|
||||
static void xm_phy_init(struct skge_port *skge)
|
||||
{
|
||||
struct skge_hw *hw = skge->hw;
|
||||
int port = skge->port;
|
||||
u16 ctrl = 0;
|
||||
|
||||
if (skge->autoneg == AUTONEG_ENABLE) {
|
||||
if (skge->advertising & ADVERTISED_1000baseT_Half)
|
||||
ctrl |= PHY_X_AN_HD;
|
||||
if (skge->advertising & ADVERTISED_1000baseT_Full)
|
||||
ctrl |= PHY_X_AN_FD;
|
||||
|
||||
switch(skge->flow_control) {
|
||||
case FLOW_MODE_NONE:
|
||||
ctrl |= PHY_X_P_NO_PAUSE;
|
||||
break;
|
||||
case FLOW_MODE_LOC_SEND:
|
||||
ctrl |= PHY_X_P_ASYM_MD;
|
||||
break;
|
||||
case FLOW_MODE_SYMMETRIC:
|
||||
ctrl |= PHY_X_P_BOTH_MD;
|
||||
break;
|
||||
}
|
||||
|
||||
xm_phy_write(hw, port, PHY_XMAC_AUNE_ADV, ctrl);
|
||||
|
||||
/* Restart Auto-negotiation */
|
||||
ctrl = PHY_CT_ANE | PHY_CT_RE_CFG;
|
||||
} else {
|
||||
/* Set DuplexMode in Config register */
|
||||
if (skge->duplex == DUPLEX_FULL)
|
||||
ctrl |= PHY_CT_DUP_MD;
|
||||
/*
|
||||
* Do NOT enable Auto-negotiation here. This would hold
|
||||
* the link down because no IDLEs are transmitted
|
||||
*/
|
||||
}
|
||||
|
||||
xm_phy_write(hw, port, PHY_XMAC_CTRL, ctrl);
|
||||
|
||||
/* Poll PHY for status changes */
|
||||
schedule_delayed_work(&skge->link_thread, LINK_HZ);
|
||||
}
|
||||
|
||||
static void xm_check_link(struct net_device *dev)
|
||||
{
|
||||
struct skge_port *skge = netdev_priv(dev);
|
||||
struct skge_hw *hw = skge->hw;
|
||||
int port = skge->port;
|
||||
u16 status;
|
||||
|
||||
/* read twice because of latch */
|
||||
(void) xm_phy_read(hw, port, PHY_XMAC_STAT);
|
||||
status = xm_phy_read(hw, port, PHY_XMAC_STAT);
|
||||
|
||||
if ((status & PHY_ST_LSYNC) == 0) {
|
||||
u16 cmd = xm_read16(hw, port, XM_MMU_CMD);
|
||||
cmd &= ~(XM_MMU_ENA_RX | XM_MMU_ENA_TX);
|
||||
xm_write16(hw, port, XM_MMU_CMD, cmd);
|
||||
/* dummy read to ensure writing */
|
||||
(void) xm_read16(hw, port, XM_MMU_CMD);
|
||||
|
||||
if (netif_carrier_ok(dev))
|
||||
skge_link_down(skge);
|
||||
return;
|
||||
}
|
||||
|
||||
if (skge->autoneg == AUTONEG_ENABLE) {
|
||||
u16 lpa, res;
|
||||
|
||||
if (!(status & PHY_ST_AN_OVER))
|
||||
return;
|
||||
|
||||
lpa = xm_phy_read(hw, port, PHY_XMAC_AUNE_LP);
|
||||
if (lpa & PHY_B_AN_RF) {
|
||||
printk(KERN_NOTICE PFX "%s: remote fault\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
res = xm_phy_read(hw, port, PHY_XMAC_RES_ABI);
|
||||
|
||||
/* Check Duplex mismatch */
|
||||
switch (res & (PHY_X_RS_HD | PHY_X_RS_FD)) {
|
||||
case PHY_X_RS_FD:
|
||||
skge->duplex = DUPLEX_FULL;
|
||||
break;
|
||||
case PHY_X_RS_HD:
|
||||
skge->duplex = DUPLEX_HALF;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_NOTICE PFX "%s: duplex mismatch\n",
|
||||
dev->name);
|
||||
return;
|
||||
}
|
||||
|
||||
/* We are using IEEE 802.3z/D5.0 Table 37-4 */
|
||||
if (lpa & PHY_X_P_SYM_MD)
|
||||
skge->flow_control = FLOW_MODE_SYMMETRIC;
|
||||
else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_ASYM_MD)
|
||||
skge->flow_control = FLOW_MODE_REM_SEND;
|
||||
else if ((lpa & PHY_X_RS_PAUSE) == PHY_X_P_BOTH_MD)
|
||||
skge->flow_control = FLOW_MODE_LOC_SEND;
|
||||
else
|
||||
skge->flow_control = FLOW_MODE_NONE;
|
||||
|
||||
|
||||
skge->speed = SPEED_1000;
|
||||
}
|
||||
|
||||
if (!netif_carrier_ok(dev))
|
||||
genesis_link_up(skge);
|
||||
}
|
||||
|
||||
/* Poll to check for link coming up.
|
||||
* Since internal PHY is wired to a level triggered pin, can't
|
||||
* get an interrupt when carrier is detected.
|
||||
*/
|
||||
static void xm_link_timer(void *arg)
|
||||
{
|
||||
struct net_device *dev = arg;
|
||||
struct skge_port *skge = netdev_priv(arg);
|
||||
struct skge_hw *hw = skge->hw;
|
||||
int port = skge->port;
|
||||
|
||||
if (!netif_running(dev))
|
||||
return;
|
||||
|
||||
if (netif_carrier_ok(dev)) {
|
||||
xm_read16(hw, port, XM_ISRC);
|
||||
if (!(xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS))
|
||||
goto nochange;
|
||||
} else {
|
||||
if (xm_read32(hw, port, XM_GP_PORT) & XM_GP_INP_ASS)
|
||||
goto nochange;
|
||||
xm_read16(hw, port, XM_ISRC);
|
||||
if (xm_read16(hw, port, XM_ISRC) & XM_IS_INP_ASS)
|
||||
goto nochange;
|
||||
}
|
||||
|
||||
mutex_lock(&hw->phy_mutex);
|
||||
xm_check_link(dev);
|
||||
mutex_unlock(&hw->phy_mutex);
|
||||
|
||||
nochange:
|
||||
schedule_delayed_work(&skge->link_thread, LINK_HZ);
|
||||
}
|
||||
|
||||
static void genesis_mac_init(struct skge_hw *hw, int port)
|
||||
@ -1189,20 +1355,29 @@ static void genesis_mac_init(struct skge_hw *hw, int port)
|
||||
* namely for the 1000baseTX cards that use the XMAC's
|
||||
* GMII mode.
|
||||
*/
|
||||
/* Take external Phy out of reset */
|
||||
r = skge_read32(hw, B2_GP_IO);
|
||||
if (port == 0)
|
||||
r |= GP_DIR_0|GP_IO_0;
|
||||
else
|
||||
r |= GP_DIR_2|GP_IO_2;
|
||||
if (hw->phy_type != SK_PHY_XMAC) {
|
||||
/* Take external Phy out of reset */
|
||||
r = skge_read32(hw, B2_GP_IO);
|
||||
if (port == 0)
|
||||
r |= GP_DIR_0|GP_IO_0;
|
||||
else
|
||||
r |= GP_DIR_2|GP_IO_2;
|
||||
|
||||
skge_write32(hw, B2_GP_IO, r);
|
||||
skge_write32(hw, B2_GP_IO, r);
|
||||
|
||||
/* Enable GMII interface */
|
||||
xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
|
||||
}
|
||||
|
||||
|
||||
/* Enable GMII interface */
|
||||
xm_write16(hw, port, XM_HW_CFG, XM_HW_GMII_MD);
|
||||
|
||||
bcom_phy_init(skge, jumbo);
|
||||
switch(hw->phy_type) {
|
||||
case SK_PHY_XMAC:
|
||||
xm_phy_init(skge);
|
||||
break;
|
||||
case SK_PHY_BCOM:
|
||||
bcom_phy_init(skge);
|
||||
bcom_check_link(hw, port);
|
||||
}
|
||||
|
||||
/* Set Station Address */
|
||||
xm_outaddr(hw, port, XM_SA, dev->dev_addr);
|
||||
@ -1335,16 +1510,18 @@ static void genesis_stop(struct skge_port *skge)
|
||||
skge_write16(hw, SK_REG(port, TX_MFF_CTRL1), MFF_SET_MAC_RST);
|
||||
|
||||
/* For external PHYs there must be special handling */
|
||||
reg = skge_read32(hw, B2_GP_IO);
|
||||
if (port == 0) {
|
||||
reg |= GP_DIR_0;
|
||||
reg &= ~GP_IO_0;
|
||||
} else {
|
||||
reg |= GP_DIR_2;
|
||||
reg &= ~GP_IO_2;
|
||||
if (hw->phy_type != SK_PHY_XMAC) {
|
||||
reg = skge_read32(hw, B2_GP_IO);
|
||||
if (port == 0) {
|
||||
reg |= GP_DIR_0;
|
||||
reg &= ~GP_IO_0;
|
||||
} else {
|
||||
reg |= GP_DIR_2;
|
||||
reg &= ~GP_IO_2;
|
||||
}
|
||||
skge_write32(hw, B2_GP_IO, reg);
|
||||
skge_read32(hw, B2_GP_IO);
|
||||
}
|
||||
skge_write32(hw, B2_GP_IO, reg);
|
||||
skge_read32(hw, B2_GP_IO);
|
||||
|
||||
xm_write16(hw, port, XM_MMU_CMD,
|
||||
xm_read16(hw, port, XM_MMU_CMD)
|
||||
@ -1406,7 +1583,7 @@ static void genesis_link_up(struct skge_port *skge)
|
||||
struct skge_hw *hw = skge->hw;
|
||||
int port = skge->port;
|
||||
u16 cmd;
|
||||
u32 mode, msk;
|
||||
u32 mode;
|
||||
|
||||
cmd = xm_read16(hw, port, XM_MMU_CMD);
|
||||
|
||||
@ -1454,27 +1631,24 @@ static void genesis_link_up(struct skge_port *skge)
|
||||
}
|
||||
|
||||
xm_write32(hw, port, XM_MODE, mode);
|
||||
|
||||
msk = XM_DEF_MSK;
|
||||
/* disable GP0 interrupt bit for external Phy */
|
||||
msk |= XM_IS_INP_ASS;
|
||||
|
||||
xm_write16(hw, port, XM_IMSK, msk);
|
||||
xm_write16(hw, port, XM_IMSK, XM_DEF_MSK);
|
||||
xm_read16(hw, port, XM_ISRC);
|
||||
|
||||
/* get MMU Command Reg. */
|
||||
cmd = xm_read16(hw, port, XM_MMU_CMD);
|
||||
if (skge->duplex == DUPLEX_FULL)
|
||||
if (hw->phy_type != SK_PHY_XMAC && skge->duplex == DUPLEX_FULL)
|
||||
cmd |= XM_MMU_GMII_FD;
|
||||
|
||||
/*
|
||||
* Workaround BCOM Errata (#10523) for all BCom Phys
|
||||
* Enable Power Management after link up
|
||||
*/
|
||||
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
||||
xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
|
||||
& ~PHY_B_AC_DIS_PM);
|
||||
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
||||
if (hw->phy_type == SK_PHY_BCOM) {
|
||||
xm_phy_write(hw, port, PHY_BCOM_AUX_CTRL,
|
||||
xm_phy_read(hw, port, PHY_BCOM_AUX_CTRL)
|
||||
& ~PHY_B_AC_DIS_PM);
|
||||
xm_phy_write(hw, port, PHY_BCOM_INT_MASK, PHY_B_DEF_MSK);
|
||||
}
|
||||
|
||||
/* enable Rx/Tx */
|
||||
xm_write16(hw, port, XM_MMU_CMD,
|
||||
@ -2240,6 +2414,8 @@ static int skge_down(struct net_device *dev)
|
||||
printk(KERN_INFO PFX "%s: disabling interface\n", dev->name);
|
||||
|
||||
netif_stop_queue(dev);
|
||||
if (hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC)
|
||||
cancel_rearming_delayed_work(&skge->link_thread);
|
||||
|
||||
skge_write8(skge->hw, SK_REG(skge->port, LNK_LED_REG), LED_OFF);
|
||||
if (hw->chip_id == CHIP_ID_GENESIS)
|
||||
@ -2862,7 +3038,7 @@ static void skge_extirq(void *arg)
|
||||
if (netif_running(dev)) {
|
||||
if (hw->chip_id != CHIP_ID_GENESIS)
|
||||
yukon_phy_intr(skge);
|
||||
else
|
||||
else if (hw->phy_type == SK_PHY_BCOM)
|
||||
bcom_phy_intr(skge);
|
||||
}
|
||||
}
|
||||
@ -3014,7 +3190,7 @@ static int skge_reset(struct skge_hw *hw)
|
||||
{
|
||||
u32 reg;
|
||||
u16 ctst, pci_status;
|
||||
u8 t8, mac_cfg, pmd_type, phy_type;
|
||||
u8 t8, mac_cfg, pmd_type;
|
||||
int i;
|
||||
|
||||
ctst = skge_read16(hw, B0_CTST);
|
||||
@ -3038,19 +3214,22 @@ static int skge_reset(struct skge_hw *hw)
|
||||
ctst & (CS_CLK_RUN_HOT|CS_CLK_RUN_RST|CS_CLK_RUN_ENA));
|
||||
|
||||
hw->chip_id = skge_read8(hw, B2_CHIP_ID);
|
||||
phy_type = skge_read8(hw, B2_E_1) & 0xf;
|
||||
hw->phy_type = skge_read8(hw, B2_E_1) & 0xf;
|
||||
pmd_type = skge_read8(hw, B2_PMD_TYP);
|
||||
hw->copper = (pmd_type == 'T' || pmd_type == '1');
|
||||
|
||||
switch (hw->chip_id) {
|
||||
case CHIP_ID_GENESIS:
|
||||
switch (phy_type) {
|
||||
switch (hw->phy_type) {
|
||||
case SK_PHY_XMAC:
|
||||
hw->phy_addr = PHY_ADDR_XMAC;
|
||||
break;
|
||||
case SK_PHY_BCOM:
|
||||
hw->phy_addr = PHY_ADDR_BCOM;
|
||||
break;
|
||||
default:
|
||||
printk(KERN_ERR PFX "%s: unsupported phy type 0x%x\n",
|
||||
pci_name(hw->pdev), phy_type);
|
||||
pci_name(hw->pdev), hw->phy_type);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
break;
|
||||
@ -3058,7 +3237,7 @@ static int skge_reset(struct skge_hw *hw)
|
||||
case CHIP_ID_YUKON:
|
||||
case CHIP_ID_YUKON_LITE:
|
||||
case CHIP_ID_YUKON_LP:
|
||||
if (phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
|
||||
if (hw->phy_type < SK_PHY_MARV_COPPER && pmd_type != 'S')
|
||||
hw->copper = 1;
|
||||
|
||||
hw->phy_addr = PHY_ADDR_MARV;
|
||||
@ -3089,10 +3268,13 @@ static int skge_reset(struct skge_hw *hw)
|
||||
else
|
||||
hw->ram_size = t8 * 4096;
|
||||
|
||||
hw->intr_mask = IS_HW_ERR | IS_EXT_REG | IS_PORT_1;
|
||||
hw->intr_mask = IS_HW_ERR | IS_PORT_1;
|
||||
if (hw->ports > 1)
|
||||
hw->intr_mask |= IS_PORT_2;
|
||||
|
||||
if (!(hw->chip_id == CHIP_ID_GENESIS && hw->phy_type == SK_PHY_XMAC))
|
||||
hw->intr_mask |= IS_EXT_REG;
|
||||
|
||||
if (hw->chip_id == CHIP_ID_GENESIS)
|
||||
genesis_init(hw);
|
||||
else {
|
||||
@ -3226,6 +3408,9 @@ static struct net_device *skge_devinit(struct skge_hw *hw, int port,
|
||||
|
||||
skge->port = port;
|
||||
|
||||
/* Only used for Genesis XMAC */
|
||||
INIT_WORK(&skge->link_thread, xm_link_timer, dev);
|
||||
|
||||
if (hw->chip_id != CHIP_ID_GENESIS) {
|
||||
dev->features |= NETIF_F_IP_CSUM | NETIF_F_SG;
|
||||
skge->rx_csum = 1;
|
||||
|
@ -934,7 +934,7 @@ enum {
|
||||
PHY_XMAC_AUNE_ADV = 0x04,/* 16 bit r/w Auto-Neg. Advertisement */
|
||||
PHY_XMAC_AUNE_LP = 0x05,/* 16 bit r/o Link Partner Abi Reg */
|
||||
PHY_XMAC_AUNE_EXP = 0x06,/* 16 bit r/o Auto-Neg. Expansion Reg */
|
||||
PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
|
||||
PHY_XMAC_NEPG = 0x07,/* 16 bit r/w Next Page Register */
|
||||
PHY_XMAC_NEPG_LP = 0x08,/* 16 bit r/o Next Page Link Partner */
|
||||
|
||||
PHY_XMAC_EXT_STAT = 0x0f,/* 16 bit r/o Ext Status Register */
|
||||
@ -1097,13 +1097,36 @@ enum {
|
||||
|
||||
/* Pause Bits (PHY_X_AN_PAUSE and PHY_X_RS_PAUSE) encoding */
|
||||
enum {
|
||||
PHY_X_P_NO_PAUSE = 0<<7,/* Bit 8..7: no Pause Mode */
|
||||
PHY_X_P_NO_PAUSE= 0<<7,/* Bit 8..7: no Pause Mode */
|
||||
PHY_X_P_SYM_MD = 1<<7, /* Bit 8..7: symmetric Pause Mode */
|
||||
PHY_X_P_ASYM_MD = 2<<7,/* Bit 8..7: asymmetric Pause Mode */
|
||||
PHY_X_P_BOTH_MD = 3<<7,/* Bit 8..7: both Pause Mode */
|
||||
};
|
||||
|
||||
|
||||
/***** PHY_XMAC_EXT_STAT 16 bit r/w Extended Status Register *****/
|
||||
enum {
|
||||
PHY_X_EX_FD = 1<<15, /* Bit 15: Device Supports Full Duplex */
|
||||
PHY_X_EX_HD = 1<<14, /* Bit 14: Device Supports Half Duplex */
|
||||
};
|
||||
|
||||
/***** PHY_XMAC_RES_ABI 16 bit r/o PHY Resolved Ability *****/
|
||||
enum {
|
||||
PHY_X_RS_PAUSE = 3<<7, /* Bit 8..7: selected Pause Mode */
|
||||
PHY_X_RS_HD = 1<<6, /* Bit 6: Half Duplex Mode selected */
|
||||
PHY_X_RS_FD = 1<<5, /* Bit 5: Full Duplex Mode selected */
|
||||
PHY_X_RS_ABLMIS = 1<<4, /* Bit 4: duplex or pause cap mismatch */
|
||||
PHY_X_RS_PAUMIS = 1<<3, /* Bit 3: pause capability mismatch */
|
||||
};
|
||||
|
||||
/* Remote Fault Bits (PHY_X_AN_RFB) encoding */
|
||||
enum {
|
||||
X_RFB_OK = 0<<12,/* Bit 13..12 No errors, Link OK */
|
||||
X_RFB_LF = 1<<12,/* Bit 13..12 Link Failure */
|
||||
X_RFB_OFF = 2<<12,/* Bit 13..12 Offline */
|
||||
X_RFB_AN_ERR = 3<<12,/* Bit 13..12 Auto-Negotiation Error */
|
||||
};
|
||||
|
||||
/* Broadcom-Specific */
|
||||
/***** PHY_BCOM_1000T_CTRL 16 bit r/w 1000Base-T Control Reg *****/
|
||||
enum {
|
||||
@ -2158,8 +2181,8 @@ enum {
|
||||
XM_IS_LNK_AE = 1<<14, /* Bit 14: Link Asynchronous Event */
|
||||
XM_IS_TX_ABORT = 1<<13, /* Bit 13: Transmit Abort, late Col. etc */
|
||||
XM_IS_FRC_INT = 1<<12, /* Bit 12: Force INT bit set in GP */
|
||||
XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
|
||||
XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
|
||||
XM_IS_INP_ASS = 1<<11, /* Bit 11: Input Asserted, GP bit 0 set */
|
||||
XM_IS_LIPA_RC = 1<<10, /* Bit 10: Link Partner requests config */
|
||||
XM_IS_RX_PAGE = 1<<9, /* Bit 9: Page Received */
|
||||
XM_IS_TX_PAGE = 1<<8, /* Bit 8: Next Page Loaded for Transmit */
|
||||
XM_IS_AND = 1<<7, /* Bit 7: Auto-Negotiation Done */
|
||||
@ -2172,9 +2195,7 @@ enum {
|
||||
XM_IS_RX_COMP = 1<<0, /* Bit 0: Frame Rx Complete */
|
||||
};
|
||||
|
||||
#define XM_DEF_MSK (~(XM_IS_INP_ASS | XM_IS_LIPA_RC | XM_IS_RX_PAGE | \
|
||||
XM_IS_AND | XM_IS_RXC_OV | XM_IS_TXC_OV | \
|
||||
XM_IS_RXF_OV | XM_IS_TXF_UR))
|
||||
#define XM_DEF_MSK (~(XM_IS_RXC_OV | XM_IS_TXC_OV | XM_IS_RXF_OV | XM_IS_TXF_UR))
|
||||
|
||||
|
||||
/* XM_HW_CFG 16 bit r/w Hardware Config Register */
|
||||
@ -2396,6 +2417,7 @@ struct skge_hw {
|
||||
u8 chip_rev;
|
||||
u8 copper;
|
||||
u8 ports;
|
||||
u8 phy_type;
|
||||
|
||||
u32 ram_size;
|
||||
u32 ram_offset;
|
||||
@ -2422,6 +2444,7 @@ struct skge_port {
|
||||
|
||||
struct net_device_stats net_stats;
|
||||
|
||||
struct work_struct link_thread;
|
||||
u8 rx_csum;
|
||||
u8 blink_on;
|
||||
u8 flow_control;
|
||||
|
@ -379,6 +379,24 @@ static inline void LPD7_SMC_outsw (unsigned char* a, int r,
|
||||
|
||||
#define SMC_IRQ_FLAGS (0)
|
||||
|
||||
#elif defined(CONFIG_ARCH_VERSATILE)
|
||||
|
||||
#define SMC_CAN_USE_8BIT 1
|
||||
#define SMC_CAN_USE_16BIT 1
|
||||
#define SMC_CAN_USE_32BIT 1
|
||||
#define SMC_NOWAIT 1
|
||||
|
||||
#define SMC_inb(a, r) readb((a) + (r))
|
||||
#define SMC_inw(a, r) readw((a) + (r))
|
||||
#define SMC_inl(a, r) readl((a) + (r))
|
||||
#define SMC_outb(v, a, r) writeb(v, (a) + (r))
|
||||
#define SMC_outw(v, a, r) writew(v, (a) + (r))
|
||||
#define SMC_outl(v, a, r) writel(v, (a) + (r))
|
||||
#define SMC_insl(a, r, p, l) readsl((a) + (r), p, l)
|
||||
#define SMC_outsl(a, r, p, l) writesl((a) + (r), p, l)
|
||||
|
||||
#define SMC_IRQ_FLAGS (0)
|
||||
|
||||
#else
|
||||
|
||||
#define SMC_CAN_USE_8BIT 1
|
||||
|
@ -1876,7 +1876,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
|
||||
datap[size+1]=io_word & 0xff;
|
||||
}
|
||||
|
||||
|
||||
size = sprintf(buffer, "\n%6s: Adapter Address : Node Address : Functional Addr\n", dev->name);
|
||||
|
||||
size += sprintf(buffer + size,
|
||||
@ -1932,64 +1931,6 @@ static int sprintf_info(char *buffer, struct net_device *dev)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
|
||||
static int streamer_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
int i;
|
||||
struct streamer_private *streamer_priv = (struct streamer_private *) dev->priv;
|
||||
u8 __iomem *streamer_mmio = streamer_priv->streamer_mmio;
|
||||
|
||||
switch(cmd) {
|
||||
case IOCTL_SISR_MASK:
|
||||
writew(SISR_MI, streamer_mmio + SISR_MASK_SUM);
|
||||
break;
|
||||
case IOCTL_SPIN_LOCK_TEST:
|
||||
printk(KERN_INFO "spin_lock() called.\n");
|
||||
spin_lock(&streamer_priv->streamer_lock);
|
||||
spin_unlock(&streamer_priv->streamer_lock);
|
||||
printk(KERN_INFO "spin_unlock() finished.\n");
|
||||
break;
|
||||
case IOCTL_PRINT_BDAS:
|
||||
printk(KERN_INFO "bdas: RXBDA: %x RXLBDA: %x TX2FDA: %x TX2LFDA: %x\n",
|
||||
readw(streamer_mmio + RXBDA),
|
||||
readw(streamer_mmio + RXLBDA),
|
||||
readw(streamer_mmio + TX2FDA),
|
||||
readw(streamer_mmio + TX2LFDA));
|
||||
break;
|
||||
case IOCTL_PRINT_REGISTERS:
|
||||
printk(KERN_INFO "registers:\n");
|
||||
printk(KERN_INFO "SISR: %04x MISR: %04x LISR: %04x BCTL: %04x BMCTL: %04x\nmask %04x mask %04x\n",
|
||||
readw(streamer_mmio + SISR),
|
||||
readw(streamer_mmio + MISR_RUM),
|
||||
readw(streamer_mmio + LISR),
|
||||
readw(streamer_mmio + BCTL),
|
||||
readw(streamer_mmio + BMCTL_SUM),
|
||||
readw(streamer_mmio + SISR_MASK),
|
||||
readw(streamer_mmio + MISR_MASK));
|
||||
break;
|
||||
case IOCTL_PRINT_RX_BUFS:
|
||||
printk(KERN_INFO "Print rx bufs:\n");
|
||||
for(i=0; i<STREAMER_RX_RING_SIZE; i++)
|
||||
printk(KERN_INFO "rx_ring %d status: 0x%x\n", i,
|
||||
streamer_priv->streamer_rx_ring[i].status);
|
||||
break;
|
||||
case IOCTL_PRINT_TX_BUFS:
|
||||
printk(KERN_INFO "Print tx bufs:\n");
|
||||
for(i=0; i<STREAMER_TX_RING_SIZE; i++)
|
||||
printk(KERN_INFO "tx_ring %d status: 0x%x\n", i,
|
||||
streamer_priv->streamer_tx_ring[i].status);
|
||||
break;
|
||||
case IOCTL_RX_CMD:
|
||||
streamer_rx(dev);
|
||||
printk(KERN_INFO "Sent rx command.\n");
|
||||
break;
|
||||
default:
|
||||
printk(KERN_INFO "Bad ioctl!\n");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static struct pci_driver streamer_pci_driver = {
|
||||
.name = "lanstreamer",
|
||||
.id_table = streamer_pci_tbl,
|
||||
|
@ -62,18 +62,6 @@
|
||||
|
||||
#include <linux/version.h>
|
||||
|
||||
#if STREAMER_IOCTL && (LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0))
|
||||
#include <asm/ioctl.h>
|
||||
#define IOCTL_PRINT_RX_BUFS SIOCDEVPRIVATE
|
||||
#define IOCTL_PRINT_TX_BUFS SIOCDEVPRIVATE+1
|
||||
#define IOCTL_RX_CMD SIOCDEVPRIVATE+2
|
||||
#define IOCTL_TX_CMD SIOCDEVPRIVATE+3
|
||||
#define IOCTL_PRINT_REGISTERS SIOCDEVPRIVATE+4
|
||||
#define IOCTL_PRINT_BDAS SIOCDEVPRIVATE+5
|
||||
#define IOCTL_SPIN_LOCK_TEST SIOCDEVPRIVATE+6
|
||||
#define IOCTL_SISR_MASK SIOCDEVPRIVATE+7
|
||||
#endif
|
||||
|
||||
/* MAX_INTR - the maximum number of times we can loop
|
||||
* inside the interrupt function before returning
|
||||
* control to the OS (maximum value is 256)
|
||||
|
@ -333,11 +333,7 @@ enum state_values {
|
||||
#define TYPHOON_RESET_TIMEOUT_NOSLEEP ((6 * 1000000) / TYPHOON_UDELAY)
|
||||
#define TYPHOON_WAIT_TIMEOUT ((1000000 / 2) / TYPHOON_UDELAY)
|
||||
|
||||
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 28)
|
||||
#define typhoon_synchronize_irq(x) synchronize_irq()
|
||||
#else
|
||||
#define typhoon_synchronize_irq(x) synchronize_irq(x)
|
||||
#endif
|
||||
|
||||
#if defined(NETIF_F_TSO)
|
||||
#define skb_tso_size(x) (skb_shinfo(x)->gso_size)
|
||||
|
@ -154,7 +154,7 @@ config HDLC
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_RAW
|
||||
bool "Raw HDLC support"
|
||||
tristate "Raw HDLC support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting raw HDLC over WAN connections.
|
||||
@ -162,7 +162,7 @@ config HDLC_RAW
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_RAW_ETH
|
||||
bool "Raw HDLC Ethernet device support"
|
||||
tristate "Raw HDLC Ethernet device support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting raw HDLC Ethernet device emulation
|
||||
@ -173,7 +173,7 @@ config HDLC_RAW_ETH
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_CISCO
|
||||
bool "Cisco HDLC support"
|
||||
tristate "Cisco HDLC support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting Cisco HDLC over WAN connections.
|
||||
@ -181,7 +181,7 @@ config HDLC_CISCO
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_FR
|
||||
bool "Frame Relay support"
|
||||
tristate "Frame Relay support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting Frame Relay over WAN connections.
|
||||
@ -189,7 +189,7 @@ config HDLC_FR
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_PPP
|
||||
bool "Synchronous Point-to-Point Protocol (PPP) support"
|
||||
tristate "Synchronous Point-to-Point Protocol (PPP) support"
|
||||
depends on HDLC
|
||||
help
|
||||
Generic HDLC driver supporting PPP over WAN connections.
|
||||
@ -197,7 +197,7 @@ config HDLC_PPP
|
||||
If unsure, say N.
|
||||
|
||||
config HDLC_X25
|
||||
bool "X.25 protocol support"
|
||||
tristate "X.25 protocol support"
|
||||
depends on HDLC && (LAPB=m && HDLC=m || LAPB=y)
|
||||
help
|
||||
Generic HDLC driver supporting X.25 over WAN connections.
|
||||
|
@ -9,14 +9,13 @@ cyclomx-y := cycx_main.o
|
||||
cyclomx-$(CONFIG_CYCLOMX_X25) += cycx_x25.o
|
||||
cyclomx-objs := $(cyclomx-y)
|
||||
|
||||
hdlc-y := hdlc_generic.o
|
||||
hdlc-$(CONFIG_HDLC_RAW) += hdlc_raw.o
|
||||
hdlc-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
|
||||
hdlc-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
|
||||
hdlc-$(CONFIG_HDLC_FR) += hdlc_fr.o
|
||||
hdlc-$(CONFIG_HDLC_PPP) += hdlc_ppp.o
|
||||
hdlc-$(CONFIG_HDLC_X25) += hdlc_x25.o
|
||||
hdlc-objs := $(hdlc-y)
|
||||
obj-$(CONFIG_HDLC) += hdlc.o
|
||||
obj-$(CONFIG_HDLC_RAW) += hdlc_raw.o
|
||||
obj-$(CONFIG_HDLC_RAW_ETH) += hdlc_raw_eth.o
|
||||
obj-$(CONFIG_HDLC_CISCO) += hdlc_cisco.o
|
||||
obj-$(CONFIG_HDLC_FR) += hdlc_fr.o
|
||||
obj-$(CONFIG_HDLC_PPP) += hdlc_ppp.o syncppp.o
|
||||
obj-$(CONFIG_HDLC_X25) += hdlc_x25.o
|
||||
|
||||
pc300-y := pc300_drv.o
|
||||
pc300-$(CONFIG_PC300_MLPPP) += pc300_tty.o
|
||||
@ -38,10 +37,6 @@ obj-$(CONFIG_CYCLADES_SYNC) += cycx_drv.o cyclomx.o
|
||||
obj-$(CONFIG_LAPBETHER) += lapbether.o
|
||||
obj-$(CONFIG_SBNI) += sbni.o
|
||||
obj-$(CONFIG_PC300) += pc300.o
|
||||
obj-$(CONFIG_HDLC) += hdlc.o
|
||||
ifeq ($(CONFIG_HDLC_PPP),y)
|
||||
obj-$(CONFIG_HDLC) += syncppp.o
|
||||
endif
|
||||
obj-$(CONFIG_N2) += n2.o
|
||||
obj-$(CONFIG_C101) += c101.o
|
||||
obj-$(CONFIG_WANXL) += wanxl.o
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Generic HDLC support routines for Linux
|
||||
*
|
||||
* Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -17,9 +17,9 @@
|
||||
* Use sethdlc utility to set line parameters, protocol and PVCs
|
||||
*
|
||||
* How does it work:
|
||||
* - proto.open(), close(), start(), stop() calls are serialized.
|
||||
* - proto->open(), close(), start(), stop() calls are serialized.
|
||||
* The order is: open, [ start, stop ... ] close ...
|
||||
* - proto.start() and stop() are called with spin_lock_irq held.
|
||||
* - proto->start() and stop() are called with spin_lock_irq held.
|
||||
*/
|
||||
|
||||
#include <linux/module.h>
|
||||
@ -38,10 +38,12 @@
|
||||
#include <linux/hdlc.h>
|
||||
|
||||
|
||||
static const char* version = "HDLC support module revision 1.19";
|
||||
static const char* version = "HDLC support module revision 1.20";
|
||||
|
||||
#undef DEBUG_LINK
|
||||
|
||||
static struct hdlc_proto *first_proto = NULL;
|
||||
|
||||
|
||||
static int hdlc_change_mtu(struct net_device *dev, int new_mtu)
|
||||
{
|
||||
@ -63,11 +65,11 @@ static struct net_device_stats *hdlc_get_stats(struct net_device *dev)
|
||||
static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
struct packet_type *p, struct net_device *orig_dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.netif_rx)
|
||||
return hdlc->proto.netif_rx(skb);
|
||||
struct hdlc_device_desc *desc = dev_to_desc(dev);
|
||||
if (desc->netif_rx)
|
||||
return desc->netif_rx(skb);
|
||||
|
||||
hdlc->stats.rx_dropped++; /* Shouldn't happen */
|
||||
desc->stats.rx_dropped++; /* Shouldn't happen */
|
||||
dev_kfree_skb(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@ -77,8 +79,8 @@ static int hdlc_rcv(struct sk_buff *skb, struct net_device *dev,
|
||||
static inline void hdlc_proto_start(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.start)
|
||||
return hdlc->proto.start(dev);
|
||||
if (hdlc->proto->start)
|
||||
return hdlc->proto->start(dev);
|
||||
}
|
||||
|
||||
|
||||
@ -86,8 +88,8 @@ static inline void hdlc_proto_start(struct net_device *dev)
|
||||
static inline void hdlc_proto_stop(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
if (hdlc->proto.stop)
|
||||
return hdlc->proto.stop(dev);
|
||||
if (hdlc->proto->stop)
|
||||
return hdlc->proto->stop(dev);
|
||||
}
|
||||
|
||||
|
||||
@ -144,15 +146,15 @@ int hdlc_open(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "hdlc_open() carrier %i open %i\n",
|
||||
printk(KERN_DEBUG "%s: hdlc_open() carrier %i open %i\n", dev->name,
|
||||
hdlc->carrier, hdlc->open);
|
||||
#endif
|
||||
|
||||
if (hdlc->proto.id == -1)
|
||||
if (hdlc->proto == NULL)
|
||||
return -ENOSYS; /* no protocol attached */
|
||||
|
||||
if (hdlc->proto.open) {
|
||||
int result = hdlc->proto.open(dev);
|
||||
if (hdlc->proto->open) {
|
||||
int result = hdlc->proto->open(dev);
|
||||
if (result)
|
||||
return result;
|
||||
}
|
||||
@ -178,7 +180,7 @@ void hdlc_close(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "hdlc_close() carrier %i open %i\n",
|
||||
printk(KERN_DEBUG "%s: hdlc_close() carrier %i open %i\n", dev->name,
|
||||
hdlc->carrier, hdlc->open);
|
||||
#endif
|
||||
|
||||
@ -190,68 +192,34 @@ void hdlc_close(struct net_device *dev)
|
||||
|
||||
spin_unlock_irq(&hdlc->state_lock);
|
||||
|
||||
if (hdlc->proto.close)
|
||||
hdlc->proto.close(dev);
|
||||
if (hdlc->proto->close)
|
||||
hdlc->proto->close(dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#ifndef CONFIG_HDLC_RAW
|
||||
#define hdlc_raw_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HDLC_RAW_ETH
|
||||
#define hdlc_raw_eth_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HDLC_PPP
|
||||
#define hdlc_ppp_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HDLC_CISCO
|
||||
#define hdlc_cisco_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HDLC_FR
|
||||
#define hdlc_fr_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
#ifndef CONFIG_HDLC_X25
|
||||
#define hdlc_x25_ioctl(dev, ifr) -ENOSYS
|
||||
#endif
|
||||
|
||||
|
||||
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
unsigned int proto;
|
||||
struct hdlc_proto *proto = first_proto;
|
||||
int result;
|
||||
|
||||
if (cmd != SIOCWANDEV)
|
||||
return -EINVAL;
|
||||
|
||||
switch(ifr->ifr_settings.type) {
|
||||
case IF_PROTO_HDLC:
|
||||
case IF_PROTO_HDLC_ETH:
|
||||
case IF_PROTO_PPP:
|
||||
case IF_PROTO_CISCO:
|
||||
case IF_PROTO_FR:
|
||||
case IF_PROTO_X25:
|
||||
proto = ifr->ifr_settings.type;
|
||||
break;
|
||||
|
||||
default:
|
||||
proto = hdlc->proto.id;
|
||||
if (dev_to_hdlc(dev)->proto) {
|
||||
result = dev_to_hdlc(dev)->proto->ioctl(dev, ifr);
|
||||
if (result != -EINVAL)
|
||||
return result;
|
||||
}
|
||||
|
||||
switch(proto) {
|
||||
case IF_PROTO_HDLC: return hdlc_raw_ioctl(dev, ifr);
|
||||
case IF_PROTO_HDLC_ETH: return hdlc_raw_eth_ioctl(dev, ifr);
|
||||
case IF_PROTO_PPP: return hdlc_ppp_ioctl(dev, ifr);
|
||||
case IF_PROTO_CISCO: return hdlc_cisco_ioctl(dev, ifr);
|
||||
case IF_PROTO_FR: return hdlc_fr_ioctl(dev, ifr);
|
||||
case IF_PROTO_X25: return hdlc_x25_ioctl(dev, ifr);
|
||||
default: return -EINVAL;
|
||||
/* Not handled by currently attached protocol (if any) */
|
||||
|
||||
while (proto) {
|
||||
if ((result = proto->ioctl(dev, ifr)) != -EINVAL)
|
||||
return result;
|
||||
proto = proto->next;
|
||||
}
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
void hdlc_setup(struct net_device *dev)
|
||||
@ -267,8 +235,6 @@ void hdlc_setup(struct net_device *dev)
|
||||
|
||||
dev->flags = IFF_POINTOPOINT | IFF_NOARP;
|
||||
|
||||
hdlc->proto.id = -1;
|
||||
hdlc->proto.detach = NULL;
|
||||
hdlc->carrier = 1;
|
||||
hdlc->open = 0;
|
||||
spin_lock_init(&hdlc->state_lock);
|
||||
@ -277,7 +243,8 @@ void hdlc_setup(struct net_device *dev)
|
||||
struct net_device *alloc_hdlcdev(void *priv)
|
||||
{
|
||||
struct net_device *dev;
|
||||
dev = alloc_netdev(sizeof(hdlc_device), "hdlc%d", hdlc_setup);
|
||||
dev = alloc_netdev(sizeof(struct hdlc_device_desc) +
|
||||
sizeof(hdlc_device), "hdlc%d", hdlc_setup);
|
||||
if (dev)
|
||||
dev_to_hdlc(dev)->priv = priv;
|
||||
return dev;
|
||||
@ -286,13 +253,71 @@ struct net_device *alloc_hdlcdev(void *priv)
|
||||
void unregister_hdlc_device(struct net_device *dev)
|
||||
{
|
||||
rtnl_lock();
|
||||
hdlc_proto_detach(dev_to_hdlc(dev));
|
||||
unregister_netdevice(dev);
|
||||
detach_hdlc_protocol(dev);
|
||||
rtnl_unlock();
|
||||
}
|
||||
|
||||
|
||||
|
||||
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
|
||||
int (*rx)(struct sk_buff *skb), size_t size)
|
||||
{
|
||||
detach_hdlc_protocol(dev);
|
||||
|
||||
if (!try_module_get(proto->module))
|
||||
return -ENOSYS;
|
||||
|
||||
if (size)
|
||||
if ((dev_to_hdlc(dev)->state = kmalloc(size,
|
||||
GFP_KERNEL)) == NULL) {
|
||||
printk(KERN_WARNING "Memory squeeze on"
|
||||
" hdlc_proto_attach()\n");
|
||||
module_put(proto->module);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
dev_to_hdlc(dev)->proto = proto;
|
||||
dev_to_desc(dev)->netif_rx = rx;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void detach_hdlc_protocol(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
|
||||
if (hdlc->proto) {
|
||||
if (hdlc->proto->detach)
|
||||
hdlc->proto->detach(dev);
|
||||
module_put(hdlc->proto->module);
|
||||
hdlc->proto = NULL;
|
||||
}
|
||||
kfree(hdlc->state);
|
||||
hdlc->state = NULL;
|
||||
}
|
||||
|
||||
|
||||
void register_hdlc_protocol(struct hdlc_proto *proto)
|
||||
{
|
||||
proto->next = first_proto;
|
||||
first_proto = proto;
|
||||
}
|
||||
|
||||
|
||||
void unregister_hdlc_protocol(struct hdlc_proto *proto)
|
||||
{
|
||||
struct hdlc_proto **p = &first_proto;
|
||||
while (*p) {
|
||||
if (*p == proto) {
|
||||
*p = proto->next;
|
||||
return;
|
||||
}
|
||||
p = &((*p)->next);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("HDLC support module");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@ -303,6 +328,10 @@ EXPORT_SYMBOL(hdlc_ioctl);
|
||||
EXPORT_SYMBOL(hdlc_setup);
|
||||
EXPORT_SYMBOL(alloc_hdlcdev);
|
||||
EXPORT_SYMBOL(unregister_hdlc_device);
|
||||
EXPORT_SYMBOL(register_hdlc_protocol);
|
||||
EXPORT_SYMBOL(unregister_hdlc_protocol);
|
||||
EXPORT_SYMBOL(attach_hdlc_protocol);
|
||||
EXPORT_SYMBOL(detach_hdlc_protocol);
|
||||
|
||||
static struct packet_type hdlc_packet_type = {
|
||||
.type = __constant_htons(ETH_P_HDLC),
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* Cisco HDLC support
|
||||
*
|
||||
* Copyright (C) 2000 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 2000 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -34,17 +34,56 @@
|
||||
#define CISCO_KEEPALIVE_REQ 2 /* Cisco keepalive request */
|
||||
|
||||
|
||||
struct hdlc_header {
|
||||
u8 address;
|
||||
u8 control;
|
||||
u16 protocol;
|
||||
}__attribute__ ((packed));
|
||||
|
||||
|
||||
struct cisco_packet {
|
||||
u32 type; /* code */
|
||||
u32 par1;
|
||||
u32 par2;
|
||||
u16 rel; /* reliability */
|
||||
u32 time;
|
||||
}__attribute__ ((packed));
|
||||
#define CISCO_PACKET_LEN 18
|
||||
#define CISCO_BIG_PACKET_LEN 20
|
||||
|
||||
|
||||
struct cisco_state {
|
||||
cisco_proto settings;
|
||||
|
||||
struct timer_list timer;
|
||||
unsigned long last_poll;
|
||||
int up;
|
||||
int request_sent;
|
||||
u32 txseq; /* TX sequence number */
|
||||
u32 rxseq; /* RX sequence number */
|
||||
};
|
||||
|
||||
|
||||
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
|
||||
static inline struct cisco_state * state(hdlc_device *hdlc)
|
||||
{
|
||||
return(struct cisco_state *)(hdlc->state);
|
||||
}
|
||||
|
||||
|
||||
static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
u16 type, void *daddr, void *saddr,
|
||||
unsigned int len)
|
||||
{
|
||||
hdlc_header *data;
|
||||
struct hdlc_header *data;
|
||||
#ifdef DEBUG_HARD_HEADER
|
||||
printk(KERN_DEBUG "%s: cisco_hard_header called\n", dev->name);
|
||||
#endif
|
||||
|
||||
skb_push(skb, sizeof(hdlc_header));
|
||||
data = (hdlc_header*)skb->data;
|
||||
skb_push(skb, sizeof(struct hdlc_header));
|
||||
data = (struct hdlc_header*)skb->data;
|
||||
if (type == CISCO_KEEPALIVE)
|
||||
data->address = CISCO_MULTICAST;
|
||||
else
|
||||
@ -52,7 +91,7 @@ static int cisco_hard_header(struct sk_buff *skb, struct net_device *dev,
|
||||
data->control = 0;
|
||||
data->protocol = htons(type);
|
||||
|
||||
return sizeof(hdlc_header);
|
||||
return sizeof(struct hdlc_header);
|
||||
}
|
||||
|
||||
|
||||
@ -61,9 +100,10 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
|
||||
u32 par1, u32 par2)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
cisco_packet *data;
|
||||
struct cisco_packet *data;
|
||||
|
||||
skb = dev_alloc_skb(sizeof(hdlc_header) + sizeof(cisco_packet));
|
||||
skb = dev_alloc_skb(sizeof(struct hdlc_header) +
|
||||
sizeof(struct cisco_packet));
|
||||
if (!skb) {
|
||||
printk(KERN_WARNING
|
||||
"%s: Memory squeeze on cisco_keepalive_send()\n",
|
||||
@ -72,7 +112,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
|
||||
}
|
||||
skb_reserve(skb, 4);
|
||||
cisco_hard_header(skb, dev, CISCO_KEEPALIVE, NULL, NULL, 0);
|
||||
data = (cisco_packet*)(skb->data + 4);
|
||||
data = (struct cisco_packet*)(skb->data + 4);
|
||||
|
||||
data->type = htonl(type);
|
||||
data->par1 = htonl(par1);
|
||||
@ -81,7 +121,7 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
|
||||
/* we will need do_div here if 1000 % HZ != 0 */
|
||||
data->time = htonl((jiffies - INITIAL_JIFFIES) * (1000 / HZ));
|
||||
|
||||
skb_put(skb, sizeof(cisco_packet));
|
||||
skb_put(skb, sizeof(struct cisco_packet));
|
||||
skb->priority = TC_PRIO_CONTROL;
|
||||
skb->dev = dev;
|
||||
skb->nh.raw = skb->data;
|
||||
@ -93,9 +133,9 @@ static void cisco_keepalive_send(struct net_device *dev, u32 type,
|
||||
|
||||
static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
hdlc_header *data = (hdlc_header*)skb->data;
|
||||
struct hdlc_header *data = (struct hdlc_header*)skb->data;
|
||||
|
||||
if (skb->len < sizeof(hdlc_header))
|
||||
if (skb->len < sizeof(struct hdlc_header))
|
||||
return __constant_htons(ETH_P_HDLC);
|
||||
|
||||
if (data->address != CISCO_MULTICAST &&
|
||||
@ -106,7 +146,7 @@ static __be16 cisco_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
case __constant_htons(ETH_P_IP):
|
||||
case __constant_htons(ETH_P_IPX):
|
||||
case __constant_htons(ETH_P_IPV6):
|
||||
skb_pull(skb, sizeof(hdlc_header));
|
||||
skb_pull(skb, sizeof(struct hdlc_header));
|
||||
return data->protocol;
|
||||
default:
|
||||
return __constant_htons(ETH_P_HDLC);
|
||||
@ -118,12 +158,12 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *dev = skb->dev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
hdlc_header *data = (hdlc_header*)skb->data;
|
||||
cisco_packet *cisco_data;
|
||||
struct hdlc_header *data = (struct hdlc_header*)skb->data;
|
||||
struct cisco_packet *cisco_data;
|
||||
struct in_device *in_dev;
|
||||
u32 addr, mask;
|
||||
|
||||
if (skb->len < sizeof(hdlc_header))
|
||||
if (skb->len < sizeof(struct hdlc_header))
|
||||
goto rx_error;
|
||||
|
||||
if (data->address != CISCO_MULTICAST &&
|
||||
@ -137,15 +177,17 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
case CISCO_KEEPALIVE:
|
||||
if (skb->len != sizeof(hdlc_header) + CISCO_PACKET_LEN &&
|
||||
skb->len != sizeof(hdlc_header) + CISCO_BIG_PACKET_LEN) {
|
||||
printk(KERN_INFO "%s: Invalid length of Cisco "
|
||||
"control packet (%d bytes)\n",
|
||||
dev->name, skb->len);
|
||||
if ((skb->len != sizeof(struct hdlc_header) +
|
||||
CISCO_PACKET_LEN) &&
|
||||
(skb->len != sizeof(struct hdlc_header) +
|
||||
CISCO_BIG_PACKET_LEN)) {
|
||||
printk(KERN_INFO "%s: Invalid length of Cisco control"
|
||||
" packet (%d bytes)\n", dev->name, skb->len);
|
||||
goto rx_error;
|
||||
}
|
||||
|
||||
cisco_data = (cisco_packet*)(skb->data + sizeof(hdlc_header));
|
||||
cisco_data = (struct cisco_packet*)(skb->data + sizeof
|
||||
(struct hdlc_header));
|
||||
|
||||
switch(ntohl (cisco_data->type)) {
|
||||
case CISCO_ADDR_REQ: /* Stolen from syncppp.c :-) */
|
||||
@ -178,11 +220,11 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
goto rx_error;
|
||||
|
||||
case CISCO_KEEPALIVE_REQ:
|
||||
hdlc->state.cisco.rxseq = ntohl(cisco_data->par1);
|
||||
if (hdlc->state.cisco.request_sent &&
|
||||
ntohl(cisco_data->par2)==hdlc->state.cisco.txseq) {
|
||||
hdlc->state.cisco.last_poll = jiffies;
|
||||
if (!hdlc->state.cisco.up) {
|
||||
state(hdlc)->rxseq = ntohl(cisco_data->par1);
|
||||
if (state(hdlc)->request_sent &&
|
||||
ntohl(cisco_data->par2) == state(hdlc)->txseq) {
|
||||
state(hdlc)->last_poll = jiffies;
|
||||
if (!state(hdlc)->up) {
|
||||
u32 sec, min, hrs, days;
|
||||
sec = ntohl(cisco_data->time) / 1000;
|
||||
min = sec / 60; sec -= min * 60;
|
||||
@ -193,7 +235,7 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
dev->name, days, hrs,
|
||||
min, sec);
|
||||
netif_dormant_off(dev);
|
||||
hdlc->state.cisco.up = 1;
|
||||
state(hdlc)->up = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -208,7 +250,7 @@ static int cisco_rx(struct sk_buff *skb)
|
||||
return NET_RX_DROP;
|
||||
|
||||
rx_error:
|
||||
hdlc->stats.rx_errors++; /* Mark error */
|
||||
dev_to_desc(dev)->stats.rx_errors++; /* Mark error */
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@ -220,23 +262,22 @@ static void cisco_timer(unsigned long arg)
|
||||
struct net_device *dev = (struct net_device *)arg;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
|
||||
if (hdlc->state.cisco.up &&
|
||||
time_after(jiffies, hdlc->state.cisco.last_poll +
|
||||
hdlc->state.cisco.settings.timeout * HZ)) {
|
||||
hdlc->state.cisco.up = 0;
|
||||
if (state(hdlc)->up &&
|
||||
time_after(jiffies, state(hdlc)->last_poll +
|
||||
state(hdlc)->settings.timeout * HZ)) {
|
||||
state(hdlc)->up = 0;
|
||||
printk(KERN_INFO "%s: Link down\n", dev->name);
|
||||
netif_dormant_on(dev);
|
||||
}
|
||||
|
||||
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ,
|
||||
++hdlc->state.cisco.txseq,
|
||||
hdlc->state.cisco.rxseq);
|
||||
hdlc->state.cisco.request_sent = 1;
|
||||
hdlc->state.cisco.timer.expires = jiffies +
|
||||
hdlc->state.cisco.settings.interval * HZ;
|
||||
hdlc->state.cisco.timer.function = cisco_timer;
|
||||
hdlc->state.cisco.timer.data = arg;
|
||||
add_timer(&hdlc->state.cisco.timer);
|
||||
cisco_keepalive_send(dev, CISCO_KEEPALIVE_REQ, ++state(hdlc)->txseq,
|
||||
state(hdlc)->rxseq);
|
||||
state(hdlc)->request_sent = 1;
|
||||
state(hdlc)->timer.expires = jiffies +
|
||||
state(hdlc)->settings.interval * HZ;
|
||||
state(hdlc)->timer.function = cisco_timer;
|
||||
state(hdlc)->timer.data = arg;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
}
|
||||
|
||||
|
||||
@ -244,15 +285,15 @@ static void cisco_timer(unsigned long arg)
|
||||
static void cisco_start(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
hdlc->state.cisco.up = 0;
|
||||
hdlc->state.cisco.request_sent = 0;
|
||||
hdlc->state.cisco.txseq = hdlc->state.cisco.rxseq = 0;
|
||||
state(hdlc)->up = 0;
|
||||
state(hdlc)->request_sent = 0;
|
||||
state(hdlc)->txseq = state(hdlc)->rxseq = 0;
|
||||
|
||||
init_timer(&hdlc->state.cisco.timer);
|
||||
hdlc->state.cisco.timer.expires = jiffies + HZ; /*First poll after 1s*/
|
||||
hdlc->state.cisco.timer.function = cisco_timer;
|
||||
hdlc->state.cisco.timer.data = (unsigned long)dev;
|
||||
add_timer(&hdlc->state.cisco.timer);
|
||||
init_timer(&state(hdlc)->timer);
|
||||
state(hdlc)->timer.expires = jiffies + HZ; /*First poll after 1s*/
|
||||
state(hdlc)->timer.function = cisco_timer;
|
||||
state(hdlc)->timer.data = (unsigned long)dev;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
}
|
||||
|
||||
|
||||
@ -260,15 +301,24 @@ static void cisco_start(struct net_device *dev)
|
||||
static void cisco_stop(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
del_timer_sync(&hdlc->state.cisco.timer);
|
||||
del_timer_sync(&state(hdlc)->timer);
|
||||
netif_dormant_on(dev);
|
||||
hdlc->state.cisco.up = 0;
|
||||
hdlc->state.cisco.request_sent = 0;
|
||||
state(hdlc)->up = 0;
|
||||
state(hdlc)->request_sent = 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
static struct hdlc_proto proto = {
|
||||
.start = cisco_start,
|
||||
.stop = cisco_stop,
|
||||
.type_trans = cisco_type_trans,
|
||||
.ioctl = cisco_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
cisco_proto __user *cisco_s = ifr->ifr_settings.ifs_ifsu.cisco;
|
||||
const size_t size = sizeof(cisco_proto);
|
||||
@ -278,12 +328,14 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_CISCO;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (copy_to_user(cisco_s, &hdlc->state.cisco.settings, size))
|
||||
if (copy_to_user(cisco_s, &state(hdlc)->settings, size))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
@ -302,19 +354,15 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
return -EINVAL;
|
||||
|
||||
result=hdlc->attach(dev, ENCODING_NRZ,PARITY_CRC16_PR1_CCITT);
|
||||
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.cisco.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
result = attach_hdlc_protocol(dev, &proto, cisco_rx,
|
||||
sizeof(struct cisco_state));
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc->proto.start = cisco_start;
|
||||
hdlc->proto.stop = cisco_stop;
|
||||
hdlc->proto.netif_rx = cisco_rx;
|
||||
hdlc->proto.type_trans = cisco_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_CISCO;
|
||||
memcpy(&state(hdlc)->settings, &new_settings, size);
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = cisco_hard_header;
|
||||
dev->hard_header_cache = NULL;
|
||||
@ -327,3 +375,25 @@ int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("Cisco HDLC protocol support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* Frame Relay support
|
||||
*
|
||||
* Copyright (C) 1999 - 2005 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -52,6 +52,8 @@
|
||||
#undef DEBUG_PKT
|
||||
#undef DEBUG_ECN
|
||||
#undef DEBUG_LINK
|
||||
#undef DEBUG_PROTO
|
||||
#undef DEBUG_PVC
|
||||
|
||||
#define FR_UI 0x03
|
||||
#define FR_PAD 0x00
|
||||
@ -115,13 +117,53 @@ typedef struct {
|
||||
}__attribute__ ((packed)) fr_hdr;
|
||||
|
||||
|
||||
typedef struct pvc_device_struct {
|
||||
struct net_device *frad;
|
||||
struct net_device *main;
|
||||
struct net_device *ether; /* bridged Ethernet interface */
|
||||
struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
|
||||
int dlci;
|
||||
int open_count;
|
||||
|
||||
struct {
|
||||
unsigned int new: 1;
|
||||
unsigned int active: 1;
|
||||
unsigned int exist: 1;
|
||||
unsigned int deleted: 1;
|
||||
unsigned int fecn: 1;
|
||||
unsigned int becn: 1;
|
||||
unsigned int bandwidth; /* Cisco LMI reporting only */
|
||||
}state;
|
||||
}pvc_device;
|
||||
|
||||
|
||||
struct frad_state {
|
||||
fr_proto settings;
|
||||
pvc_device *first_pvc;
|
||||
int dce_pvc_count;
|
||||
|
||||
struct timer_list timer;
|
||||
unsigned long last_poll;
|
||||
int reliable;
|
||||
int dce_changed;
|
||||
int request;
|
||||
int fullrep_sent;
|
||||
u32 last_errors; /* last errors bit list */
|
||||
u8 n391cnt;
|
||||
u8 txseq; /* TX sequence number */
|
||||
u8 rxseq; /* RX sequence number */
|
||||
};
|
||||
|
||||
|
||||
static int fr_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
|
||||
static inline u16 q922_to_dlci(u8 *hdr)
|
||||
{
|
||||
return ((hdr[0] & 0xFC) << 2) | ((hdr[1] & 0xF0) >> 4);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static inline void dlci_to_q922(u8 *hdr, u16 dlci)
|
||||
{
|
||||
hdr[0] = (dlci >> 2) & 0xFC;
|
||||
@ -129,10 +171,21 @@ static inline void dlci_to_q922(u8 *hdr, u16 dlci)
|
||||
}
|
||||
|
||||
|
||||
static inline struct frad_state * state(hdlc_device *hdlc)
|
||||
{
|
||||
return(struct frad_state *)(hdlc->state);
|
||||
}
|
||||
|
||||
|
||||
static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
|
||||
{
|
||||
return dev->priv;
|
||||
}
|
||||
|
||||
|
||||
static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
|
||||
{
|
||||
pvc_device *pvc = hdlc->state.fr.first_pvc;
|
||||
pvc_device *pvc = state(hdlc)->first_pvc;
|
||||
|
||||
while (pvc) {
|
||||
if (pvc->dlci == dlci)
|
||||
@ -146,10 +199,10 @@ static inline pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
|
||||
}
|
||||
|
||||
|
||||
static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
|
||||
static pvc_device* add_pvc(struct net_device *dev, u16 dlci)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pvc_device *pvc, **pvc_p = &hdlc->state.fr.first_pvc;
|
||||
pvc_device *pvc, **pvc_p = &state(hdlc)->first_pvc;
|
||||
|
||||
while (*pvc_p) {
|
||||
if ((*pvc_p)->dlci == dlci)
|
||||
@ -160,12 +213,15 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
|
||||
}
|
||||
|
||||
pvc = kmalloc(sizeof(pvc_device), GFP_ATOMIC);
|
||||
#ifdef DEBUG_PVC
|
||||
printk(KERN_DEBUG "add_pvc: allocated pvc %p, frad %p\n", pvc, dev);
|
||||
#endif
|
||||
if (!pvc)
|
||||
return NULL;
|
||||
|
||||
memset(pvc, 0, sizeof(pvc_device));
|
||||
pvc->dlci = dlci;
|
||||
pvc->master = dev;
|
||||
pvc->frad = dev;
|
||||
pvc->next = *pvc_p; /* Put it in the chain */
|
||||
*pvc_p = pvc;
|
||||
return pvc;
|
||||
@ -174,7 +230,7 @@ static inline pvc_device* add_pvc(struct net_device *dev, u16 dlci)
|
||||
|
||||
static inline int pvc_is_used(pvc_device *pvc)
|
||||
{
|
||||
return pvc->main != NULL || pvc->ether != NULL;
|
||||
return pvc->main || pvc->ether;
|
||||
}
|
||||
|
||||
|
||||
@ -200,11 +256,14 @@ static inline void pvc_carrier(int on, pvc_device *pvc)
|
||||
|
||||
static inline void delete_unused_pvcs(hdlc_device *hdlc)
|
||||
{
|
||||
pvc_device **pvc_p = &hdlc->state.fr.first_pvc;
|
||||
pvc_device **pvc_p = &state(hdlc)->first_pvc;
|
||||
|
||||
while (*pvc_p) {
|
||||
if (!pvc_is_used(*pvc_p)) {
|
||||
pvc_device *pvc = *pvc_p;
|
||||
#ifdef DEBUG_PVC
|
||||
printk(KERN_DEBUG "freeing unused pvc: %p\n", pvc);
|
||||
#endif
|
||||
*pvc_p = pvc->next;
|
||||
kfree(pvc);
|
||||
continue;
|
||||
@ -295,16 +354,16 @@ static int pvc_open(struct net_device *dev)
|
||||
{
|
||||
pvc_device *pvc = dev_to_pvc(dev);
|
||||
|
||||
if ((pvc->master->flags & IFF_UP) == 0)
|
||||
return -EIO; /* Master must be UP in order to activate PVC */
|
||||
if ((pvc->frad->flags & IFF_UP) == 0)
|
||||
return -EIO; /* Frad must be UP in order to activate PVC */
|
||||
|
||||
if (pvc->open_count++ == 0) {
|
||||
hdlc_device *hdlc = dev_to_hdlc(pvc->master);
|
||||
if (hdlc->state.fr.settings.lmi == LMI_NONE)
|
||||
pvc->state.active = netif_carrier_ok(pvc->master);
|
||||
hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
|
||||
if (state(hdlc)->settings.lmi == LMI_NONE)
|
||||
pvc->state.active = netif_carrier_ok(pvc->frad);
|
||||
|
||||
pvc_carrier(pvc->state.active, pvc);
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -316,12 +375,12 @@ static int pvc_close(struct net_device *dev)
|
||||
pvc_device *pvc = dev_to_pvc(dev);
|
||||
|
||||
if (--pvc->open_count == 0) {
|
||||
hdlc_device *hdlc = dev_to_hdlc(pvc->master);
|
||||
if (hdlc->state.fr.settings.lmi == LMI_NONE)
|
||||
hdlc_device *hdlc = dev_to_hdlc(pvc->frad);
|
||||
if (state(hdlc)->settings.lmi == LMI_NONE)
|
||||
pvc->state.active = 0;
|
||||
|
||||
if (hdlc->state.fr.settings.dce) {
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
if (state(hdlc)->settings.dce) {
|
||||
state(hdlc)->dce_changed = 1;
|
||||
pvc->state.active = 0;
|
||||
}
|
||||
}
|
||||
@ -348,7 +407,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
}
|
||||
|
||||
info.dlci = pvc->dlci;
|
||||
memcpy(info.master, pvc->master->name, IFNAMSIZ);
|
||||
memcpy(info.master, pvc->frad->name, IFNAMSIZ);
|
||||
if (copy_to_user(ifr->ifr_settings.ifs_ifsu.fr_pvc_info,
|
||||
&info, sizeof(info)))
|
||||
return -EFAULT;
|
||||
@ -361,7 +420,7 @@ static int pvc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
|
||||
static inline struct net_device_stats *pvc_get_stats(struct net_device *dev)
|
||||
{
|
||||
return netdev_priv(dev);
|
||||
return &dev_to_desc(dev)->stats;
|
||||
}
|
||||
|
||||
|
||||
@ -393,7 +452,7 @@ static int pvc_xmit(struct sk_buff *skb, struct net_device *dev)
|
||||
stats->tx_packets++;
|
||||
if (pvc->state.fecn) /* TX Congestion counter */
|
||||
stats->tx_compressed++;
|
||||
skb->dev = pvc->master;
|
||||
skb->dev = pvc->frad;
|
||||
dev_queue_xmit(skb);
|
||||
return 0;
|
||||
}
|
||||
@ -419,7 +478,7 @@ static int pvc_change_mtu(struct net_device *dev, int new_mtu)
|
||||
static inline void fr_log_dlci_active(pvc_device *pvc)
|
||||
{
|
||||
printk(KERN_INFO "%s: DLCI %d [%s%s%s]%s %s\n",
|
||||
pvc->master->name,
|
||||
pvc->frad->name,
|
||||
pvc->dlci,
|
||||
pvc->main ? pvc->main->name : "",
|
||||
pvc->main && pvc->ether ? " " : "",
|
||||
@ -438,21 +497,20 @@ static inline u8 fr_lmi_nextseq(u8 x)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fr_lmi_send(struct net_device *dev, int fullrep)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
struct sk_buff *skb;
|
||||
pvc_device *pvc = hdlc->state.fr.first_pvc;
|
||||
int lmi = hdlc->state.fr.settings.lmi;
|
||||
int dce = hdlc->state.fr.settings.dce;
|
||||
pvc_device *pvc = state(hdlc)->first_pvc;
|
||||
int lmi = state(hdlc)->settings.lmi;
|
||||
int dce = state(hdlc)->settings.dce;
|
||||
int len = lmi == LMI_ANSI ? LMI_ANSI_LENGTH : LMI_CCITT_CISCO_LENGTH;
|
||||
int stat_len = (lmi == LMI_CISCO) ? 6 : 3;
|
||||
u8 *data;
|
||||
int i = 0;
|
||||
|
||||
if (dce && fullrep) {
|
||||
len += hdlc->state.fr.dce_pvc_count * (2 + stat_len);
|
||||
len += state(hdlc)->dce_pvc_count * (2 + stat_len);
|
||||
if (len > HDLC_MAX_MRU) {
|
||||
printk(KERN_WARNING "%s: Too many PVCs while sending "
|
||||
"LMI full report\n", dev->name);
|
||||
@ -486,8 +544,9 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
|
||||
data[i++] = fullrep ? LMI_FULLREP : LMI_INTEGRITY;
|
||||
data[i++] = lmi == LMI_CCITT ? LMI_CCITT_ALIVE : LMI_ANSI_CISCO_ALIVE;
|
||||
data[i++] = LMI_INTEG_LEN;
|
||||
data[i++] = hdlc->state.fr.txseq =fr_lmi_nextseq(hdlc->state.fr.txseq);
|
||||
data[i++] = hdlc->state.fr.rxseq;
|
||||
data[i++] = state(hdlc)->txseq =
|
||||
fr_lmi_nextseq(state(hdlc)->txseq);
|
||||
data[i++] = state(hdlc)->rxseq;
|
||||
|
||||
if (dce && fullrep) {
|
||||
while (pvc) {
|
||||
@ -496,7 +555,7 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
|
||||
data[i++] = stat_len;
|
||||
|
||||
/* LMI start/restart */
|
||||
if (hdlc->state.fr.reliable && !pvc->state.exist) {
|
||||
if (state(hdlc)->reliable && !pvc->state.exist) {
|
||||
pvc->state.exist = pvc->state.new = 1;
|
||||
fr_log_dlci_active(pvc);
|
||||
}
|
||||
@ -541,15 +600,15 @@ static void fr_lmi_send(struct net_device *dev, int fullrep)
|
||||
static void fr_set_link_state(int reliable, struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pvc_device *pvc = hdlc->state.fr.first_pvc;
|
||||
pvc_device *pvc = state(hdlc)->first_pvc;
|
||||
|
||||
hdlc->state.fr.reliable = reliable;
|
||||
state(hdlc)->reliable = reliable;
|
||||
if (reliable) {
|
||||
netif_dormant_off(dev);
|
||||
hdlc->state.fr.n391cnt = 0; /* Request full status */
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
state(hdlc)->n391cnt = 0; /* Request full status */
|
||||
state(hdlc)->dce_changed = 1;
|
||||
|
||||
if (hdlc->state.fr.settings.lmi == LMI_NONE) {
|
||||
if (state(hdlc)->settings.lmi == LMI_NONE) {
|
||||
while (pvc) { /* Activate all PVCs */
|
||||
pvc_carrier(1, pvc);
|
||||
pvc->state.exist = pvc->state.active = 1;
|
||||
@ -563,7 +622,7 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
|
||||
pvc_carrier(0, pvc);
|
||||
pvc->state.exist = pvc->state.active = 0;
|
||||
pvc->state.new = 0;
|
||||
if (!hdlc->state.fr.settings.dce)
|
||||
if (!state(hdlc)->settings.dce)
|
||||
pvc->state.bandwidth = 0;
|
||||
pvc = pvc->next;
|
||||
}
|
||||
@ -571,7 +630,6 @@ static void fr_set_link_state(int reliable, struct net_device *dev)
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fr_timer(unsigned long arg)
|
||||
{
|
||||
struct net_device *dev = (struct net_device *)arg;
|
||||
@ -579,62 +637,61 @@ static void fr_timer(unsigned long arg)
|
||||
int i, cnt = 0, reliable;
|
||||
u32 list;
|
||||
|
||||
if (hdlc->state.fr.settings.dce) {
|
||||
reliable = hdlc->state.fr.request &&
|
||||
time_before(jiffies, hdlc->state.fr.last_poll +
|
||||
hdlc->state.fr.settings.t392 * HZ);
|
||||
hdlc->state.fr.request = 0;
|
||||
if (state(hdlc)->settings.dce) {
|
||||
reliable = state(hdlc)->request &&
|
||||
time_before(jiffies, state(hdlc)->last_poll +
|
||||
state(hdlc)->settings.t392 * HZ);
|
||||
state(hdlc)->request = 0;
|
||||
} else {
|
||||
hdlc->state.fr.last_errors <<= 1; /* Shift the list */
|
||||
if (hdlc->state.fr.request) {
|
||||
if (hdlc->state.fr.reliable)
|
||||
state(hdlc)->last_errors <<= 1; /* Shift the list */
|
||||
if (state(hdlc)->request) {
|
||||
if (state(hdlc)->reliable)
|
||||
printk(KERN_INFO "%s: No LMI status reply "
|
||||
"received\n", dev->name);
|
||||
hdlc->state.fr.last_errors |= 1;
|
||||
state(hdlc)->last_errors |= 1;
|
||||
}
|
||||
|
||||
list = hdlc->state.fr.last_errors;
|
||||
for (i = 0; i < hdlc->state.fr.settings.n393; i++, list >>= 1)
|
||||
list = state(hdlc)->last_errors;
|
||||
for (i = 0; i < state(hdlc)->settings.n393; i++, list >>= 1)
|
||||
cnt += (list & 1); /* errors count */
|
||||
|
||||
reliable = (cnt < hdlc->state.fr.settings.n392);
|
||||
reliable = (cnt < state(hdlc)->settings.n392);
|
||||
}
|
||||
|
||||
if (hdlc->state.fr.reliable != reliable) {
|
||||
if (state(hdlc)->reliable != reliable) {
|
||||
printk(KERN_INFO "%s: Link %sreliable\n", dev->name,
|
||||
reliable ? "" : "un");
|
||||
fr_set_link_state(reliable, dev);
|
||||
}
|
||||
|
||||
if (hdlc->state.fr.settings.dce)
|
||||
hdlc->state.fr.timer.expires = jiffies +
|
||||
hdlc->state.fr.settings.t392 * HZ;
|
||||
if (state(hdlc)->settings.dce)
|
||||
state(hdlc)->timer.expires = jiffies +
|
||||
state(hdlc)->settings.t392 * HZ;
|
||||
else {
|
||||
if (hdlc->state.fr.n391cnt)
|
||||
hdlc->state.fr.n391cnt--;
|
||||
if (state(hdlc)->n391cnt)
|
||||
state(hdlc)->n391cnt--;
|
||||
|
||||
fr_lmi_send(dev, hdlc->state.fr.n391cnt == 0);
|
||||
fr_lmi_send(dev, state(hdlc)->n391cnt == 0);
|
||||
|
||||
hdlc->state.fr.last_poll = jiffies;
|
||||
hdlc->state.fr.request = 1;
|
||||
hdlc->state.fr.timer.expires = jiffies +
|
||||
hdlc->state.fr.settings.t391 * HZ;
|
||||
state(hdlc)->last_poll = jiffies;
|
||||
state(hdlc)->request = 1;
|
||||
state(hdlc)->timer.expires = jiffies +
|
||||
state(hdlc)->settings.t391 * HZ;
|
||||
}
|
||||
|
||||
hdlc->state.fr.timer.function = fr_timer;
|
||||
hdlc->state.fr.timer.data = arg;
|
||||
add_timer(&hdlc->state.fr.timer);
|
||||
state(hdlc)->timer.function = fr_timer;
|
||||
state(hdlc)->timer.data = arg;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pvc_device *pvc;
|
||||
u8 rxseq, txseq;
|
||||
int lmi = hdlc->state.fr.settings.lmi;
|
||||
int dce = hdlc->state.fr.settings.dce;
|
||||
int lmi = state(hdlc)->settings.lmi;
|
||||
int dce = state(hdlc)->settings.dce;
|
||||
int stat_len = (lmi == LMI_CISCO) ? 6 : 3, reptype, error, no_ram, i;
|
||||
|
||||
if (skb->len < (lmi == LMI_ANSI ? LMI_ANSI_LENGTH :
|
||||
@ -645,8 +702,8 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
|
||||
if (skb->data[3] != (lmi == LMI_CISCO ? NLPID_CISCO_LMI :
|
||||
NLPID_CCITT_ANSI_LMI)) {
|
||||
printk(KERN_INFO "%s: Received non-LMI frame with LMI"
|
||||
" DLCI\n", dev->name);
|
||||
printk(KERN_INFO "%s: Received non-LMI frame with LMI DLCI\n",
|
||||
dev->name);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -706,53 +763,53 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
}
|
||||
i++;
|
||||
|
||||
hdlc->state.fr.rxseq = skb->data[i++]; /* TX sequence from peer */
|
||||
state(hdlc)->rxseq = skb->data[i++]; /* TX sequence from peer */
|
||||
rxseq = skb->data[i++]; /* Should confirm our sequence */
|
||||
|
||||
txseq = hdlc->state.fr.txseq;
|
||||
txseq = state(hdlc)->txseq;
|
||||
|
||||
if (dce)
|
||||
hdlc->state.fr.last_poll = jiffies;
|
||||
state(hdlc)->last_poll = jiffies;
|
||||
|
||||
error = 0;
|
||||
if (!hdlc->state.fr.reliable)
|
||||
if (!state(hdlc)->reliable)
|
||||
error = 1;
|
||||
|
||||
if (rxseq == 0 || rxseq != txseq) {
|
||||
hdlc->state.fr.n391cnt = 0; /* Ask for full report next time */
|
||||
if (rxseq == 0 || rxseq != txseq) { /* Ask for full report next time */
|
||||
state(hdlc)->n391cnt = 0;
|
||||
error = 1;
|
||||
}
|
||||
|
||||
if (dce) {
|
||||
if (hdlc->state.fr.fullrep_sent && !error) {
|
||||
if (state(hdlc)->fullrep_sent && !error) {
|
||||
/* Stop sending full report - the last one has been confirmed by DTE */
|
||||
hdlc->state.fr.fullrep_sent = 0;
|
||||
pvc = hdlc->state.fr.first_pvc;
|
||||
state(hdlc)->fullrep_sent = 0;
|
||||
pvc = state(hdlc)->first_pvc;
|
||||
while (pvc) {
|
||||
if (pvc->state.new) {
|
||||
pvc->state.new = 0;
|
||||
|
||||
/* Tell DTE that new PVC is now active */
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
}
|
||||
pvc = pvc->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (hdlc->state.fr.dce_changed) {
|
||||
if (state(hdlc)->dce_changed) {
|
||||
reptype = LMI_FULLREP;
|
||||
hdlc->state.fr.fullrep_sent = 1;
|
||||
hdlc->state.fr.dce_changed = 0;
|
||||
state(hdlc)->fullrep_sent = 1;
|
||||
state(hdlc)->dce_changed = 0;
|
||||
}
|
||||
|
||||
hdlc->state.fr.request = 1; /* got request */
|
||||
state(hdlc)->request = 1; /* got request */
|
||||
fr_lmi_send(dev, reptype == LMI_FULLREP ? 1 : 0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* DTE */
|
||||
|
||||
hdlc->state.fr.request = 0; /* got response, no request pending */
|
||||
state(hdlc)->request = 0; /* got response, no request pending */
|
||||
|
||||
if (error)
|
||||
return 0;
|
||||
@ -760,7 +817,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
if (reptype != LMI_FULLREP)
|
||||
return 0;
|
||||
|
||||
pvc = hdlc->state.fr.first_pvc;
|
||||
pvc = state(hdlc)->first_pvc;
|
||||
|
||||
while (pvc) {
|
||||
pvc->state.deleted = 1;
|
||||
@ -827,7 +884,7 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
i += stat_len;
|
||||
}
|
||||
|
||||
pvc = hdlc->state.fr.first_pvc;
|
||||
pvc = state(hdlc)->first_pvc;
|
||||
|
||||
while (pvc) {
|
||||
if (pvc->state.deleted && pvc->state.exist) {
|
||||
@ -841,17 +898,16 @@ static int fr_lmi_recv(struct net_device *dev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* Next full report after N391 polls */
|
||||
hdlc->state.fr.n391cnt = hdlc->state.fr.settings.n391;
|
||||
state(hdlc)->n391cnt = state(hdlc)->settings.n391;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int fr_rx(struct sk_buff *skb)
|
||||
{
|
||||
struct net_device *ndev = skb->dev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(ndev);
|
||||
struct net_device *frad = skb->dev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(frad);
|
||||
fr_hdr *fh = (fr_hdr*)skb->data;
|
||||
u8 *data = skb->data;
|
||||
u16 dlci;
|
||||
@ -864,11 +920,11 @@ static int fr_rx(struct sk_buff *skb)
|
||||
dlci = q922_to_dlci(skb->data);
|
||||
|
||||
if ((dlci == LMI_CCITT_ANSI_DLCI &&
|
||||
(hdlc->state.fr.settings.lmi == LMI_ANSI ||
|
||||
hdlc->state.fr.settings.lmi == LMI_CCITT)) ||
|
||||
(state(hdlc)->settings.lmi == LMI_ANSI ||
|
||||
state(hdlc)->settings.lmi == LMI_CCITT)) ||
|
||||
(dlci == LMI_CISCO_DLCI &&
|
||||
hdlc->state.fr.settings.lmi == LMI_CISCO)) {
|
||||
if (fr_lmi_recv(ndev, skb))
|
||||
state(hdlc)->settings.lmi == LMI_CISCO)) {
|
||||
if (fr_lmi_recv(frad, skb))
|
||||
goto rx_error;
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_SUCCESS;
|
||||
@ -878,7 +934,7 @@ static int fr_rx(struct sk_buff *skb)
|
||||
if (!pvc) {
|
||||
#ifdef DEBUG_PKT
|
||||
printk(KERN_INFO "%s: No PVC for received frame's DLCI %d\n",
|
||||
ndev->name, dlci);
|
||||
frad->name, dlci);
|
||||
#endif
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
@ -886,7 +942,7 @@ static int fr_rx(struct sk_buff *skb)
|
||||
|
||||
if (pvc->state.fecn != fh->fecn) {
|
||||
#ifdef DEBUG_ECN
|
||||
printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", ndev->name,
|
||||
printk(KERN_DEBUG "%s: DLCI %d FECN O%s\n", frad->name,
|
||||
dlci, fh->fecn ? "N" : "FF");
|
||||
#endif
|
||||
pvc->state.fecn ^= 1;
|
||||
@ -894,7 +950,7 @@ static int fr_rx(struct sk_buff *skb)
|
||||
|
||||
if (pvc->state.becn != fh->becn) {
|
||||
#ifdef DEBUG_ECN
|
||||
printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", ndev->name,
|
||||
printk(KERN_DEBUG "%s: DLCI %d BECN O%s\n", frad->name,
|
||||
dlci, fh->becn ? "N" : "FF");
|
||||
#endif
|
||||
pvc->state.becn ^= 1;
|
||||
@ -902,7 +958,7 @@ static int fr_rx(struct sk_buff *skb)
|
||||
|
||||
|
||||
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
|
||||
hdlc->stats.rx_dropped++;
|
||||
dev_to_desc(frad)->stats.rx_dropped++;
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
@ -938,13 +994,13 @@ static int fr_rx(struct sk_buff *skb)
|
||||
|
||||
default:
|
||||
printk(KERN_INFO "%s: Unsupported protocol, OUI=%x "
|
||||
"PID=%x\n", ndev->name, oui, pid);
|
||||
"PID=%x\n", frad->name, oui, pid);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
} else {
|
||||
printk(KERN_INFO "%s: Unsupported protocol, NLPID=%x "
|
||||
"length = %i\n", ndev->name, data[3], skb->len);
|
||||
"length = %i\n", frad->name, data[3], skb->len);
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@ -964,7 +1020,7 @@ static int fr_rx(struct sk_buff *skb)
|
||||
}
|
||||
|
||||
rx_error:
|
||||
hdlc->stats.rx_errors++; /* Mark error */
|
||||
dev_to_desc(frad)->stats.rx_errors++; /* Mark error */
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
@ -977,44 +1033,42 @@ static void fr_start(struct net_device *dev)
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "fr_start\n");
|
||||
#endif
|
||||
if (hdlc->state.fr.settings.lmi != LMI_NONE) {
|
||||
hdlc->state.fr.reliable = 0;
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
hdlc->state.fr.request = 0;
|
||||
hdlc->state.fr.fullrep_sent = 0;
|
||||
hdlc->state.fr.last_errors = 0xFFFFFFFF;
|
||||
hdlc->state.fr.n391cnt = 0;
|
||||
hdlc->state.fr.txseq = hdlc->state.fr.rxseq = 0;
|
||||
if (state(hdlc)->settings.lmi != LMI_NONE) {
|
||||
state(hdlc)->reliable = 0;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
state(hdlc)->request = 0;
|
||||
state(hdlc)->fullrep_sent = 0;
|
||||
state(hdlc)->last_errors = 0xFFFFFFFF;
|
||||
state(hdlc)->n391cnt = 0;
|
||||
state(hdlc)->txseq = state(hdlc)->rxseq = 0;
|
||||
|
||||
init_timer(&hdlc->state.fr.timer);
|
||||
init_timer(&state(hdlc)->timer);
|
||||
/* First poll after 1 s */
|
||||
hdlc->state.fr.timer.expires = jiffies + HZ;
|
||||
hdlc->state.fr.timer.function = fr_timer;
|
||||
hdlc->state.fr.timer.data = (unsigned long)dev;
|
||||
add_timer(&hdlc->state.fr.timer);
|
||||
state(hdlc)->timer.expires = jiffies + HZ;
|
||||
state(hdlc)->timer.function = fr_timer;
|
||||
state(hdlc)->timer.data = (unsigned long)dev;
|
||||
add_timer(&state(hdlc)->timer);
|
||||
} else
|
||||
fr_set_link_state(1, dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fr_stop(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
#ifdef DEBUG_LINK
|
||||
printk(KERN_DEBUG "fr_stop\n");
|
||||
#endif
|
||||
if (hdlc->state.fr.settings.lmi != LMI_NONE)
|
||||
del_timer_sync(&hdlc->state.fr.timer);
|
||||
if (state(hdlc)->settings.lmi != LMI_NONE)
|
||||
del_timer_sync(&state(hdlc)->timer);
|
||||
fr_set_link_state(0, dev);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void fr_close(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pvc_device *pvc = hdlc->state.fr.first_pvc;
|
||||
pvc_device *pvc = state(hdlc)->first_pvc;
|
||||
|
||||
while (pvc) { /* Shutdown all PVCs for this FRAD */
|
||||
if (pvc->main)
|
||||
@ -1025,7 +1079,8 @@ static void fr_close(struct net_device *dev)
|
||||
}
|
||||
}
|
||||
|
||||
static void dlci_setup(struct net_device *dev)
|
||||
|
||||
static void pvc_setup(struct net_device *dev)
|
||||
{
|
||||
dev->type = ARPHRD_DLCI;
|
||||
dev->flags = IFF_POINTOPOINT;
|
||||
@ -1033,9 +1088,9 @@ static void dlci_setup(struct net_device *dev)
|
||||
dev->addr_len = 2;
|
||||
}
|
||||
|
||||
static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
|
||||
static int fr_add_pvc(struct net_device *frad, unsigned int dlci, int type)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(master);
|
||||
hdlc_device *hdlc = dev_to_hdlc(frad);
|
||||
pvc_device *pvc = NULL;
|
||||
struct net_device *dev;
|
||||
int result, used;
|
||||
@ -1044,9 +1099,9 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
|
||||
if (type == ARPHRD_ETHER)
|
||||
prefix = "pvceth%d";
|
||||
|
||||
if ((pvc = add_pvc(master, dlci)) == NULL) {
|
||||
if ((pvc = add_pvc(frad, dlci)) == NULL) {
|
||||
printk(KERN_WARNING "%s: Memory squeeze on fr_add_pvc()\n",
|
||||
master->name);
|
||||
frad->name);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
|
||||
@ -1060,11 +1115,11 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
|
||||
"pvceth%d", ether_setup);
|
||||
else
|
||||
dev = alloc_netdev(sizeof(struct net_device_stats),
|
||||
"pvc%d", dlci_setup);
|
||||
"pvc%d", pvc_setup);
|
||||
|
||||
if (!dev) {
|
||||
printk(KERN_WARNING "%s: Memory squeeze on fr_pvc()\n",
|
||||
master->name);
|
||||
frad->name);
|
||||
delete_unused_pvcs(hdlc);
|
||||
return -ENOBUFS;
|
||||
}
|
||||
@ -1102,8 +1157,8 @@ static int fr_add_pvc(struct net_device *master, unsigned int dlci, int type)
|
||||
dev->destructor = free_netdev;
|
||||
*get_dev_p(pvc, type) = dev;
|
||||
if (!used) {
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
hdlc->state.fr.dce_pvc_count++;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
state(hdlc)->dce_pvc_count++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -1128,8 +1183,8 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
|
||||
*get_dev_p(pvc, type) = NULL;
|
||||
|
||||
if (!pvc_is_used(pvc)) {
|
||||
hdlc->state.fr.dce_pvc_count--;
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
state(hdlc)->dce_pvc_count--;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
}
|
||||
delete_unused_pvcs(hdlc);
|
||||
return 0;
|
||||
@ -1137,14 +1192,13 @@ static int fr_del_pvc(hdlc_device *hdlc, unsigned int dlci, int type)
|
||||
|
||||
|
||||
|
||||
static void fr_destroy(hdlc_device *hdlc)
|
||||
static void fr_destroy(struct net_device *frad)
|
||||
{
|
||||
pvc_device *pvc;
|
||||
|
||||
pvc = hdlc->state.fr.first_pvc;
|
||||
hdlc->state.fr.first_pvc = NULL; /* All PVCs destroyed */
|
||||
hdlc->state.fr.dce_pvc_count = 0;
|
||||
hdlc->state.fr.dce_changed = 1;
|
||||
hdlc_device *hdlc = dev_to_hdlc(frad);
|
||||
pvc_device *pvc = state(hdlc)->first_pvc;
|
||||
state(hdlc)->first_pvc = NULL; /* All PVCs destroyed */
|
||||
state(hdlc)->dce_pvc_count = 0;
|
||||
state(hdlc)->dce_changed = 1;
|
||||
|
||||
while (pvc) {
|
||||
pvc_device *next = pvc->next;
|
||||
@ -1161,8 +1215,17 @@ static void fr_destroy(hdlc_device *hdlc)
|
||||
}
|
||||
|
||||
|
||||
static struct hdlc_proto proto = {
|
||||
.close = fr_close,
|
||||
.start = fr_start,
|
||||
.stop = fr_stop,
|
||||
.detach = fr_destroy,
|
||||
.ioctl = fr_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
static int fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
fr_proto __user *fr_s = ifr->ifr_settings.ifs_ifsu.fr;
|
||||
const size_t size = sizeof(fr_proto);
|
||||
@ -1173,12 +1236,14 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_FR;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (copy_to_user(fr_s, &hdlc->state.fr.settings, size))
|
||||
if (copy_to_user(fr_s, &state(hdlc)->settings, size))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
@ -1213,20 +1278,16 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
if (hdlc->proto.id != IF_PROTO_FR) {
|
||||
hdlc_proto_detach(hdlc);
|
||||
hdlc->state.fr.first_pvc = NULL;
|
||||
hdlc->state.fr.dce_pvc_count = 0;
|
||||
if (dev_to_hdlc(dev)->proto != &proto) { /* Different proto */
|
||||
result = attach_hdlc_protocol(dev, &proto, fr_rx,
|
||||
sizeof(struct frad_state));
|
||||
if (result)
|
||||
return result;
|
||||
state(hdlc)->first_pvc = NULL;
|
||||
state(hdlc)->dce_pvc_count = 0;
|
||||
}
|
||||
memcpy(&hdlc->state.fr.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
memcpy(&state(hdlc)->settings, &new_settings, size);
|
||||
|
||||
hdlc->proto.close = fr_close;
|
||||
hdlc->proto.start = fr_start;
|
||||
hdlc->proto.stop = fr_stop;
|
||||
hdlc->proto.detach = fr_destroy;
|
||||
hdlc->proto.netif_rx = fr_rx;
|
||||
hdlc->proto.id = IF_PROTO_FR;
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_FRAD;
|
||||
@ -1238,6 +1299,9 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
case IF_PROTO_FR_DEL_PVC:
|
||||
case IF_PROTO_FR_ADD_ETH_PVC:
|
||||
case IF_PROTO_FR_DEL_ETH_PVC:
|
||||
if (dev_to_hdlc(dev)->proto != &proto) /* Different proto */
|
||||
return -EINVAL;
|
||||
|
||||
if(!capable(CAP_NET_ADMIN))
|
||||
return -EPERM;
|
||||
|
||||
@ -1263,3 +1327,24 @@ int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("Frame-Relay protocol support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* Point-to-point protocol support
|
||||
*
|
||||
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -22,6 +22,21 @@
|
||||
#include <linux/lapb.h>
|
||||
#include <linux/rtnetlink.h>
|
||||
#include <linux/hdlc.h>
|
||||
#include <net/syncppp.h>
|
||||
|
||||
struct ppp_state {
|
||||
struct ppp_device pppdev;
|
||||
struct ppp_device *syncppp_ptr;
|
||||
int (*old_change_mtu)(struct net_device *dev, int new_mtu);
|
||||
};
|
||||
|
||||
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
|
||||
static inline struct ppp_state* state(hdlc_device *hdlc)
|
||||
{
|
||||
return(struct ppp_state *)(hdlc->state);
|
||||
}
|
||||
|
||||
|
||||
static int ppp_open(struct net_device *dev)
|
||||
@ -30,16 +45,16 @@ static int ppp_open(struct net_device *dev)
|
||||
void *old_ioctl;
|
||||
int result;
|
||||
|
||||
dev->priv = &hdlc->state.ppp.syncppp_ptr;
|
||||
hdlc->state.ppp.syncppp_ptr = &hdlc->state.ppp.pppdev;
|
||||
hdlc->state.ppp.pppdev.dev = dev;
|
||||
dev->priv = &state(hdlc)->syncppp_ptr;
|
||||
state(hdlc)->syncppp_ptr = &state(hdlc)->pppdev;
|
||||
state(hdlc)->pppdev.dev = dev;
|
||||
|
||||
old_ioctl = dev->do_ioctl;
|
||||
hdlc->state.ppp.old_change_mtu = dev->change_mtu;
|
||||
sppp_attach(&hdlc->state.ppp.pppdev);
|
||||
state(hdlc)->old_change_mtu = dev->change_mtu;
|
||||
sppp_attach(&state(hdlc)->pppdev);
|
||||
/* sppp_attach nukes them. We don't need syncppp's ioctl */
|
||||
dev->do_ioctl = old_ioctl;
|
||||
hdlc->state.ppp.pppdev.sppp.pp_flags &= ~PP_CISCO;
|
||||
state(hdlc)->pppdev.sppp.pp_flags &= ~PP_CISCO;
|
||||
dev->type = ARPHRD_PPP;
|
||||
result = sppp_open(dev);
|
||||
if (result) {
|
||||
@ -59,7 +74,7 @@ static void ppp_close(struct net_device *dev)
|
||||
sppp_close(dev);
|
||||
sppp_detach(dev);
|
||||
dev->rebuild_header = NULL;
|
||||
dev->change_mtu = hdlc->state.ppp.old_change_mtu;
|
||||
dev->change_mtu = state(hdlc)->old_change_mtu;
|
||||
dev->mtu = HDLC_MAX_MTU;
|
||||
dev->hard_header_len = 16;
|
||||
}
|
||||
@ -73,13 +88,24 @@ static __be16 ppp_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
|
||||
|
||||
int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
static struct hdlc_proto proto = {
|
||||
.open = ppp_open,
|
||||
.close = ppp_close,
|
||||
.type_trans = ppp_type_trans,
|
||||
.ioctl = ppp_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
int result;
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_PPP;
|
||||
return 0; /* return protocol only, no settable parameters */
|
||||
|
||||
@ -96,13 +122,10 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.open = ppp_open;
|
||||
hdlc->proto.close = ppp_close;
|
||||
hdlc->proto.type_trans = ppp_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_PPP;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(struct ppp_state));
|
||||
if (result)
|
||||
return result;
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_PPP;
|
||||
@ -113,3 +136,25 @@ int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("PPP protocol support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* HDLC support
|
||||
*
|
||||
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -24,6 +24,8 @@
|
||||
#include <linux/hdlc.h>
|
||||
|
||||
|
||||
static int raw_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
return __constant_htons(ETH_P_IP);
|
||||
@ -31,7 +33,14 @@ static __be16 raw_type_trans(struct sk_buff *skb, struct net_device *dev)
|
||||
|
||||
|
||||
|
||||
int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
static struct hdlc_proto proto = {
|
||||
.type_trans = raw_type_trans,
|
||||
.ioctl = raw_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
|
||||
const size_t size = sizeof(raw_hdlc_proto);
|
||||
@ -41,12 +50,14 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_HDLC;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
|
||||
if (copy_to_user(raw_s, hdlc->state, size))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
@ -71,12 +82,11 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.type_trans = raw_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_HDLC;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(raw_hdlc_proto));
|
||||
if (result)
|
||||
return result;
|
||||
memcpy(hdlc->state, &new_settings, size);
|
||||
dev->hard_start_xmit = hdlc->xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_RAWHDLC;
|
||||
@ -88,3 +98,25 @@ int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("Raw HDLC protocol support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* HDLC Ethernet emulation support
|
||||
*
|
||||
* Copyright (C) 2002-2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 2002-2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -25,6 +25,7 @@
|
||||
#include <linux/etherdevice.h>
|
||||
#include <linux/hdlc.h>
|
||||
|
||||
static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
static int eth_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
{
|
||||
@ -44,7 +45,14 @@ static int eth_tx(struct sk_buff *skb, struct net_device *dev)
|
||||
}
|
||||
|
||||
|
||||
int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
static struct hdlc_proto proto = {
|
||||
.type_trans = eth_type_trans,
|
||||
.ioctl = raw_eth_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
|
||||
static int raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
raw_hdlc_proto __user *raw_s = ifr->ifr_settings.ifs_ifsu.raw_hdlc;
|
||||
const size_t size = sizeof(raw_hdlc_proto);
|
||||
@ -56,12 +64,14 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_HDLC_ETH;
|
||||
if (ifr->ifr_settings.size < size) {
|
||||
ifr->ifr_settings.size = size; /* data size wanted */
|
||||
return -ENOBUFS;
|
||||
}
|
||||
if (copy_to_user(raw_s, &hdlc->state.raw_hdlc.settings, size))
|
||||
if (copy_to_user(raw_s, hdlc->state, size))
|
||||
return -EFAULT;
|
||||
return 0;
|
||||
|
||||
@ -86,12 +96,11 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memcpy(&hdlc->state.raw_hdlc.settings, &new_settings, size);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.type_trans = eth_type_trans;
|
||||
hdlc->proto.id = IF_PROTO_HDLC_ETH;
|
||||
result = attach_hdlc_protocol(dev, &proto, NULL,
|
||||
sizeof(raw_hdlc_proto));
|
||||
if (result)
|
||||
return result;
|
||||
memcpy(hdlc->state, &new_settings, size);
|
||||
dev->hard_start_xmit = eth_tx;
|
||||
old_ch_mtu = dev->change_mtu;
|
||||
old_qlen = dev->tx_queue_len;
|
||||
@ -106,3 +115,25 @@ int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("Ethernet encapsulation support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -2,7 +2,7 @@
|
||||
* Generic HDLC support routines for Linux
|
||||
* X.25 support
|
||||
*
|
||||
* Copyright (C) 1999 - 2003 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
* Copyright (C) 1999 - 2006 Krzysztof Halasa <khc@pm.waw.pl>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms of version 2 of the GNU General Public License
|
||||
@ -25,6 +25,8 @@
|
||||
|
||||
#include <net/x25device.h>
|
||||
|
||||
static int x25_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
/* These functions are callbacks called by LAPB layer */
|
||||
|
||||
static void x25_connect_disconnect(struct net_device *dev, int reason, int code)
|
||||
@ -162,30 +164,39 @@ static void x25_close(struct net_device *dev)
|
||||
|
||||
static int x25_rx(struct sk_buff *skb)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(skb->dev);
|
||||
struct hdlc_device_desc *desc = dev_to_desc(skb->dev);
|
||||
|
||||
if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL) {
|
||||
hdlc->stats.rx_dropped++;
|
||||
desc->stats.rx_dropped++;
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
if (lapb_data_received(skb->dev, skb) == LAPB_OK)
|
||||
return NET_RX_SUCCESS;
|
||||
|
||||
hdlc->stats.rx_errors++;
|
||||
desc->stats.rx_errors++;
|
||||
dev_kfree_skb_any(skb);
|
||||
return NET_RX_DROP;
|
||||
}
|
||||
|
||||
|
||||
static struct hdlc_proto proto = {
|
||||
.open = x25_open,
|
||||
.close = x25_close,
|
||||
.ioctl = x25_ioctl,
|
||||
.module = THIS_MODULE,
|
||||
};
|
||||
|
||||
int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
static int x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
int result;
|
||||
|
||||
switch (ifr->ifr_settings.type) {
|
||||
case IF_GET_PROTO:
|
||||
if (dev_to_hdlc(dev)->proto != &proto)
|
||||
return -EINVAL;
|
||||
ifr->ifr_settings.type = IF_PROTO_X25;
|
||||
return 0; /* return protocol only, no settable parameters */
|
||||
|
||||
@ -200,14 +211,9 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
hdlc_proto_detach(hdlc);
|
||||
memset(&hdlc->proto, 0, sizeof(hdlc->proto));
|
||||
|
||||
hdlc->proto.open = x25_open;
|
||||
hdlc->proto.close = x25_close;
|
||||
hdlc->proto.netif_rx = x25_rx;
|
||||
hdlc->proto.type_trans = NULL;
|
||||
hdlc->proto.id = IF_PROTO_X25;
|
||||
if ((result = attach_hdlc_protocol(dev, &proto,
|
||||
x25_rx, 0)) != 0)
|
||||
return result;
|
||||
dev->hard_start_xmit = x25_xmit;
|
||||
dev->hard_header = NULL;
|
||||
dev->type = ARPHRD_X25;
|
||||
@ -218,3 +224,25 @@ int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr)
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
||||
static int __init mod_init(void)
|
||||
{
|
||||
register_hdlc_protocol(&proto);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void __exit mod_exit(void)
|
||||
{
|
||||
unregister_hdlc_protocol(&proto);
|
||||
}
|
||||
|
||||
|
||||
module_init(mod_init);
|
||||
module_exit(mod_exit);
|
||||
|
||||
MODULE_AUTHOR("Krzysztof Halasa <khc@pm.waw.pl>");
|
||||
MODULE_DESCRIPTION("X.25 protocol support for generic HDLC");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
@ -100,6 +100,7 @@
|
||||
#define _PC300_H
|
||||
|
||||
#include <linux/hdlc.h>
|
||||
#include <net/syncppp.h>
|
||||
#include "hd64572.h"
|
||||
#include "pc300-falc-lh.h"
|
||||
|
||||
|
@ -2016,7 +2016,6 @@ static void sca_intr(pc300_t * card)
|
||||
pc300ch_t *chan = &card->chan[ch];
|
||||
pc300dev_t *d = &chan->d;
|
||||
struct net_device *dev = d->dev;
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
|
||||
spin_lock(&card->card_lock);
|
||||
|
||||
@ -2049,8 +2048,8 @@ static void sca_intr(pc300_t * card)
|
||||
}
|
||||
cpc_net_rx(dev);
|
||||
/* Discard invalid frames */
|
||||
hdlc->stats.rx_errors++;
|
||||
hdlc->stats.rx_over_errors++;
|
||||
hdlc_stats(dev)->rx_errors++;
|
||||
hdlc_stats(dev)->rx_over_errors++;
|
||||
chan->rx_first_bd = 0;
|
||||
chan->rx_last_bd = N_DMA_RX_BUF - 1;
|
||||
rx_dma_start(card, ch);
|
||||
@ -2116,8 +2115,8 @@ static void sca_intr(pc300_t * card)
|
||||
card->hw.cpld_reg2) &
|
||||
~ (CPLD_REG2_FALC_LED1 << (2 * ch)));
|
||||
}
|
||||
hdlc->stats.tx_errors++;
|
||||
hdlc->stats.tx_fifo_errors++;
|
||||
hdlc_stats(dev)->tx_errors++;
|
||||
hdlc_stats(dev)->tx_fifo_errors++;
|
||||
sca_tx_intr(d);
|
||||
}
|
||||
}
|
||||
@ -2534,7 +2533,6 @@ static int cpc_change_mtu(struct net_device *dev, int new_mtu)
|
||||
|
||||
static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pc300dev_t *d = (pc300dev_t *) dev->priv;
|
||||
pc300ch_t *chan = (pc300ch_t *) d->chan;
|
||||
pc300_t *card = (pc300_t *) chan->card;
|
||||
@ -2552,10 +2550,10 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
case SIOCGPC300CONF:
|
||||
#ifdef CONFIG_PC300_MLPPP
|
||||
if (conf->proto != PC300_PROTO_MLPPP) {
|
||||
conf->proto = hdlc->proto.id;
|
||||
conf->proto = /* FIXME hdlc->proto.id */ 0;
|
||||
}
|
||||
#else
|
||||
conf->proto = hdlc->proto.id;
|
||||
conf->proto = /* FIXME hdlc->proto.id */ 0;
|
||||
#endif
|
||||
memcpy(&conf_aux.conf, conf, sizeof(pc300chconf_t));
|
||||
memcpy(&conf_aux.hw, &card->hw, sizeof(pc300hw_t));
|
||||
@ -2588,12 +2586,12 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
}
|
||||
} else {
|
||||
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
|
||||
hdlc->proto.id = conf->proto;
|
||||
/* FIXME hdlc->proto.id = conf->proto; */
|
||||
}
|
||||
}
|
||||
#else
|
||||
memcpy(conf, &conf_aux.conf, sizeof(pc300chconf_t));
|
||||
hdlc->proto.id = conf->proto;
|
||||
/* FIXME hdlc->proto.id = conf->proto; */
|
||||
#endif
|
||||
return 0;
|
||||
case SIOCGPC300STATUS:
|
||||
@ -2606,7 +2604,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
case SIOCGPC300UTILSTATS:
|
||||
{
|
||||
if (!arg) { /* clear statistics */
|
||||
memset(&hdlc->stats, 0, sizeof(struct net_device_stats));
|
||||
memset(hdlc_stats(dev), 0, sizeof(struct net_device_stats));
|
||||
if (card->hw.type == PC300_TE) {
|
||||
memset(&chan->falc, 0, sizeof(falc_t));
|
||||
}
|
||||
@ -2617,7 +2615,7 @@ static int cpc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
|
||||
pc300stats.hw_type = card->hw.type;
|
||||
pc300stats.line_on = card->chan[ch].d.line_on;
|
||||
pc300stats.line_off = card->chan[ch].d.line_off;
|
||||
memcpy(&pc300stats.gen_stats, &hdlc->stats,
|
||||
memcpy(&pc300stats.gen_stats, hdlc_stats(dev),
|
||||
sizeof(struct net_device_stats));
|
||||
if (card->hw.type == PC300_TE)
|
||||
memcpy(&pc300stats.te_stats,&chan->falc,sizeof(falc_t));
|
||||
@ -3147,7 +3145,6 @@ static void cpc_closech(pc300dev_t * d)
|
||||
|
||||
int cpc_open(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pc300dev_t *d = (pc300dev_t *) dev->priv;
|
||||
struct ifreq ifr;
|
||||
int result;
|
||||
@ -3156,12 +3153,14 @@ int cpc_open(struct net_device *dev)
|
||||
printk("pc300: cpc_open");
|
||||
#endif
|
||||
|
||||
#ifdef FIXME
|
||||
if (hdlc->proto.id == IF_PROTO_PPP) {
|
||||
d->if_ptr = &hdlc->state.ppp.pppdev;
|
||||
}
|
||||
#endif
|
||||
|
||||
result = hdlc_open(dev);
|
||||
if (hdlc->proto.id == IF_PROTO_PPP) {
|
||||
if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
|
||||
dev->priv = d;
|
||||
}
|
||||
if (result) {
|
||||
@ -3176,7 +3175,6 @@ int cpc_open(struct net_device *dev)
|
||||
|
||||
static int cpc_close(struct net_device *dev)
|
||||
{
|
||||
hdlc_device *hdlc = dev_to_hdlc(dev);
|
||||
pc300dev_t *d = (pc300dev_t *) dev->priv;
|
||||
pc300ch_t *chan = (pc300ch_t *) d->chan;
|
||||
pc300_t *card = (pc300_t *) chan->card;
|
||||
@ -3193,7 +3191,7 @@ static int cpc_close(struct net_device *dev)
|
||||
CPC_UNLOCK(card, flags);
|
||||
|
||||
hdlc_close(dev);
|
||||
if (hdlc->proto.id == IF_PROTO_PPP) {
|
||||
if (/* FIXME hdlc->proto.id == IF_PROTO_PPP*/ 0) {
|
||||
d->if_ptr = NULL;
|
||||
}
|
||||
#ifdef CONFIG_PC300_MLPPP
|
||||
|
@ -5868,7 +5868,7 @@ static int airo_set_essid(struct net_device *dev,
|
||||
int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
|
||||
|
||||
/* Check the size of the string */
|
||||
if(dwrq->length > IW_ESSID_MAX_SIZE+1) {
|
||||
if(dwrq->length > IW_ESSID_MAX_SIZE) {
|
||||
return -E2BIG ;
|
||||
}
|
||||
/* Check if index is valid */
|
||||
@ -5880,7 +5880,7 @@ static int airo_set_essid(struct net_device *dev,
|
||||
memset(SSID_rid.ssids[index].ssid, 0,
|
||||
sizeof(SSID_rid.ssids[index].ssid));
|
||||
memcpy(SSID_rid.ssids[index].ssid, extra, dwrq->length);
|
||||
SSID_rid.ssids[index].len = dwrq->length - 1;
|
||||
SSID_rid.ssids[index].len = dwrq->length;
|
||||
}
|
||||
SSID_rid.len = sizeof(SSID_rid);
|
||||
/* Write it to the card */
|
||||
@ -5990,7 +5990,7 @@ static int airo_set_nick(struct net_device *dev,
|
||||
struct airo_info *local = dev->priv;
|
||||
|
||||
/* Check the size of the string */
|
||||
if(dwrq->length > 16 + 1) {
|
||||
if(dwrq->length > 16) {
|
||||
return -E2BIG;
|
||||
}
|
||||
readConfigRid(local, 1);
|
||||
@ -6015,7 +6015,7 @@ static int airo_get_nick(struct net_device *dev,
|
||||
readConfigRid(local, 1);
|
||||
strncpy(extra, local->config.nodeName, 16);
|
||||
extra[16] = '\0';
|
||||
dwrq->length = strlen(extra) + 1;
|
||||
dwrq->length = strlen(extra);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -6767,9 +6767,9 @@ static int airo_set_retry(struct net_device *dev,
|
||||
}
|
||||
readConfigRid(local, 1);
|
||||
if(vwrq->flags & IW_RETRY_LIMIT) {
|
||||
if(vwrq->flags & IW_RETRY_MAX)
|
||||
if(vwrq->flags & IW_RETRY_LONG)
|
||||
local->config.longRetryLimit = vwrq->value;
|
||||
else if (vwrq->flags & IW_RETRY_MIN)
|
||||
else if (vwrq->flags & IW_RETRY_SHORT)
|
||||
local->config.shortRetryLimit = vwrq->value;
|
||||
else {
|
||||
/* No modifier : set both */
|
||||
@ -6805,14 +6805,14 @@ static int airo_get_retry(struct net_device *dev,
|
||||
if((vwrq->flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME) {
|
||||
vwrq->flags = IW_RETRY_LIFETIME;
|
||||
vwrq->value = (int)local->config.txLifetime * 1024;
|
||||
} else if((vwrq->flags & IW_RETRY_MAX)) {
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
} else if((vwrq->flags & IW_RETRY_LONG)) {
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
vwrq->value = (int)local->config.longRetryLimit;
|
||||
} else {
|
||||
vwrq->flags = IW_RETRY_LIMIT;
|
||||
vwrq->value = (int)local->config.shortRetryLimit;
|
||||
if((int)local->config.shortRetryLimit != (int)local->config.longRetryLimit)
|
||||
vwrq->flags |= IW_RETRY_MIN;
|
||||
vwrq->flags |= IW_RETRY_SHORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
@ -6990,6 +6990,7 @@ static int airo_set_power(struct net_device *dev,
|
||||
local->config.rmode |= RXMODE_BC_MC_ADDR;
|
||||
set_bit (FLAG_COMMIT, &local->flags);
|
||||
case IW_POWER_ON:
|
||||
/* This is broken, fixme ;-) */
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
|
@ -1656,13 +1656,13 @@ static int atmel_set_essid(struct net_device *dev,
|
||||
priv->connect_to_any_BSS = 0;
|
||||
|
||||
/* Check the size of the string */
|
||||
if (dwrq->length > MAX_SSID_LENGTH + 1)
|
||||
if (dwrq->length > MAX_SSID_LENGTH)
|
||||
return -E2BIG;
|
||||
if (index != 0)
|
||||
return -EINVAL;
|
||||
|
||||
memcpy(priv->new_SSID, extra, dwrq->length - 1);
|
||||
priv->new_SSID_size = dwrq->length - 1;
|
||||
memcpy(priv->new_SSID, extra, dwrq->length);
|
||||
priv->new_SSID_size = dwrq->length;
|
||||
}
|
||||
|
||||
return -EINPROGRESS;
|
||||
@ -2120,9 +2120,9 @@ static int atmel_set_retry(struct net_device *dev,
|
||||
struct atmel_private *priv = netdev_priv(dev);
|
||||
|
||||
if (!vwrq->disabled && (vwrq->flags & IW_RETRY_LIMIT)) {
|
||||
if (vwrq->flags & IW_RETRY_MAX)
|
||||
if (vwrq->flags & IW_RETRY_LONG)
|
||||
priv->long_retry = vwrq->value;
|
||||
else if (vwrq->flags & IW_RETRY_MIN)
|
||||
else if (vwrq->flags & IW_RETRY_SHORT)
|
||||
priv->short_retry = vwrq->value;
|
||||
else {
|
||||
/* No modifier : set both */
|
||||
@ -2144,15 +2144,15 @@ static int atmel_get_retry(struct net_device *dev,
|
||||
|
||||
vwrq->disabled = 0; /* Can't be disabled */
|
||||
|
||||
/* Note : by default, display the min retry number */
|
||||
if (vwrq->flags & IW_RETRY_MAX) {
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
/* Note : by default, display the short retry number */
|
||||
if (vwrq->flags & IW_RETRY_LONG) {
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
vwrq->value = priv->long_retry;
|
||||
} else {
|
||||
vwrq->flags = IW_RETRY_LIMIT;
|
||||
vwrq->value = priv->short_retry;
|
||||
if (priv->long_retry != priv->short_retry)
|
||||
vwrq->flags |= IW_RETRY_MIN;
|
||||
vwrq->flags |= IW_RETRY_SHORT;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -666,7 +666,6 @@ struct bcm43xx_noise_calculation {
|
||||
};
|
||||
|
||||
struct bcm43xx_stats {
|
||||
u8 link_quality;
|
||||
u8 noise;
|
||||
struct iw_statistics wstats;
|
||||
/* Store the last TX/RX times here for updating the leds. */
|
||||
|
@ -2405,9 +2405,10 @@ static int bcm43xx_chip_init(struct bcm43xx_private *bcm)
|
||||
BCM43xx_UCODE_TIME) & 0x1f);
|
||||
|
||||
if ( value16 > 0x128 ) {
|
||||
dprintk(KERN_ERR PFX
|
||||
"Firmware: no support for microcode rev > 0x128\n");
|
||||
err = -1;
|
||||
printk(KERN_ERR PFX
|
||||
"Firmware: no support for microcode extracted "
|
||||
"from version 4.x binary drivers.\n");
|
||||
err = -EOPNOTSUPP;
|
||||
goto err_release_fw;
|
||||
}
|
||||
|
||||
@ -3169,8 +3170,7 @@ static void bcm43xx_periodic_work_handler(void *d)
|
||||
* be preemtible.
|
||||
*/
|
||||
mutex_lock(&bcm->mutex);
|
||||
netif_stop_queue(bcm->net_dev);
|
||||
synchronize_net();
|
||||
netif_tx_disable(bcm->net_dev);
|
||||
spin_lock_irqsave(&bcm->irq_lock, flags);
|
||||
bcm43xx_mac_suspend(bcm);
|
||||
if (bcm43xx_using_pio(bcm))
|
||||
|
@ -361,7 +361,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
|
||||
if (phy->rev <= 2)
|
||||
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
|
||||
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg1[i]);
|
||||
else if ((phy->rev == 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
|
||||
else if ((phy->rev >= 7) && (bcm43xx_phy_read(bcm, 0x0449) & 0x0200))
|
||||
for (i = 0; i < BCM43xx_ILT_NOISESCALEG_SIZE; i++)
|
||||
bcm43xx_ilt_write(bcm, 0x1400 + i, bcm43xx_ilt_noisescaleg3[i]);
|
||||
else
|
||||
@ -371,7 +371,7 @@ static void bcm43xx_phy_setupg(struct bcm43xx_private *bcm)
|
||||
if (phy->rev == 2)
|
||||
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
|
||||
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr1[i]);
|
||||
else if ((phy->rev > 2) && (phy->rev <= 7))
|
||||
else if ((phy->rev > 2) && (phy->rev <= 8))
|
||||
for (i = 0; i < BCM43xx_ILT_SIGMASQR_SIZE; i++)
|
||||
bcm43xx_ilt_write(bcm, 0x5000 + i, bcm43xx_ilt_sigmasqr2[i]);
|
||||
|
||||
@ -1197,7 +1197,7 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
|
||||
|
||||
if (phy->rev == 1)
|
||||
bcm43xx_phy_initb5(bcm);
|
||||
else if (phy->rev >= 2 && phy->rev <= 7)
|
||||
else
|
||||
bcm43xx_phy_initb6(bcm);
|
||||
if (phy->rev >= 2 || phy->connected)
|
||||
bcm43xx_phy_inita(bcm);
|
||||
@ -1241,23 +1241,22 @@ static void bcm43xx_phy_initg(struct bcm43xx_private *bcm)
|
||||
bcm43xx_phy_lo_g_measure(bcm);
|
||||
} else {
|
||||
if (radio->version == 0x2050 && radio->revision == 8) {
|
||||
//FIXME
|
||||
bcm43xx_radio_write16(bcm, 0x0052,
|
||||
(radio->txctl1 << 4) | radio->txctl2);
|
||||
} else {
|
||||
bcm43xx_radio_write16(bcm, 0x0052,
|
||||
(bcm43xx_radio_read16(bcm, 0x0052)
|
||||
& 0xFFF0) | radio->txctl1);
|
||||
}
|
||||
if (phy->rev >= 6) {
|
||||
/*
|
||||
bcm43xx_phy_write(bcm, 0x0036,
|
||||
(bcm43xx_phy_read(bcm, 0x0036)
|
||||
& 0xF000) | (FIXME << 12));
|
||||
*/
|
||||
& 0xF000) | (radio->txctl2 << 12));
|
||||
}
|
||||
if (bcm->sprom.boardflags & BCM43xx_BFL_PACTRL)
|
||||
bcm43xx_phy_write(bcm, 0x002E, 0x8075);
|
||||
else
|
||||
bcm43xx_phy_write(bcm, 0x003E, 0x807F);
|
||||
bcm43xx_phy_write(bcm, 0x002E, 0x807F);
|
||||
if (phy->rev < 2)
|
||||
bcm43xx_phy_write(bcm, 0x002F, 0x0101);
|
||||
else
|
||||
|
@ -334,7 +334,7 @@ static int bcm43xx_wx_get_nick(struct net_device *net_dev,
|
||||
size_t len;
|
||||
|
||||
mutex_lock(&bcm->mutex);
|
||||
len = strlen(bcm->nick) + 1;
|
||||
len = strlen(bcm->nick);
|
||||
memcpy(extra, bcm->nick, len);
|
||||
data->data.length = (__u16)len;
|
||||
data->data.flags = 1;
|
||||
|
@ -496,15 +496,14 @@ int bcm43xx_rx(struct bcm43xx_private *bcm,
|
||||
stats.signal = bcm43xx_rssi_postprocess(bcm, rxhdr->rssi, is_ofdm,
|
||||
!!(rxflags1 & BCM43xx_RXHDR_FLAGS1_2053RSSIADJ),
|
||||
!!(rxflags3 & BCM43xx_RXHDR_FLAGS3_2050RSSIADJ));
|
||||
//TODO stats.noise =
|
||||
stats.noise = bcm->stats.noise;
|
||||
if (is_ofdm)
|
||||
stats.rate = bcm43xx_plcp_get_bitrate_ofdm(plcp);
|
||||
else
|
||||
stats.rate = bcm43xx_plcp_get_bitrate_cck(plcp);
|
||||
stats.received_channel = radio->channel;
|
||||
//TODO stats.control =
|
||||
stats.mask = IEEE80211_STATMASK_SIGNAL |
|
||||
//TODO IEEE80211_STATMASK_NOISE |
|
||||
IEEE80211_STATMASK_NOISE |
|
||||
IEEE80211_STATMASK_RATE |
|
||||
IEEE80211_STATMASK_RSSI;
|
||||
if (phy->type == BCM43xx_PHYTYPE_A)
|
||||
|
@ -1412,9 +1412,9 @@ static int prism2_ioctl_siwretry(struct net_device *dev,
|
||||
/* what could be done, if firmware would support this.. */
|
||||
|
||||
if (rrq->flags & IW_RETRY_LIMIT) {
|
||||
if (rrq->flags & IW_RETRY_MAX)
|
||||
if (rrq->flags & IW_RETRY_LONG)
|
||||
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
|
||||
else if (rrq->flags & IW_RETRY_MIN)
|
||||
else if (rrq->flags & IW_RETRY_SHORT)
|
||||
HFA384X_RID_SHORTRETRYLIMIT = rrq->value;
|
||||
else {
|
||||
HFA384X_RID_LONGRETRYLIMIT = rrq->value;
|
||||
@ -1468,14 +1468,14 @@ static int prism2_ioctl_giwretry(struct net_device *dev,
|
||||
rrq->value = le16_to_cpu(altretry);
|
||||
else
|
||||
rrq->value = local->manual_retry_count;
|
||||
} else if ((rrq->flags & IW_RETRY_MAX)) {
|
||||
rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
} else if ((rrq->flags & IW_RETRY_LONG)) {
|
||||
rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
rrq->value = longretry;
|
||||
} else {
|
||||
rrq->flags = IW_RETRY_LIMIT;
|
||||
rrq->value = shortretry;
|
||||
if (shortretry != longretry)
|
||||
rrq->flags |= IW_RETRY_MIN;
|
||||
rrq->flags |= IW_RETRY_SHORT;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
|
@ -6958,7 +6958,7 @@ static int ipw2100_wx_set_essid(struct net_device *dev,
|
||||
}
|
||||
|
||||
if (wrqu->essid.flags && wrqu->essid.length) {
|
||||
length = wrqu->essid.length - 1;
|
||||
length = wrqu->essid.length;
|
||||
essid = extra;
|
||||
}
|
||||
|
||||
@ -7051,7 +7051,7 @@ static int ipw2100_wx_get_nick(struct net_device *dev,
|
||||
|
||||
struct ipw2100_priv *priv = ieee80211_priv(dev);
|
||||
|
||||
wrqu->data.length = strlen(priv->nick) + 1;
|
||||
wrqu->data.length = strlen(priv->nick);
|
||||
memcpy(extra, priv->nick, wrqu->data.length);
|
||||
wrqu->data.flags = 1; /* active */
|
||||
|
||||
@ -7343,14 +7343,14 @@ static int ipw2100_wx_set_retry(struct net_device *dev,
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (wrqu->retry.flags & IW_RETRY_MIN) {
|
||||
if (wrqu->retry.flags & IW_RETRY_SHORT) {
|
||||
err = ipw2100_set_short_retry(priv, wrqu->retry.value);
|
||||
IPW_DEBUG_WX("SET Short Retry Limit -> %d \n",
|
||||
wrqu->retry.value);
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (wrqu->retry.flags & IW_RETRY_MAX) {
|
||||
if (wrqu->retry.flags & IW_RETRY_LONG) {
|
||||
err = ipw2100_set_long_retry(priv, wrqu->retry.value);
|
||||
IPW_DEBUG_WX("SET Long Retry Limit -> %d \n",
|
||||
wrqu->retry.value);
|
||||
@ -7383,14 +7383,14 @@ static int ipw2100_wx_get_retry(struct net_device *dev,
|
||||
if ((wrqu->retry.flags & IW_RETRY_TYPE) == IW_RETRY_LIFETIME)
|
||||
return -EINVAL;
|
||||
|
||||
if (wrqu->retry.flags & IW_RETRY_MAX) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
if (wrqu->retry.flags & IW_RETRY_LONG) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
wrqu->retry.value = priv->long_retry_limit;
|
||||
} else {
|
||||
wrqu->retry.flags =
|
||||
(priv->short_retry_limit !=
|
||||
priv->long_retry_limit) ?
|
||||
IW_RETRY_LIMIT | IW_RETRY_MIN : IW_RETRY_LIMIT;
|
||||
IW_RETRY_LIMIT | IW_RETRY_SHORT : IW_RETRY_LIMIT;
|
||||
|
||||
wrqu->retry.value = priv->short_retry_limit;
|
||||
}
|
||||
|
@ -8875,8 +8875,6 @@ static int ipw_wx_set_essid(struct net_device *dev,
|
||||
}
|
||||
|
||||
length = min((int)wrqu->essid.length, IW_ESSID_MAX_SIZE);
|
||||
if (!extra[length - 1])
|
||||
length--;
|
||||
|
||||
priv->config |= CFG_STATIC_ESSID;
|
||||
|
||||
@ -8953,7 +8951,7 @@ static int ipw_wx_get_nick(struct net_device *dev,
|
||||
struct ipw_priv *priv = ieee80211_priv(dev);
|
||||
IPW_DEBUG_WX("Getting nick\n");
|
||||
mutex_lock(&priv->mutex);
|
||||
wrqu->data.length = strlen(priv->nick) + 1;
|
||||
wrqu->data.length = strlen(priv->nick);
|
||||
memcpy(extra, priv->nick, wrqu->data.length);
|
||||
wrqu->data.flags = 1; /* active */
|
||||
mutex_unlock(&priv->mutex);
|
||||
@ -9276,9 +9274,9 @@ static int ipw_wx_set_retry(struct net_device *dev,
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&priv->mutex);
|
||||
if (wrqu->retry.flags & IW_RETRY_MIN)
|
||||
if (wrqu->retry.flags & IW_RETRY_SHORT)
|
||||
priv->short_retry_limit = (u8) wrqu->retry.value;
|
||||
else if (wrqu->retry.flags & IW_RETRY_MAX)
|
||||
else if (wrqu->retry.flags & IW_RETRY_LONG)
|
||||
priv->long_retry_limit = (u8) wrqu->retry.value;
|
||||
else {
|
||||
priv->short_retry_limit = (u8) wrqu->retry.value;
|
||||
@ -9307,11 +9305,11 @@ static int ipw_wx_get_retry(struct net_device *dev,
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (wrqu->retry.flags & IW_RETRY_MAX) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
if (wrqu->retry.flags & IW_RETRY_LONG) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
wrqu->retry.value = priv->long_retry_limit;
|
||||
} else if (wrqu->retry.flags & IW_RETRY_MIN) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
|
||||
} else if (wrqu->retry.flags & IW_RETRY_SHORT) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
|
||||
wrqu->retry.value = priv->short_retry_limit;
|
||||
} else {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT;
|
||||
|
@ -3037,7 +3037,7 @@ static int orinoco_ioctl_getessid(struct net_device *dev,
|
||||
}
|
||||
|
||||
erq->flags = 1;
|
||||
erq->length = strlen(essidbuf) + 1;
|
||||
erq->length = strlen(essidbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3078,7 +3078,7 @@ static int orinoco_ioctl_getnick(struct net_device *dev,
|
||||
memcpy(nickbuf, priv->nick, IW_ESSID_MAX_SIZE+1);
|
||||
orinoco_unlock(priv, &flags);
|
||||
|
||||
nrq->length = strlen(nickbuf)+1;
|
||||
nrq->length = strlen(nickbuf);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -3575,14 +3575,14 @@ static int orinoco_ioctl_getretry(struct net_device *dev,
|
||||
rrq->value = lifetime * 1000; /* ??? */
|
||||
} else {
|
||||
/* By default, display the min number */
|
||||
if ((rrq->flags & IW_RETRY_MAX)) {
|
||||
rrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
if ((rrq->flags & IW_RETRY_LONG)) {
|
||||
rrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
rrq->value = long_limit;
|
||||
} else {
|
||||
rrq->flags = IW_RETRY_LIMIT;
|
||||
rrq->value = short_limit;
|
||||
if(short_limit != long_limit)
|
||||
rrq->flags |= IW_RETRY_MIN;
|
||||
rrq->flags |= IW_RETRY_SHORT;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -742,9 +742,9 @@ prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
|
||||
|
||||
/* Check if we were asked for `any' */
|
||||
if (dwrq->flags && dwrq->length) {
|
||||
if (dwrq->length > min(33, IW_ESSID_MAX_SIZE + 1))
|
||||
if (dwrq->length > 32)
|
||||
return -E2BIG;
|
||||
essid.length = dwrq->length - 1;
|
||||
essid.length = dwrq->length;
|
||||
memcpy(essid.octets, extra, dwrq->length);
|
||||
} else
|
||||
essid.length = 0;
|
||||
@ -814,7 +814,7 @@ prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
|
||||
dwrq->length = 0;
|
||||
|
||||
down_read(&priv->mib_sem);
|
||||
dwrq->length = strlen(priv->nickname) + 1;
|
||||
dwrq->length = strlen(priv->nickname);
|
||||
memcpy(extra, priv->nickname, dwrq->length);
|
||||
up_read(&priv->mib_sem);
|
||||
|
||||
@ -992,9 +992,9 @@ prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
|
||||
return -EINVAL;
|
||||
|
||||
if (vwrq->flags & IW_RETRY_LIMIT) {
|
||||
if (vwrq->flags & IW_RETRY_MIN)
|
||||
if (vwrq->flags & IW_RETRY_SHORT)
|
||||
slimit = vwrq->value;
|
||||
else if (vwrq->flags & IW_RETRY_MAX)
|
||||
else if (vwrq->flags & IW_RETRY_LONG)
|
||||
llimit = vwrq->value;
|
||||
else {
|
||||
/* we are asked to set both */
|
||||
@ -1035,18 +1035,18 @@ prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
|
||||
mgt_get_request(priv, DOT11_OID_MAXTXLIFETIME, 0, NULL, &r);
|
||||
vwrq->value = r.u * 1024;
|
||||
vwrq->flags = IW_RETRY_LIFETIME;
|
||||
} else if ((vwrq->flags & IW_RETRY_MAX)) {
|
||||
} else if ((vwrq->flags & IW_RETRY_LONG)) {
|
||||
/* we are asked for the long retry limit */
|
||||
rvalue |=
|
||||
mgt_get_request(priv, DOT11_OID_LONGRETRIES, 0, NULL, &r);
|
||||
vwrq->value = r.u;
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
} else {
|
||||
/* default. get the short retry limit */
|
||||
rvalue |=
|
||||
mgt_get_request(priv, DOT11_OID_SHORTRETRIES, 0, NULL, &r);
|
||||
vwrq->value = r.u;
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
|
||||
vwrq->flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
|
||||
}
|
||||
|
||||
return rvalue;
|
||||
|
@ -1173,7 +1173,7 @@ static int ray_set_essid(struct net_device *dev,
|
||||
return -EOPNOTSUPP;
|
||||
} else {
|
||||
/* Check the size of the string */
|
||||
if(dwrq->length > IW_ESSID_MAX_SIZE + 1) {
|
||||
if(dwrq->length > IW_ESSID_MAX_SIZE) {
|
||||
return -E2BIG;
|
||||
}
|
||||
|
||||
|
@ -1802,15 +1802,15 @@ static int wl3501_get_retry(struct net_device *dev,
|
||||
&retry, sizeof(retry));
|
||||
if (rc)
|
||||
goto out;
|
||||
if (wrqu->retry.flags & IW_RETRY_MAX) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MAX;
|
||||
if (wrqu->retry.flags & IW_RETRY_LONG) {
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_LONG;
|
||||
goto set_value;
|
||||
}
|
||||
rc = wl3501_get_mib_value(this, WL3501_MIB_ATTR_SHORT_RETRY_LIMIT,
|
||||
&retry, sizeof(retry));
|
||||
if (rc)
|
||||
goto out;
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_MIN;
|
||||
wrqu->retry.flags = IW_RETRY_LIMIT | IW_RETRY_SHORT;
|
||||
set_value:
|
||||
wrqu->retry.value = retry;
|
||||
wrqu->retry.disabled = 0;
|
||||
|
@ -1218,7 +1218,7 @@ static int zd1201_set_essid(struct net_device *dev,
|
||||
return -EINVAL;
|
||||
if (data->length < 1)
|
||||
data->length = 1;
|
||||
zd->essidlen = data->length-1;
|
||||
zd->essidlen = data->length;
|
||||
memset(zd->essid, 0, IW_ESSID_MAX_SIZE+1);
|
||||
memcpy(zd->essid, essid, data->length);
|
||||
return zd1201_join(zd, zd->essid, zd->essidlen);
|
||||
|
@ -249,7 +249,6 @@ int zd_ioread16(struct zd_chip *chip, zd_addr_t addr, u16 *value)
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_ioread16_locked(chip, value, addr);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -260,7 +259,6 @@ int zd_ioread32(struct zd_chip *chip, zd_addr_t addr, u32 *value)
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_ioread32_locked(chip, value, addr);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -271,7 +269,6 @@ int zd_iowrite16(struct zd_chip *chip, zd_addr_t addr, u16 value)
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_iowrite16_locked(chip, value, addr);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -282,7 +279,6 @@ int zd_iowrite32(struct zd_chip *chip, zd_addr_t addr, u32 value)
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_iowrite32_locked(chip, value, addr);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -294,7 +290,6 @@ int zd_ioread32v(struct zd_chip *chip, const zd_addr_t *addresses,
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_ioread32v_locked(chip, values, addresses, count);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -306,7 +301,6 @@ int zd_iowrite32a(struct zd_chip *chip, const struct zd_ioreq32 *ioreqs,
|
||||
{
|
||||
int r;
|
||||
|
||||
ZD_ASSERT(!mutex_is_locked(&chip->mutex));
|
||||
mutex_lock(&chip->mutex);
|
||||
r = zd_iowrite32a_locked(chip, ioreqs, count);
|
||||
mutex_unlock(&chip->mutex);
|
||||
@ -331,13 +325,22 @@ static int read_pod(struct zd_chip *chip, u8 *rf_type)
|
||||
chip->patch_cr157 = (value >> 13) & 0x1;
|
||||
chip->patch_6m_band_edge = (value >> 21) & 0x1;
|
||||
chip->new_phy_layout = (value >> 31) & 0x1;
|
||||
chip->link_led = ((value >> 4) & 1) ? LED1 : LED2;
|
||||
chip->supports_tx_led = 1;
|
||||
if (value & (1 << 24)) { /* LED scenario */
|
||||
if (value & (1 << 29))
|
||||
chip->supports_tx_led = 0;
|
||||
}
|
||||
|
||||
dev_dbg_f(zd_chip_dev(chip),
|
||||
"RF %s %#01x PA type %#01x patch CCK %d patch CR157 %d "
|
||||
"patch 6M %d new PHY %d\n",
|
||||
"patch 6M %d new PHY %d link LED%d tx led %d\n",
|
||||
zd_rf_name(*rf_type), *rf_type,
|
||||
chip->pa_type, chip->patch_cck_gain,
|
||||
chip->patch_cr157, chip->patch_6m_band_edge, chip->new_phy_layout);
|
||||
chip->patch_cr157, chip->patch_6m_band_edge,
|
||||
chip->new_phy_layout,
|
||||
chip->link_led == LED1 ? 1 : 2,
|
||||
chip->supports_tx_led);
|
||||
return 0;
|
||||
error:
|
||||
*rf_type = 0;
|
||||
@ -1181,7 +1184,7 @@ static int update_pwr_int(struct zd_chip *chip, u8 channel)
|
||||
u8 value = chip->pwr_int_values[channel - 1];
|
||||
dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_int %#04x\n",
|
||||
channel, value);
|
||||
return zd_iowrite32_locked(chip, value, CR31);
|
||||
return zd_iowrite16_locked(chip, value, CR31);
|
||||
}
|
||||
|
||||
static int update_pwr_cal(struct zd_chip *chip, u8 channel)
|
||||
@ -1189,12 +1192,12 @@ static int update_pwr_cal(struct zd_chip *chip, u8 channel)
|
||||
u8 value = chip->pwr_cal_values[channel-1];
|
||||
dev_dbg_f(zd_chip_dev(chip), "channel %d pwr_cal %#04x\n",
|
||||
channel, value);
|
||||
return zd_iowrite32_locked(chip, value, CR68);
|
||||
return zd_iowrite16_locked(chip, value, CR68);
|
||||
}
|
||||
|
||||
static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
|
||||
{
|
||||
struct zd_ioreq32 ioreqs[3];
|
||||
struct zd_ioreq16 ioreqs[3];
|
||||
|
||||
ioreqs[0].addr = CR67;
|
||||
ioreqs[0].value = chip->ofdm_cal_values[OFDM_36M_INDEX][channel-1];
|
||||
@ -1206,7 +1209,7 @@ static int update_ofdm_cal(struct zd_chip *chip, u8 channel)
|
||||
dev_dbg_f(zd_chip_dev(chip),
|
||||
"channel %d ofdm_cal 36M %#04x 48M %#04x 54M %#04x\n",
|
||||
channel, ioreqs[0].value, ioreqs[1].value, ioreqs[2].value);
|
||||
return zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
return zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
}
|
||||
|
||||
static int update_channel_integration_and_calibration(struct zd_chip *chip,
|
||||
@ -1218,7 +1221,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
|
||||
if (r)
|
||||
return r;
|
||||
if (chip->is_zd1211b) {
|
||||
static const struct zd_ioreq32 ioreqs[] = {
|
||||
static const struct zd_ioreq16 ioreqs[] = {
|
||||
{ CR69, 0x28 },
|
||||
{},
|
||||
{ CR69, 0x2a },
|
||||
@ -1230,7 +1233,7 @@ static int update_channel_integration_and_calibration(struct zd_chip *chip,
|
||||
r = update_pwr_cal(chip, channel);
|
||||
if (r)
|
||||
return r;
|
||||
r = zd_iowrite32a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
if (r)
|
||||
return r;
|
||||
}
|
||||
@ -1252,7 +1255,7 @@ static int patch_cck_gain(struct zd_chip *chip)
|
||||
if (r)
|
||||
return r;
|
||||
dev_dbg_f(zd_chip_dev(chip), "patching value %x\n", value & 0xff);
|
||||
return zd_iowrite32_locked(chip, value & 0xff, CR47);
|
||||
return zd_iowrite16_locked(chip, value & 0xff, CR47);
|
||||
}
|
||||
|
||||
int zd_chip_set_channel(struct zd_chip *chip, u8 channel)
|
||||
@ -1295,92 +1298,63 @@ u8 zd_chip_get_channel(struct zd_chip *chip)
|
||||
return channel;
|
||||
}
|
||||
|
||||
static u16 led_mask(int led)
|
||||
int zd_chip_control_leds(struct zd_chip *chip, enum led_status status)
|
||||
{
|
||||
switch (led) {
|
||||
case 1:
|
||||
return LED1;
|
||||
case 2:
|
||||
return LED2;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
static const zd_addr_t a[] = {
|
||||
FW_LINK_STATUS,
|
||||
CR_LED,
|
||||
};
|
||||
|
||||
static int read_led_reg(struct zd_chip *chip, u16 *status)
|
||||
{
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
return zd_ioread16_locked(chip, status, CR_LED);
|
||||
}
|
||||
int r;
|
||||
u16 v[ARRAY_SIZE(a)];
|
||||
struct zd_ioreq16 ioreqs[ARRAY_SIZE(a)] = {
|
||||
[0] = { FW_LINK_STATUS },
|
||||
[1] = { CR_LED },
|
||||
};
|
||||
u16 other_led;
|
||||
|
||||
static int write_led_reg(struct zd_chip *chip, u16 status)
|
||||
{
|
||||
ZD_ASSERT(mutex_is_locked(&chip->mutex));
|
||||
return zd_iowrite16_locked(chip, status, CR_LED);
|
||||
}
|
||||
|
||||
int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status)
|
||||
{
|
||||
int r, ret;
|
||||
u16 mask = led_mask(led);
|
||||
u16 reg;
|
||||
|
||||
if (!mask)
|
||||
return -EINVAL;
|
||||
mutex_lock(&chip->mutex);
|
||||
r = read_led_reg(chip, ®);
|
||||
r = zd_ioread16v_locked(chip, v, (const zd_addr_t *)a, ARRAY_SIZE(a));
|
||||
if (r)
|
||||
return r;
|
||||
goto out;
|
||||
|
||||
other_led = chip->link_led == LED1 ? LED2 : LED1;
|
||||
|
||||
switch (status) {
|
||||
case LED_STATUS:
|
||||
return (reg & mask) ? LED_ON : LED_OFF;
|
||||
case LED_OFF:
|
||||
reg &= ~mask;
|
||||
ret = LED_OFF;
|
||||
ioreqs[0].value = FW_LINK_OFF;
|
||||
ioreqs[1].value = v[1] & ~(LED1|LED2);
|
||||
break;
|
||||
case LED_FLIP:
|
||||
reg ^= mask;
|
||||
ret = (reg&mask) ? LED_ON : LED_OFF;
|
||||
case LED_SCANNING:
|
||||
ioreqs[0].value = FW_LINK_OFF;
|
||||
ioreqs[1].value = v[1] & ~other_led;
|
||||
if (get_seconds() % 3 == 0) {
|
||||
ioreqs[1].value &= ~chip->link_led;
|
||||
} else {
|
||||
ioreqs[1].value |= chip->link_led;
|
||||
}
|
||||
break;
|
||||
case LED_ON:
|
||||
reg |= mask;
|
||||
ret = LED_ON;
|
||||
case LED_ASSOCIATED:
|
||||
ioreqs[0].value = FW_LINK_TX;
|
||||
ioreqs[1].value = v[1] & ~other_led;
|
||||
ioreqs[1].value |= chip->link_led;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
r = write_led_reg(chip, reg);
|
||||
if (r) {
|
||||
ret = r;
|
||||
r = -EINVAL;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (v[0] != ioreqs[0].value || v[1] != ioreqs[1].value) {
|
||||
r = zd_iowrite16a_locked(chip, ioreqs, ARRAY_SIZE(ioreqs));
|
||||
if (r)
|
||||
goto out;
|
||||
}
|
||||
r = 0;
|
||||
out:
|
||||
mutex_unlock(&chip->mutex);
|
||||
return r;
|
||||
}
|
||||
|
||||
int zd_chip_led_flip(struct zd_chip *chip, int led,
|
||||
const unsigned int *phases_msecs, unsigned int count)
|
||||
{
|
||||
int i, r;
|
||||
enum led_status status;
|
||||
|
||||
r = zd_chip_led_status(chip, led, LED_STATUS);
|
||||
if (r)
|
||||
return r;
|
||||
status = r;
|
||||
for (i = 0; i < count; i++) {
|
||||
r = zd_chip_led_status(chip, led, LED_FLIP);
|
||||
if (r < 0)
|
||||
goto out;
|
||||
msleep(phases_msecs[i]);
|
||||
}
|
||||
|
||||
out:
|
||||
zd_chip_led_status(chip, led, status);
|
||||
return r;
|
||||
}
|
||||
|
||||
int zd_chip_set_basic_rates(struct zd_chip *chip, u16 cr_rates)
|
||||
{
|
||||
int r;
|
||||
@ -1679,4 +1653,3 @@ int zd_rfwritev_cr_locked(struct zd_chip *chip,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -428,6 +428,7 @@
|
||||
/* masks for controlling LEDs */
|
||||
#define LED1 0x0100
|
||||
#define LED2 0x0200
|
||||
#define LED_SW 0x0400
|
||||
|
||||
/* Seems to indicate that the configuration is over.
|
||||
*/
|
||||
@ -629,6 +630,10 @@
|
||||
#define FW_SOFT_RESET FW_REG(4)
|
||||
#define FW_FLASH_CHK FW_REG(5)
|
||||
|
||||
#define FW_LINK_OFF 0x0
|
||||
#define FW_LINK_TX 0x1
|
||||
/* 0x2 - link led on? */
|
||||
|
||||
enum {
|
||||
CR_BASE_OFFSET = 0x9000,
|
||||
FW_START_OFFSET = 0xee00,
|
||||
@ -663,8 +668,11 @@ struct zd_chip {
|
||||
u8 pwr_int_values[E2P_CHANNEL_COUNT];
|
||||
/* SetPointOFDM in the vendor driver */
|
||||
u8 ofdm_cal_values[3][E2P_CHANNEL_COUNT];
|
||||
u8 pa_type:4, patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
|
||||
new_phy_layout:1, is_zd1211b:1;
|
||||
u16 link_led;
|
||||
unsigned int pa_type:4,
|
||||
patch_cck_gain:1, patch_cr157:1, patch_6m_band_edge:1,
|
||||
new_phy_layout:1,
|
||||
is_zd1211b:1, supports_tx_led:1;
|
||||
};
|
||||
|
||||
static inline struct zd_chip *zd_usb_to_chip(struct zd_usb *usb)
|
||||
@ -812,15 +820,12 @@ int zd_chip_lock_phy_regs(struct zd_chip *chip);
|
||||
int zd_chip_unlock_phy_regs(struct zd_chip *chip);
|
||||
|
||||
enum led_status {
|
||||
LED_OFF = 0,
|
||||
LED_ON = 1,
|
||||
LED_FLIP = 2,
|
||||
LED_STATUS = 3,
|
||||
LED_OFF = 0,
|
||||
LED_SCANNING = 1,
|
||||
LED_ASSOCIATED = 2,
|
||||
};
|
||||
|
||||
int zd_chip_led_status(struct zd_chip *chip, int led, enum led_status status);
|
||||
int zd_chip_led_flip(struct zd_chip *chip, int led,
|
||||
const unsigned int *phases_msecs, unsigned int count);
|
||||
int zd_chip_control_leds(struct zd_chip *chip, enum led_status status);
|
||||
|
||||
int zd_set_beacon_interval(struct zd_chip *chip, u32 interval);
|
||||
|
||||
|
@ -33,6 +33,10 @@
|
||||
static void ieee_init(struct ieee80211_device *ieee);
|
||||
static void softmac_init(struct ieee80211softmac_device *sm);
|
||||
|
||||
static void housekeeping_init(struct zd_mac *mac);
|
||||
static void housekeeping_enable(struct zd_mac *mac);
|
||||
static void housekeeping_disable(struct zd_mac *mac);
|
||||
|
||||
int zd_mac_init(struct zd_mac *mac,
|
||||
struct net_device *netdev,
|
||||
struct usb_interface *intf)
|
||||
@ -46,6 +50,7 @@ int zd_mac_init(struct zd_mac *mac,
|
||||
ieee_init(ieee);
|
||||
softmac_init(ieee80211_priv(netdev));
|
||||
zd_chip_init(&mac->chip, netdev, intf);
|
||||
housekeeping_init(mac);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -178,6 +183,7 @@ int zd_mac_open(struct net_device *netdev)
|
||||
if (r < 0)
|
||||
goto disable_rx;
|
||||
|
||||
housekeeping_enable(mac);
|
||||
ieee80211softmac_start(netdev);
|
||||
return 0;
|
||||
disable_rx:
|
||||
@ -204,6 +210,7 @@ int zd_mac_stop(struct net_device *netdev)
|
||||
*/
|
||||
|
||||
zd_chip_disable_rx(chip);
|
||||
housekeeping_disable(mac);
|
||||
ieee80211softmac_stop(netdev);
|
||||
|
||||
zd_chip_disable_hwint(chip);
|
||||
@ -1080,3 +1087,46 @@ void zd_dump_rx_status(const struct rx_status *status)
|
||||
}
|
||||
}
|
||||
#endif /* DEBUG */
|
||||
|
||||
#define LINK_LED_WORK_DELAY HZ
|
||||
|
||||
static void link_led_handler(void *p)
|
||||
{
|
||||
struct zd_mac *mac = p;
|
||||
struct zd_chip *chip = &mac->chip;
|
||||
struct ieee80211softmac_device *sm = ieee80211_priv(mac->netdev);
|
||||
int is_associated;
|
||||
int r;
|
||||
|
||||
spin_lock_irq(&mac->lock);
|
||||
is_associated = sm->associated != 0;
|
||||
spin_unlock_irq(&mac->lock);
|
||||
|
||||
r = zd_chip_control_leds(chip,
|
||||
is_associated ? LED_ASSOCIATED : LED_SCANNING);
|
||||
if (r)
|
||||
dev_err(zd_mac_dev(mac), "zd_chip_control_leds error %d\n", r);
|
||||
|
||||
queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
|
||||
LINK_LED_WORK_DELAY);
|
||||
}
|
||||
|
||||
static void housekeeping_init(struct zd_mac *mac)
|
||||
{
|
||||
INIT_WORK(&mac->housekeeping.link_led_work, link_led_handler, mac);
|
||||
}
|
||||
|
||||
static void housekeeping_enable(struct zd_mac *mac)
|
||||
{
|
||||
dev_dbg_f(zd_mac_dev(mac), "\n");
|
||||
queue_delayed_work(zd_workqueue, &mac->housekeeping.link_led_work,
|
||||
0);
|
||||
}
|
||||
|
||||
static void housekeeping_disable(struct zd_mac *mac)
|
||||
{
|
||||
dev_dbg_f(zd_mac_dev(mac), "\n");
|
||||
cancel_rearming_delayed_workqueue(zd_workqueue,
|
||||
&mac->housekeeping.link_led_work);
|
||||
zd_chip_control_leds(&mac->chip, LED_OFF);
|
||||
}
|
||||
|
@ -120,6 +120,10 @@ enum mac_flags {
|
||||
MAC_FIXED_CHANNEL = 0x01,
|
||||
};
|
||||
|
||||
struct housekeeping {
|
||||
struct work_struct link_led_work;
|
||||
};
|
||||
|
||||
#define ZD_MAC_STATS_BUFFER_SIZE 16
|
||||
|
||||
struct zd_mac {
|
||||
@ -128,6 +132,7 @@ struct zd_mac {
|
||||
struct net_device *netdev;
|
||||
/* Unlocked reading possible */
|
||||
struct iw_statistics iw_stats;
|
||||
struct housekeeping housekeeping;
|
||||
unsigned int stats_count;
|
||||
u8 qual_buffer[ZD_MAC_STATS_BUFFER_SIZE];
|
||||
u8 rssi_buffer[ZD_MAC_STATS_BUFFER_SIZE];
|
||||
|
@ -82,7 +82,7 @@ static int iw_get_nick(struct net_device *netdev,
|
||||
union iwreq_data *req, char *extra)
|
||||
{
|
||||
strcpy(extra, "zd1211");
|
||||
req->data.length = strlen(extra) + 1;
|
||||
req->data.length = strlen(extra);
|
||||
req->data.flags = 1;
|
||||
return 0;
|
||||
}
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include <linux/errno.h>
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/usb.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <net/ieee80211.h>
|
||||
|
||||
#include "zd_def.h"
|
||||
@ -1112,12 +1113,20 @@ static struct usb_driver driver = {
|
||||
.disconnect = disconnect,
|
||||
};
|
||||
|
||||
struct workqueue_struct *zd_workqueue;
|
||||
|
||||
static int __init usb_init(void)
|
||||
{
|
||||
int r;
|
||||
|
||||
pr_debug("usb_init()\n");
|
||||
|
||||
zd_workqueue = create_singlethread_workqueue(driver.name);
|
||||
if (zd_workqueue == NULL) {
|
||||
printk(KERN_ERR "%s: couldn't create workqueue\n", driver.name);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
r = usb_register(&driver);
|
||||
if (r) {
|
||||
printk(KERN_ERR "usb_register() failed. Error number %d\n", r);
|
||||
@ -1132,6 +1141,7 @@ static void __exit usb_exit(void)
|
||||
{
|
||||
pr_debug("usb_exit()\n");
|
||||
usb_deregister(&driver);
|
||||
destroy_workqueue(zd_workqueue);
|
||||
}
|
||||
|
||||
module_init(usb_init);
|
||||
|
@ -238,4 +238,6 @@ int zd_usb_iowrite16v(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
|
||||
|
||||
int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits);
|
||||
|
||||
extern struct workqueue_struct *zd_workqueue;
|
||||
|
||||
#endif /* _ZD_USB_H */
|
||||
|
@ -11,95 +11,46 @@
|
||||
#ifndef __HDLC_H
|
||||
#define __HDLC_H
|
||||
|
||||
#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
|
||||
|
||||
#define CLOCK_DEFAULT 0 /* Default setting */
|
||||
#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
|
||||
#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
|
||||
#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
|
||||
#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
|
||||
|
||||
|
||||
#define ENCODING_DEFAULT 0 /* Default setting */
|
||||
#define ENCODING_NRZ 1
|
||||
#define ENCODING_NRZI 2
|
||||
#define ENCODING_FM_MARK 3
|
||||
#define ENCODING_FM_SPACE 4
|
||||
#define ENCODING_MANCHESTER 5
|
||||
|
||||
|
||||
#define PARITY_DEFAULT 0 /* Default setting */
|
||||
#define PARITY_NONE 1 /* No parity */
|
||||
#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
|
||||
#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
|
||||
#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
|
||||
#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
|
||||
#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
|
||||
#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
|
||||
|
||||
#define LMI_DEFAULT 0 /* Default setting */
|
||||
#define LMI_NONE 1 /* No LMI, all PVCs are static */
|
||||
#define LMI_ANSI 2 /* ANSI Annex D */
|
||||
#define LMI_CCITT 3 /* ITU-T Annex A */
|
||||
#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
|
||||
|
||||
#define HDLC_MAX_MTU 1500 /* Ethernet 1500 bytes */
|
||||
#if 0
|
||||
#define HDLC_MAX_MRU (HDLC_MAX_MTU + 10 + 14 + 4) /* for ETH+VLAN over FR */
|
||||
#else
|
||||
#define HDLC_MAX_MRU 1600 /* as required for FR network */
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef __KERNEL__
|
||||
|
||||
#include <linux/skbuff.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <net/syncppp.h>
|
||||
#include <linux/hdlc/ioctl.h>
|
||||
|
||||
|
||||
typedef struct { /* Used in Cisco and PPP mode */
|
||||
u8 address;
|
||||
u8 control;
|
||||
u16 protocol;
|
||||
}__attribute__ ((packed)) hdlc_header;
|
||||
|
||||
|
||||
|
||||
typedef struct {
|
||||
u32 type; /* code */
|
||||
u32 par1;
|
||||
u32 par2;
|
||||
u16 rel; /* reliability */
|
||||
u32 time;
|
||||
}__attribute__ ((packed)) cisco_packet;
|
||||
#define CISCO_PACKET_LEN 18
|
||||
#define CISCO_BIG_PACKET_LEN 20
|
||||
|
||||
|
||||
|
||||
typedef struct pvc_device_struct {
|
||||
struct net_device *master;
|
||||
struct net_device *main;
|
||||
struct net_device *ether; /* bridged Ethernet interface */
|
||||
struct pvc_device_struct *next; /* Sorted in ascending DLCI order */
|
||||
int dlci;
|
||||
int open_count;
|
||||
|
||||
struct {
|
||||
unsigned int new: 1;
|
||||
unsigned int active: 1;
|
||||
unsigned int exist: 1;
|
||||
unsigned int deleted: 1;
|
||||
unsigned int fecn: 1;
|
||||
unsigned int becn: 1;
|
||||
unsigned int bandwidth; /* Cisco LMI reporting only */
|
||||
}state;
|
||||
}pvc_device;
|
||||
|
||||
|
||||
|
||||
typedef struct hdlc_device_struct {
|
||||
/* To be initialized by hardware driver */
|
||||
/* Used by all network devices here, pointed to by netdev_priv(dev) */
|
||||
struct hdlc_device_desc {
|
||||
int (*netif_rx)(struct sk_buff *skb);
|
||||
struct net_device_stats stats;
|
||||
};
|
||||
|
||||
/* This structure is a private property of HDLC protocols.
|
||||
Hardware drivers have no interest here */
|
||||
|
||||
struct hdlc_proto {
|
||||
int (*open)(struct net_device *dev);
|
||||
void (*close)(struct net_device *dev);
|
||||
void (*start)(struct net_device *dev); /* if open & DCD */
|
||||
void (*stop)(struct net_device *dev); /* if open & !DCD */
|
||||
void (*detach)(struct net_device *dev);
|
||||
int (*ioctl)(struct net_device *dev, struct ifreq *ifr);
|
||||
unsigned short (*type_trans)(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
struct module *module;
|
||||
struct hdlc_proto *next; /* next protocol in the list */
|
||||
};
|
||||
|
||||
|
||||
typedef struct hdlc_device {
|
||||
/* used by HDLC layer to take control over HDLC device from hw driver*/
|
||||
int (*attach)(struct net_device *dev,
|
||||
unsigned short encoding, unsigned short parity);
|
||||
@ -107,82 +58,18 @@ typedef struct hdlc_device_struct {
|
||||
/* hardware driver must handle this instead of dev->hard_start_xmit */
|
||||
int (*xmit)(struct sk_buff *skb, struct net_device *dev);
|
||||
|
||||
|
||||
/* Things below are for HDLC layer internal use only */
|
||||
struct {
|
||||
int (*open)(struct net_device *dev);
|
||||
void (*close)(struct net_device *dev);
|
||||
|
||||
/* if open & DCD */
|
||||
void (*start)(struct net_device *dev);
|
||||
/* if open & !DCD */
|
||||
void (*stop)(struct net_device *dev);
|
||||
|
||||
void (*detach)(struct hdlc_device_struct *hdlc);
|
||||
int (*netif_rx)(struct sk_buff *skb);
|
||||
unsigned short (*type_trans)(struct sk_buff *skb,
|
||||
struct net_device *dev);
|
||||
int id; /* IF_PROTO_HDLC/CISCO/FR/etc. */
|
||||
}proto;
|
||||
|
||||
const struct hdlc_proto *proto;
|
||||
int carrier;
|
||||
int open;
|
||||
spinlock_t state_lock;
|
||||
|
||||
union {
|
||||
struct {
|
||||
fr_proto settings;
|
||||
pvc_device *first_pvc;
|
||||
int dce_pvc_count;
|
||||
|
||||
struct timer_list timer;
|
||||
unsigned long last_poll;
|
||||
int reliable;
|
||||
int dce_changed;
|
||||
int request;
|
||||
int fullrep_sent;
|
||||
u32 last_errors; /* last errors bit list */
|
||||
u8 n391cnt;
|
||||
u8 txseq; /* TX sequence number */
|
||||
u8 rxseq; /* RX sequence number */
|
||||
}fr;
|
||||
|
||||
struct {
|
||||
cisco_proto settings;
|
||||
|
||||
struct timer_list timer;
|
||||
unsigned long last_poll;
|
||||
int up;
|
||||
int request_sent;
|
||||
u32 txseq; /* TX sequence number */
|
||||
u32 rxseq; /* RX sequence number */
|
||||
}cisco;
|
||||
|
||||
struct {
|
||||
raw_hdlc_proto settings;
|
||||
}raw_hdlc;
|
||||
|
||||
struct {
|
||||
struct ppp_device pppdev;
|
||||
struct ppp_device *syncppp_ptr;
|
||||
int (*old_change_mtu)(struct net_device *dev,
|
||||
int new_mtu);
|
||||
}ppp;
|
||||
}state;
|
||||
void *state;
|
||||
void *priv;
|
||||
}hdlc_device;
|
||||
|
||||
|
||||
|
||||
int hdlc_raw_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
int hdlc_raw_eth_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
int hdlc_cisco_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
int hdlc_ppp_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
int hdlc_fr_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
int hdlc_x25_ioctl(struct net_device *dev, struct ifreq *ifr);
|
||||
|
||||
|
||||
/* Exported from hdlc.o */
|
||||
/* Exported from hdlc module */
|
||||
|
||||
/* Called by hardware driver when a user requests HDLC service */
|
||||
int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
@ -191,17 +78,21 @@ int hdlc_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
|
||||
#define register_hdlc_device(dev) register_netdev(dev)
|
||||
void unregister_hdlc_device(struct net_device *dev);
|
||||
|
||||
|
||||
void register_hdlc_protocol(struct hdlc_proto *proto);
|
||||
void unregister_hdlc_protocol(struct hdlc_proto *proto);
|
||||
|
||||
struct net_device *alloc_hdlcdev(void *priv);
|
||||
|
||||
static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
|
||||
|
||||
static __inline__ struct hdlc_device_desc* dev_to_desc(struct net_device *dev)
|
||||
{
|
||||
return netdev_priv(dev);
|
||||
}
|
||||
|
||||
|
||||
static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
|
||||
static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
|
||||
{
|
||||
return (pvc_device*)dev->priv;
|
||||
return netdev_priv(dev) + sizeof(struct hdlc_device_desc);
|
||||
}
|
||||
|
||||
|
||||
@ -225,18 +116,14 @@ int hdlc_open(struct net_device *dev);
|
||||
/* Must be called by hardware driver when HDLC device is being closed */
|
||||
void hdlc_close(struct net_device *dev);
|
||||
|
||||
int attach_hdlc_protocol(struct net_device *dev, struct hdlc_proto *proto,
|
||||
int (*rx)(struct sk_buff *skb), size_t size);
|
||||
/* May be used by hardware driver to gain control over HDLC device */
|
||||
static __inline__ void hdlc_proto_detach(hdlc_device *hdlc)
|
||||
{
|
||||
if (hdlc->proto.detach)
|
||||
hdlc->proto.detach(hdlc);
|
||||
hdlc->proto.detach = NULL;
|
||||
}
|
||||
|
||||
void detach_hdlc_protocol(struct net_device *dev);
|
||||
|
||||
static __inline__ struct net_device_stats *hdlc_stats(struct net_device *dev)
|
||||
{
|
||||
return &dev_to_hdlc(dev)->stats;
|
||||
return &dev_to_desc(dev)->stats;
|
||||
}
|
||||
|
||||
|
||||
@ -248,8 +135,8 @@ static __inline__ __be16 hdlc_type_trans(struct sk_buff *skb,
|
||||
skb->mac.raw = skb->data;
|
||||
skb->dev = dev;
|
||||
|
||||
if (hdlc->proto.type_trans)
|
||||
return hdlc->proto.type_trans(skb, dev);
|
||||
if (hdlc->proto->type_trans)
|
||||
return hdlc->proto->type_trans(skb, dev);
|
||||
else
|
||||
return htons(ETH_P_HDLC);
|
||||
}
|
||||
|
@ -1,6 +1,39 @@
|
||||
#ifndef __HDLC_IOCTL_H__
|
||||
#define __HDLC_IOCTL_H__
|
||||
|
||||
|
||||
#define GENERIC_HDLC_VERSION 4 /* For synchronization with sethdlc utility */
|
||||
|
||||
#define CLOCK_DEFAULT 0 /* Default setting */
|
||||
#define CLOCK_EXT 1 /* External TX and RX clock - DTE */
|
||||
#define CLOCK_INT 2 /* Internal TX and RX clock - DCE */
|
||||
#define CLOCK_TXINT 3 /* Internal TX and external RX clock */
|
||||
#define CLOCK_TXFROMRX 4 /* TX clock derived from external RX clock */
|
||||
|
||||
|
||||
#define ENCODING_DEFAULT 0 /* Default setting */
|
||||
#define ENCODING_NRZ 1
|
||||
#define ENCODING_NRZI 2
|
||||
#define ENCODING_FM_MARK 3
|
||||
#define ENCODING_FM_SPACE 4
|
||||
#define ENCODING_MANCHESTER 5
|
||||
|
||||
|
||||
#define PARITY_DEFAULT 0 /* Default setting */
|
||||
#define PARITY_NONE 1 /* No parity */
|
||||
#define PARITY_CRC16_PR0 2 /* CRC16, initial value 0x0000 */
|
||||
#define PARITY_CRC16_PR1 3 /* CRC16, initial value 0xFFFF */
|
||||
#define PARITY_CRC16_PR0_CCITT 4 /* CRC16, initial 0x0000, ITU-T version */
|
||||
#define PARITY_CRC16_PR1_CCITT 5 /* CRC16, initial 0xFFFF, ITU-T version */
|
||||
#define PARITY_CRC32_PR0_CCITT 6 /* CRC32, initial value 0x00000000 */
|
||||
#define PARITY_CRC32_PR1_CCITT 7 /* CRC32, initial value 0xFFFFFFFF */
|
||||
|
||||
#define LMI_DEFAULT 0 /* Default setting */
|
||||
#define LMI_NONE 1 /* No LMI, all PVCs are static */
|
||||
#define LMI_ANSI 2 /* ANSI Annex D */
|
||||
#define LMI_CCITT 3 /* ITU-T Annex A */
|
||||
#define LMI_CISCO 4 /* The "original" LMI, aka Gang of Four */
|
||||
|
||||
typedef struct {
|
||||
unsigned int clock_rate; /* bits per second */
|
||||
unsigned int clock_type; /* internal, external, TX-internal etc. */
|
||||
|
@ -59,6 +59,8 @@
|
||||
#define IFF_SLAVE_INACTIVE 0x4 /* bonding slave not the curr. active */
|
||||
#define IFF_MASTER_8023AD 0x8 /* bonding master, 802.3ad. */
|
||||
#define IFF_MASTER_ALB 0x10 /* bonding master, balance-alb. */
|
||||
#define IFF_BONDING 0x20 /* bonding master or slave */
|
||||
#define IFF_SLAVE_NEEDARP 0x40 /* need ARPs for validation */
|
||||
|
||||
#define IF_GET_IFACE 0x0001 /* for querying only */
|
||||
#define IF_GET_PROTO 0x0002
|
||||
|
@ -334,7 +334,6 @@ struct net_device
|
||||
|
||||
|
||||
struct net_device_stats* (*get_stats)(struct net_device *dev);
|
||||
struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
|
||||
|
||||
/* List of functions to handle Wireless Extensions (instead of ioctl).
|
||||
* See <net/iw_handler.h> for details. Jean II */
|
||||
@ -1016,7 +1015,8 @@ static inline int netif_needs_gso(struct net_device *dev, struct sk_buff *skb)
|
||||
}
|
||||
|
||||
/* On bonding slaves other than the currently active slave, suppress
|
||||
* duplicates except for 802.3ad ETH_P_SLOW and alb non-mcast/bcast.
|
||||
* duplicates except for 802.3ad ETH_P_SLOW, alb non-mcast/bcast, and
|
||||
* ARP on active-backup slaves with arp_validate enabled.
|
||||
*/
|
||||
static inline int skb_bond_should_drop(struct sk_buff *skb)
|
||||
{
|
||||
@ -1025,6 +1025,10 @@ static inline int skb_bond_should_drop(struct sk_buff *skb)
|
||||
|
||||
if (master &&
|
||||
(dev->priv_flags & IFF_SLAVE_INACTIVE)) {
|
||||
if ((dev->priv_flags & IFF_SLAVE_NEEDARP) &&
|
||||
skb->protocol == __constant_htons(ETH_P_ARP))
|
||||
return 0;
|
||||
|
||||
if (master->priv_flags & IFF_MASTER_ALB) {
|
||||
if (skb->pkt_type != PACKET_BROADCAST &&
|
||||
skb->pkt_type != PACKET_MULTICAST)
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* This file define a set of standard wireless extensions
|
||||
*
|
||||
* Version : 20 17.2.06
|
||||
* Version : 21 14.3.06
|
||||
*
|
||||
* Authors : Jean Tourrilhes - HPL - <jt@hpl.hp.com>
|
||||
* Copyright (c) 1997-2006 Jean Tourrilhes, All Rights Reserved.
|
||||
@ -69,9 +69,14 @@
|
||||
|
||||
/***************************** INCLUDES *****************************/
|
||||
|
||||
/* This header is used in user-space, therefore need to be sanitised
|
||||
* for that purpose. Those includes are usually not compatible with glibc.
|
||||
* To know which includes to use in user-space, check iwlib.h. */
|
||||
#ifdef __KERNEL__
|
||||
#include <linux/types.h> /* for "caddr_t" et al */
|
||||
#include <linux/socket.h> /* for "struct sockaddr" et al */
|
||||
#include <linux/if.h> /* for IFNAMSIZ and co... */
|
||||
#endif /* __KERNEL__ */
|
||||
|
||||
/***************************** VERSION *****************************/
|
||||
/*
|
||||
@ -80,7 +85,7 @@
|
||||
* (there is some stuff that will be added in the future...)
|
||||
* I just plan to increment with each new version.
|
||||
*/
|
||||
#define WIRELESS_EXT 20
|
||||
#define WIRELESS_EXT 21
|
||||
|
||||
/*
|
||||
* Changes :
|
||||
@ -208,6 +213,14 @@
|
||||
* V19 to V20
|
||||
* ----------
|
||||
* - RtNetlink requests support (SET/GET)
|
||||
*
|
||||
* V20 to V21
|
||||
* ----------
|
||||
* - Remove (struct net_device *)->get_wireless_stats()
|
||||
* - Change length in ESSID and NICK to strlen() instead of strlen()+1
|
||||
* - Add IW_RETRY_SHORT/IW_RETRY_LONG retry modifiers
|
||||
* - Power/Retry relative values no longer * 100000
|
||||
* - Add explicit flag to tell stats are in 802.11k RCPI : IW_QUAL_RCPI
|
||||
*/
|
||||
|
||||
/**************************** CONSTANTS ****************************/
|
||||
@ -448,6 +461,7 @@
|
||||
#define IW_QUAL_QUAL_INVALID 0x10 /* Driver doesn't provide value */
|
||||
#define IW_QUAL_LEVEL_INVALID 0x20
|
||||
#define IW_QUAL_NOISE_INVALID 0x40
|
||||
#define IW_QUAL_RCPI 0x80 /* Level + Noise are 802.11k RCPI */
|
||||
#define IW_QUAL_ALL_INVALID 0x70
|
||||
|
||||
/* Frequency flags */
|
||||
@ -500,10 +514,12 @@
|
||||
#define IW_RETRY_TYPE 0xF000 /* Type of parameter */
|
||||
#define IW_RETRY_LIMIT 0x1000 /* Maximum number of retries*/
|
||||
#define IW_RETRY_LIFETIME 0x2000 /* Maximum duration of retries in us */
|
||||
#define IW_RETRY_MODIFIER 0x000F /* Modify a parameter */
|
||||
#define IW_RETRY_MODIFIER 0x00FF /* Modify a parameter */
|
||||
#define IW_RETRY_MIN 0x0001 /* Value is a minimum */
|
||||
#define IW_RETRY_MAX 0x0002 /* Value is a maximum */
|
||||
#define IW_RETRY_RELATIVE 0x0004 /* Value is not in seconds/ms/us */
|
||||
#define IW_RETRY_SHORT 0x0010 /* Value is for short packets */
|
||||
#define IW_RETRY_LONG 0x0020 /* Value is for long packets */
|
||||
|
||||
/* Scanning request flags */
|
||||
#define IW_SCAN_DEFAULT 0x0000 /* Default scan of the driver */
|
||||
@ -1017,7 +1033,7 @@ struct iw_range
|
||||
/* Note : this frequency list doesn't need to fit channel numbers,
|
||||
* because each entry contain its channel index */
|
||||
|
||||
__u32 enc_capa; /* IW_ENC_CAPA_* bit field */
|
||||
__u32 enc_capa; /* IW_ENC_CAPA_* bit field */
|
||||
};
|
||||
|
||||
/*
|
||||
|
@ -344,8 +344,6 @@ static ssize_t wireless_show(struct class_device *cd, char *buf,
|
||||
if(dev->wireless_handlers &&
|
||||
dev->wireless_handlers->get_wireless_stats)
|
||||
iw = dev->wireless_handlers->get_wireless_stats(dev);
|
||||
else if (dev->get_wireless_stats)
|
||||
iw = dev->get_wireless_stats(dev);
|
||||
if (iw != NULL)
|
||||
ret = (*format)(iw, buf);
|
||||
}
|
||||
@ -465,8 +463,7 @@ int netdev_register_sysfs(struct net_device *net)
|
||||
*groups++ = &netstat_group;
|
||||
|
||||
#ifdef WIRELESS_EXT
|
||||
if (net->get_wireless_stats
|
||||
|| (net->wireless_handlers && net->wireless_handlers->get_wireless_stats))
|
||||
if (net->wireless_handlers && net->wireless_handlers->get_wireless_stats)
|
||||
*groups++ = &wireless_group;
|
||||
#endif
|
||||
|
||||
|
@ -68,6 +68,14 @@
|
||||
*
|
||||
* v8 - 17.02.06 - Jean II
|
||||
* o RtNetlink requests support (SET/GET)
|
||||
*
|
||||
* v8b - 03.08.06 - Herbert Xu
|
||||
* o Fix Wireless Event locking issues.
|
||||
*
|
||||
* v9 - 14.3.06 - Jean II
|
||||
* o Change length in ESSID and NICK to strlen() instead of strlen()+1
|
||||
* o Make standard_ioctl_num and standard_event_num unsigned
|
||||
* o Remove (struct net_device *)->get_wireless_stats()
|
||||
*/
|
||||
|
||||
/***************************** INCLUDES *****************************/
|
||||
@ -234,24 +242,24 @@ static const struct iw_ioctl_description standard_ioctl[] = {
|
||||
[SIOCSIWESSID - SIOCIWFIRST] = {
|
||||
.header_type = IW_HEADER_TYPE_POINT,
|
||||
.token_size = 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE + 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE,
|
||||
.flags = IW_DESCR_FLAG_EVENT,
|
||||
},
|
||||
[SIOCGIWESSID - SIOCIWFIRST] = {
|
||||
.header_type = IW_HEADER_TYPE_POINT,
|
||||
.token_size = 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE + 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE,
|
||||
.flags = IW_DESCR_FLAG_DUMP,
|
||||
},
|
||||
[SIOCSIWNICKN - SIOCIWFIRST] = {
|
||||
.header_type = IW_HEADER_TYPE_POINT,
|
||||
.token_size = 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE + 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE,
|
||||
},
|
||||
[SIOCGIWNICKN - SIOCIWFIRST] = {
|
||||
.header_type = IW_HEADER_TYPE_POINT,
|
||||
.token_size = 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE + 1,
|
||||
.max_tokens = IW_ESSID_MAX_SIZE,
|
||||
},
|
||||
[SIOCSIWRATE - SIOCIWFIRST] = {
|
||||
.header_type = IW_HEADER_TYPE_PARAM,
|
||||
@ -338,8 +346,8 @@ static const struct iw_ioctl_description standard_ioctl[] = {
|
||||
.max_tokens = sizeof(struct iw_pmksa),
|
||||
},
|
||||
};
|
||||
static const int standard_ioctl_num = (sizeof(standard_ioctl) /
|
||||
sizeof(struct iw_ioctl_description));
|
||||
static const unsigned standard_ioctl_num = (sizeof(standard_ioctl) /
|
||||
sizeof(struct iw_ioctl_description));
|
||||
|
||||
/*
|
||||
* Meta-data about all the additional standard Wireless Extension events
|
||||
@ -389,8 +397,8 @@ static const struct iw_ioctl_description standard_event[] = {
|
||||
.max_tokens = sizeof(struct iw_pmkid_cand),
|
||||
},
|
||||
};
|
||||
static const int standard_event_num = (sizeof(standard_event) /
|
||||
sizeof(struct iw_ioctl_description));
|
||||
static const unsigned standard_event_num = (sizeof(standard_event) /
|
||||
sizeof(struct iw_ioctl_description));
|
||||
|
||||
/* Size (in bytes) of the various private data types */
|
||||
static const char iw_priv_type_size[] = {
|
||||
@ -465,17 +473,6 @@ static inline struct iw_statistics *get_wireless_stats(struct net_device *dev)
|
||||
(dev->wireless_handlers->get_wireless_stats != NULL))
|
||||
return dev->wireless_handlers->get_wireless_stats(dev);
|
||||
|
||||
/* Old location, field to be removed in next WE */
|
||||
if(dev->get_wireless_stats) {
|
||||
static int printed_message;
|
||||
|
||||
if (!printed_message++)
|
||||
printk(KERN_DEBUG "%s (WE) : Driver using old /proc/net/wireless support, please fix driver !\n",
|
||||
dev->name);
|
||||
|
||||
return dev->get_wireless_stats(dev);
|
||||
}
|
||||
|
||||
/* Not found */
|
||||
return (struct iw_statistics *) NULL;
|
||||
}
|
||||
@ -1843,8 +1840,33 @@ int wireless_rtnetlink_set(struct net_device * dev,
|
||||
*/
|
||||
|
||||
#ifdef WE_EVENT_RTNETLINK
|
||||
/* ---------------------------------------------------------------- */
|
||||
/*
|
||||
* Locking...
|
||||
* ----------
|
||||
*
|
||||
* Thanks to Herbert Xu <herbert@gondor.apana.org.au> for fixing
|
||||
* the locking issue in here and implementing this code !
|
||||
*
|
||||
* The issue : wireless_send_event() is often called in interrupt context,
|
||||
* while the Netlink layer can never be called in interrupt context.
|
||||
* The fully formed RtNetlink events are queued, and then a tasklet is run
|
||||
* to feed those to Netlink.
|
||||
* The skb_queue is interrupt safe, and its lock is not held while calling
|
||||
* Netlink, so there is no possibility of dealock.
|
||||
* Jean II
|
||||
*/
|
||||
|
||||
static struct sk_buff_head wireless_nlevent_queue;
|
||||
|
||||
static int __init wireless_nlevent_init(void)
|
||||
{
|
||||
skb_queue_head_init(&wireless_nlevent_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(wireless_nlevent_init);
|
||||
|
||||
static void wireless_nlevent_process(unsigned long data)
|
||||
{
|
||||
struct sk_buff *skb;
|
||||
@ -1921,13 +1943,6 @@ static inline void rtmsg_iwinfo(struct net_device * dev,
|
||||
tasklet_schedule(&wireless_nlevent_tasklet);
|
||||
}
|
||||
|
||||
static int __init wireless_nlevent_init(void)
|
||||
{
|
||||
skb_queue_head_init(&wireless_nlevent_queue);
|
||||
return 0;
|
||||
}
|
||||
|
||||
subsys_initcall(wireless_nlevent_init);
|
||||
#endif /* WE_EVENT_RTNETLINK */
|
||||
|
||||
/* ---------------------------------------------------------------- */
|
||||
|
@ -80,10 +80,10 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
|
||||
* If it's our network, ignore the change, we're already doing it!
|
||||
*/
|
||||
if((sm->associnfo.associating || sm->associated) &&
|
||||
(data->essid.flags && data->essid.length && extra)) {
|
||||
(data->essid.flags && data->essid.length)) {
|
||||
/* Get the associating network */
|
||||
n = ieee80211softmac_get_network_by_bssid(sm, sm->associnfo.bssid);
|
||||
if(n && n->essid.len == (data->essid.length - 1) &&
|
||||
if(n && n->essid.len == data->essid.length &&
|
||||
!memcmp(n->essid.data, extra, n->essid.len)) {
|
||||
dprintk(KERN_INFO PFX "Already associating or associated to "MAC_FMT"\n",
|
||||
MAC_ARG(sm->associnfo.bssid));
|
||||
@ -109,8 +109,8 @@ ieee80211softmac_wx_set_essid(struct net_device *net_dev,
|
||||
sm->associnfo.static_essid = 0;
|
||||
sm->associnfo.assoc_wait = 0;
|
||||
|
||||
if (data->essid.flags && data->essid.length && extra /*required?*/) {
|
||||
length = min(data->essid.length - 1, IW_ESSID_MAX_SIZE);
|
||||
if (data->essid.flags && data->essid.length) {
|
||||
length = min((int)data->essid.length, IW_ESSID_MAX_SIZE);
|
||||
if (length) {
|
||||
memcpy(sm->associnfo.req_essid.data, extra, length);
|
||||
sm->associnfo.static_essid = 1;
|
||||
|
Loading…
Reference in New Issue
Block a user