Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6
* git://git.kernel.org/pub/scm/linux/kernel/git/davem/net-2.6: (25 commits) smc91c92_cs: define multicast_table as unsigned char can: avoids a false warning e1000e: stop cleaning when we reach tx_ring->next_to_use igb: restrict WoL for 82576 ET2 Quad Port Server Adapter virtio_net: missing sg_init_table Revert "tcp: Set CHECKSUM_UNNECESSARY in tcp_init_nondata_skb" iwlwifi: need check for valid qos packet before free tcp: Set CHECKSUM_UNNECESSARY in tcp_init_nondata_skb udp: fix for unicast RX path optimization myri10ge: fix rx_pause in myri10ge_set_pauseparam net: corrected documentation for hardware time stamping stmmac: use resource_size() x.25 attempts to negotiate invalid throughput x25: Patch to fix bug 15678 - x25 accesses fields beyond end of packet. bridge: Fix IGMP3 report parsing cnic: Fix crash during bnx2x MTU change. qlcnic: fix set mac addr r6040: fix r6040_multicast_list vhost-net: fix vq_memory_access_ok error checking ath9k: fix double calls to ath_radio_enable ...
This commit is contained in:
commit
465de2ba71
30 changed files with 348 additions and 138 deletions
|
@ -41,11 +41,12 @@ SOF_TIMESTAMPING_SOFTWARE: return system time stamp generated in
|
|||
SOF_TIMESTAMPING_TX/RX determine how time stamps are generated.
|
||||
SOF_TIMESTAMPING_RAW/SYS determine how they are reported in the
|
||||
following control message:
|
||||
struct scm_timestamping {
|
||||
struct timespec systime;
|
||||
struct timespec hwtimetrans;
|
||||
struct timespec hwtimeraw;
|
||||
};
|
||||
|
||||
struct scm_timestamping {
|
||||
struct timespec systime;
|
||||
struct timespec hwtimetrans;
|
||||
struct timespec hwtimeraw;
|
||||
};
|
||||
|
||||
recvmsg() can be used to get this control message for regular incoming
|
||||
packets. For send time stamps the outgoing packet is looped back to
|
||||
|
@ -87,12 +88,13 @@ by the network device and will be empty without that support.
|
|||
SIOCSHWTSTAMP:
|
||||
|
||||
Hardware time stamping must also be initialized for each device driver
|
||||
that is expected to do hardware time stamping. The parameter is:
|
||||
that is expected to do hardware time stamping. The parameter is defined in
|
||||
/include/linux/net_tstamp.h as:
|
||||
|
||||
struct hwtstamp_config {
|
||||
int flags; /* no flags defined right now, must be zero */
|
||||
int tx_type; /* HWTSTAMP_TX_* */
|
||||
int rx_filter; /* HWTSTAMP_FILTER_* */
|
||||
int flags; /* no flags defined right now, must be zero */
|
||||
int tx_type; /* HWTSTAMP_TX_* */
|
||||
int rx_filter; /* HWTSTAMP_FILTER_* */
|
||||
};
|
||||
|
||||
Desired behavior is passed into the kernel and to a specific device by
|
||||
|
@ -139,42 +141,56 @@ enum {
|
|||
/* time stamp any incoming packet */
|
||||
HWTSTAMP_FILTER_ALL,
|
||||
|
||||
/* return value: time stamp all packets requested plus some others */
|
||||
HWTSTAMP_FILTER_SOME,
|
||||
/* return value: time stamp all packets requested plus some others */
|
||||
HWTSTAMP_FILTER_SOME,
|
||||
|
||||
/* PTP v1, UDP, any kind of event packet */
|
||||
HWTSTAMP_FILTER_PTP_V1_L4_EVENT,
|
||||
|
||||
...
|
||||
/* for the complete list of values, please check
|
||||
* the include file /include/linux/net_tstamp.h
|
||||
*/
|
||||
};
|
||||
|
||||
|
||||
DEVICE IMPLEMENTATION
|
||||
|
||||
A driver which supports hardware time stamping must support the
|
||||
SIOCSHWTSTAMP ioctl. Time stamps for received packets must be stored
|
||||
in the skb with skb_hwtstamp_set().
|
||||
SIOCSHWTSTAMP ioctl and update the supplied struct hwtstamp_config with
|
||||
the actual values as described in the section on SIOCSHWTSTAMP.
|
||||
|
||||
Time stamps for received packets must be stored in the skb. To get a pointer
|
||||
to the shared time stamp structure of the skb call skb_hwtstamps(). Then
|
||||
set the time stamps in the structure:
|
||||
|
||||
struct skb_shared_hwtstamps {
|
||||
/* hardware time stamp transformed into duration
|
||||
* since arbitrary point in time
|
||||
*/
|
||||
ktime_t hwtstamp;
|
||||
ktime_t syststamp; /* hwtstamp transformed to system time base */
|
||||
};
|
||||
|
||||
Time stamps for outgoing packets are to be generated as follows:
|
||||
- In hard_start_xmit(), check if skb_hwtstamp_check_tx_hardware()
|
||||
returns non-zero. If yes, then the driver is expected
|
||||
to do hardware time stamping.
|
||||
- In hard_start_xmit(), check if skb_tx(skb)->hardware is set no-zero.
|
||||
If yes, then the driver is expected to do hardware time stamping.
|
||||
- If this is possible for the skb and requested, then declare
|
||||
that the driver is doing the time stamping by calling
|
||||
skb_hwtstamp_tx_in_progress(). A driver not supporting
|
||||
hardware time stamping doesn't do that. A driver must never
|
||||
touch sk_buff::tstamp! It is used to store how time stamping
|
||||
for an outgoing packets is to be done.
|
||||
that the driver is doing the time stamping by setting the field
|
||||
skb_tx(skb)->in_progress non-zero. You might want to keep a pointer
|
||||
to the associated skb for the next step and not free the skb. A driver
|
||||
not supporting hardware time stamping doesn't do that. A driver must
|
||||
never touch sk_buff::tstamp! It is used to store software generated
|
||||
time stamps by the network subsystem.
|
||||
- As soon as the driver has sent the packet and/or obtained a
|
||||
hardware time stamp for it, it passes the time stamp back by
|
||||
calling skb_hwtstamp_tx() with the original skb, the raw
|
||||
hardware time stamp and a handle to the device (necessary
|
||||
to convert the hardware time stamp to system time). If obtaining
|
||||
the hardware time stamp somehow fails, then the driver should
|
||||
not fall back to software time stamping. The rationale is that
|
||||
this would occur at a later time in the processing pipeline
|
||||
than other software time stamping and therefore could lead
|
||||
to unexpected deltas between time stamps.
|
||||
- If the driver did not call skb_hwtstamp_tx_in_progress(), then
|
||||
hardware time stamp. skb_hwtstamp_tx() clones the original skb and
|
||||
adds the timestamps, therefore the original skb has to be freed now.
|
||||
If obtaining the hardware time stamp somehow fails, then the driver
|
||||
should not fall back to software time stamping. The rationale is that
|
||||
this would occur at a later time in the processing pipeline than other
|
||||
software time stamping and therefore could lead to unexpected deltas
|
||||
between time stamps.
|
||||
- If the driver did not call set skb_tx(skb)->in_progress, then
|
||||
dev_hard_start_xmit() checks whether software time stamping
|
||||
is wanted as fallback and potentially generates the time stamp.
|
||||
|
|
|
@ -2334,13 +2334,13 @@ static int cnic_service_bnx2x(void *data, void *status_blk)
|
|||
struct cnic_local *cp = dev->cnic_priv;
|
||||
u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
|
||||
|
||||
prefetch(cp->status_blk.bnx2x);
|
||||
prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
|
||||
if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags))) {
|
||||
prefetch(cp->status_blk.bnx2x);
|
||||
prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
|
||||
|
||||
if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
|
||||
tasklet_schedule(&cp->cnic_irq_task);
|
||||
|
||||
cnic_chk_pkt_rings(cp);
|
||||
cnic_chk_pkt_rings(cp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -661,6 +661,8 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
|
|||
i = 0;
|
||||
}
|
||||
|
||||
if (i == tx_ring->next_to_use)
|
||||
break;
|
||||
eop = tx_ring->buffer_info[i].next_to_watch;
|
||||
eop_desc = E1000_TX_DESC(*tx_ring, eop);
|
||||
}
|
||||
|
|
|
@ -1814,6 +1814,7 @@ static int igb_wol_exclusion(struct igb_adapter *adapter,
|
|||
retval = 0;
|
||||
break;
|
||||
case E1000_DEV_ID_82576_QUAD_COPPER:
|
||||
case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
|
||||
/* quad port adapters only support WoL on port A */
|
||||
if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) {
|
||||
wol->supported = 0;
|
||||
|
|
|
@ -1612,6 +1612,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
|
|||
adapter->eeprom_wol = 0;
|
||||
break;
|
||||
case E1000_DEV_ID_82576_QUAD_COPPER:
|
||||
case E1000_DEV_ID_82576_QUAD_COPPER_ET2:
|
||||
/* if quad port adapter, disable WoL on all but port A */
|
||||
if (global_quad_port_a != 0)
|
||||
adapter->eeprom_wol = 0;
|
||||
|
|
|
@ -1690,7 +1690,7 @@ myri10ge_set_pauseparam(struct net_device *netdev,
|
|||
if (pause->tx_pause != mgp->pause)
|
||||
return myri10ge_change_pause(mgp, pause->tx_pause);
|
||||
if (pause->rx_pause != mgp->pause)
|
||||
return myri10ge_change_pause(mgp, pause->tx_pause);
|
||||
return myri10ge_change_pause(mgp, pause->rx_pause);
|
||||
if (pause->autoneg != 0)
|
||||
return -EINVAL;
|
||||
return 0;
|
||||
|
|
|
@ -1608,9 +1608,12 @@ static void set_rx_mode(struct net_device *dev)
|
|||
{
|
||||
unsigned int ioaddr = dev->base_addr;
|
||||
struct smc_private *smc = netdev_priv(dev);
|
||||
u_int multicast_table[ 2 ] = { 0, };
|
||||
unsigned char multicast_table[8];
|
||||
unsigned long flags;
|
||||
u_short rx_cfg_setting;
|
||||
int i;
|
||||
|
||||
memset(multicast_table, 0, sizeof(multicast_table));
|
||||
|
||||
if (dev->flags & IFF_PROMISC) {
|
||||
rx_cfg_setting = RxStripCRC | RxEnable | RxPromisc | RxAllMulti;
|
||||
|
@ -1622,10 +1625,6 @@ static void set_rx_mode(struct net_device *dev)
|
|||
|
||||
netdev_for_each_mc_addr(mc_addr, dev) {
|
||||
u_int position = ether_crc(6, mc_addr->dmi_addr);
|
||||
#ifndef final_version /* Verify multicast address. */
|
||||
if ((mc_addr->dmi_addr[0] & 1) == 0)
|
||||
continue;
|
||||
#endif
|
||||
multicast_table[position >> 29] |= 1 << ((position >> 26) & 7);
|
||||
}
|
||||
}
|
||||
|
@ -1635,8 +1634,8 @@ static void set_rx_mode(struct net_device *dev)
|
|||
/* Load MC table and Rx setting into the chip without interrupts. */
|
||||
spin_lock_irqsave(&smc->lock, flags);
|
||||
SMC_SELECT_BANK(3);
|
||||
outl(multicast_table[0], ioaddr + MULTICAST0);
|
||||
outl(multicast_table[1], ioaddr + MULTICAST4);
|
||||
for (i = 0; i < 8; i++)
|
||||
outb(multicast_table[i], ioaddr + MULTICAST0 + i);
|
||||
SMC_SELECT_BANK(0);
|
||||
outw(rx_cfg_setting, ioaddr + RCR);
|
||||
SMC_SELECT_BANK(2);
|
||||
|
|
|
@ -431,6 +431,9 @@ void qlcnic_set_multi(struct net_device *netdev)
|
|||
u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
|
||||
u32 mode = VPORT_MISS_MODE_DROP;
|
||||
|
||||
if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
|
||||
return;
|
||||
|
||||
qlcnic_nic_add_mac(adapter, adapter->mac_addr);
|
||||
qlcnic_nic_add_mac(adapter, bcast_addr);
|
||||
|
||||
|
|
|
@ -134,7 +134,7 @@
|
|||
#define RX_DESC_SIZE (RX_DCNT * sizeof(struct r6040_descriptor))
|
||||
#define TX_DESC_SIZE (TX_DCNT * sizeof(struct r6040_descriptor))
|
||||
#define MBCR_DEFAULT 0x012A /* MAC Bus Control Register */
|
||||
#define MCAST_MAX 4 /* Max number multicast addresses to filter */
|
||||
#define MCAST_MAX 3 /* Max number multicast addresses to filter */
|
||||
|
||||
/* Descriptor status */
|
||||
#define DSC_OWNER_MAC 0x8000 /* MAC is the owner of this descriptor */
|
||||
|
@ -982,9 +982,6 @@ static void r6040_multicast_list(struct net_device *dev)
|
|||
crc >>= 26;
|
||||
hash_table[crc >> 4] |= 1 << (15 - (crc & 0xf));
|
||||
}
|
||||
/* Write the index of the hash table */
|
||||
for (i = 0; i < 4; i++)
|
||||
iowrite16(hash_table[i] << 14, ioaddr + MCR1);
|
||||
/* Fill the MAC hash tables with their values */
|
||||
iowrite16(hash_table[0], ioaddr + MAR0);
|
||||
iowrite16(hash_table[1], ioaddr + MAR1);
|
||||
|
@ -1000,9 +997,9 @@ static void r6040_multicast_list(struct net_device *dev)
|
|||
iowrite16(adrp[1], ioaddr + MID_1M + 8 * i);
|
||||
iowrite16(adrp[2], ioaddr + MID_1H + 8 * i);
|
||||
} else {
|
||||
iowrite16(0xffff, ioaddr + MID_0L + 8 * i);
|
||||
iowrite16(0xffff, ioaddr + MID_0M + 8 * i);
|
||||
iowrite16(0xffff, ioaddr + MID_0H + 8 * i);
|
||||
iowrite16(0xffff, ioaddr + MID_1L + 8 * i);
|
||||
iowrite16(0xffff, ioaddr + MID_1M + 8 * i);
|
||||
iowrite16(0xffff, ioaddr + MID_1H + 8 * i);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
|
|
@ -1686,7 +1686,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
|
|||
}
|
||||
pr_info("done!\n");
|
||||
|
||||
if (!request_mem_region(res->start, (res->end - res->start),
|
||||
if (!request_mem_region(res->start, resource_size(res),
|
||||
pdev->name)) {
|
||||
pr_err("%s: ERROR: memory allocation failed"
|
||||
"cannot get the I/O addr 0x%x\n",
|
||||
|
@ -1695,9 +1695,9 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
|
|||
goto out;
|
||||
}
|
||||
|
||||
addr = ioremap(res->start, (res->end - res->start));
|
||||
addr = ioremap(res->start, resource_size(res));
|
||||
if (!addr) {
|
||||
pr_err("%s: ERROR: memory mapping failed \n", __func__);
|
||||
pr_err("%s: ERROR: memory mapping failed\n", __func__);
|
||||
ret = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
|
@ -1775,7 +1775,7 @@ static int stmmac_dvr_probe(struct platform_device *pdev)
|
|||
out:
|
||||
if (ret < 0) {
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
release_mem_region(res->start, (res->end - res->start));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
if (addr != NULL)
|
||||
iounmap(addr);
|
||||
}
|
||||
|
@ -1813,7 +1813,7 @@ static int stmmac_dvr_remove(struct platform_device *pdev)
|
|||
|
||||
iounmap((void *)ndev->base_addr);
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
release_mem_region(res->start, (res->end - res->start));
|
||||
release_mem_region(res->start, resource_size(res));
|
||||
|
||||
free_netdev(ndev);
|
||||
|
||||
|
|
|
@ -327,6 +327,7 @@ static int add_recvbuf_small(struct virtnet_info *vi, gfp_t gfp)
|
|||
struct scatterlist sg[2];
|
||||
int err;
|
||||
|
||||
sg_init_table(sg, 2);
|
||||
skb = netdev_alloc_skb_ip_align(vi->dev, MAX_PACKET_LEN);
|
||||
if (unlikely(!skb))
|
||||
return -ENOMEM;
|
||||
|
@ -352,6 +353,7 @@ static int add_recvbuf_big(struct virtnet_info *vi, gfp_t gfp)
|
|||
char *p;
|
||||
int i, err, offset;
|
||||
|
||||
sg_init_table(sg, MAX_SKB_FRAGS + 2);
|
||||
/* page in sg[MAX_SKB_FRAGS + 1] is list tail */
|
||||
for (i = MAX_SKB_FRAGS + 1; i > 1; --i) {
|
||||
first = get_a_page(vi, gfp);
|
||||
|
|
|
@ -1532,8 +1532,7 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
|
|||
all_wiphys_idle = ath9k_all_wiphys_idle(sc);
|
||||
ath9k_set_wiphy_idle(aphy, idle);
|
||||
|
||||
if (!idle && all_wiphys_idle)
|
||||
enable_radio = true;
|
||||
enable_radio = (!idle && all_wiphys_idle);
|
||||
|
||||
/*
|
||||
* After we unlock here its possible another wiphy
|
||||
|
|
|
@ -2015,7 +2015,9 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
|||
IWL_DEBUG_TX_REPLY(priv, "Retry scheduler reclaim scd_ssn "
|
||||
"%d index %d\n", scd_ssn , index);
|
||||
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
|
||||
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
|
||||
if (qc)
|
||||
iwl_free_tfds_in_queue(priv, sta_id,
|
||||
tid, freed);
|
||||
|
||||
if (priv->mac80211_registered &&
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark) &&
|
||||
|
@ -2041,14 +2043,17 @@ static void iwl4965_rx_reply_tx(struct iwl_priv *priv,
|
|||
tx_resp->failure_frame);
|
||||
|
||||
freed = iwl_tx_queue_reclaim(priv, txq_id, index);
|
||||
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
|
||||
if (qc && likely(sta_id != IWL_INVALID_STATION))
|
||||
iwl_free_tfds_in_queue(priv, sta_id, tid, freed);
|
||||
else if (sta_id == IWL_INVALID_STATION)
|
||||
IWL_DEBUG_TX_REPLY(priv, "Station not known\n");
|
||||
|
||||
if (priv->mac80211_registered &&
|
||||
(iwl_queue_space(&txq->q) > txq->q.low_mark))
|
||||
iwl_wake_queue(priv, txq_id);
|
||||
}
|
||||
|
||||
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
|
||||
if (qc && likely(sta_id != IWL_INVALID_STATION))
|
||||
iwl_txq_check_empty(priv, sta_id, tid, txq_id);
|
||||
|
||||
if (iwl_check_bits(status, TX_ABORT_REQUIRED_MSK))
|
||||
IWL_ERR(priv, "TODO: Implement Tx ABORT REQUIRED!!!\n");
|
||||
|
|
|
@ -346,6 +346,17 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
|
|||
!!(rate_n_flags & RATE_MCS_ANT_C_MSK);
|
||||
}
|
||||
|
||||
/*
|
||||
* Static function to get the expected throughput from an iwl_scale_tbl_info
|
||||
* that wraps a NULL pointer check
|
||||
*/
|
||||
static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
|
||||
{
|
||||
if (tbl->expected_tpt)
|
||||
return tbl->expected_tpt[rs_index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* rs_collect_tx_data - Update the success/failure sliding window
|
||||
*
|
||||
|
@ -353,19 +364,21 @@ static inline int get_num_of_ant_from_rate(u32 rate_n_flags)
|
|||
* at this rate. window->data contains the bitmask of successful
|
||||
* packets.
|
||||
*/
|
||||
static int rs_collect_tx_data(struct iwl_rate_scale_data *windows,
|
||||
int scale_index, s32 tpt, int attempts,
|
||||
int successes)
|
||||
static int rs_collect_tx_data(struct iwl_scale_tbl_info *tbl,
|
||||
int scale_index, int attempts, int successes)
|
||||
{
|
||||
struct iwl_rate_scale_data *window = NULL;
|
||||
static const u64 mask = (((u64)1) << (IWL_RATE_MAX_WINDOW - 1));
|
||||
s32 fail_count;
|
||||
s32 fail_count, tpt;
|
||||
|
||||
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
|
||||
return -EINVAL;
|
||||
|
||||
/* Select window for current tx bit rate */
|
||||
window = &(windows[scale_index]);
|
||||
window = &(tbl->win[scale_index]);
|
||||
|
||||
/* Get expected throughput */
|
||||
tpt = get_expected_tpt(tbl, scale_index);
|
||||
|
||||
/*
|
||||
* Keep track of only the latest 62 tx frame attempts in this rate's
|
||||
|
@ -739,16 +752,6 @@ static bool table_type_matches(struct iwl_scale_tbl_info *a,
|
|||
return (a->lq_type == b->lq_type) && (a->ant_type == b->ant_type) &&
|
||||
(a->is_SGI == b->is_SGI);
|
||||
}
|
||||
/*
|
||||
* Static function to get the expected throughput from an iwl_scale_tbl_info
|
||||
* that wraps a NULL pointer check
|
||||
*/
|
||||
static s32 get_expected_tpt(struct iwl_scale_tbl_info *tbl, int rs_index)
|
||||
{
|
||||
if (tbl->expected_tpt)
|
||||
return tbl->expected_tpt[rs_index];
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* mac80211 sends us Tx status
|
||||
|
@ -765,12 +768,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
|
||||
struct iwl_priv *priv = (struct iwl_priv *)priv_r;
|
||||
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
|
||||
struct iwl_rate_scale_data *window = NULL;
|
||||
enum mac80211_rate_control_flags mac_flags;
|
||||
u32 tx_rate;
|
||||
struct iwl_scale_tbl_info tbl_type;
|
||||
struct iwl_scale_tbl_info *curr_tbl, *other_tbl;
|
||||
s32 tpt = 0;
|
||||
struct iwl_scale_tbl_info *curr_tbl, *other_tbl, *tmp_tbl;
|
||||
|
||||
IWL_DEBUG_RATE_LIMIT(priv, "get frame ack response, update rate scale window\n");
|
||||
|
||||
|
@ -853,7 +854,6 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
IWL_DEBUG_RATE(priv, "Neither active nor search matches tx rate\n");
|
||||
return;
|
||||
}
|
||||
window = (struct iwl_rate_scale_data *)&(curr_tbl->win[0]);
|
||||
|
||||
/*
|
||||
* Updating the frame history depends on whether packets were
|
||||
|
@ -866,8 +866,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
tx_rate = le32_to_cpu(table->rs_table[0].rate_n_flags);
|
||||
rs_get_tbl_info_from_mcs(tx_rate, priv->band, &tbl_type,
|
||||
&rs_index);
|
||||
tpt = get_expected_tpt(curr_tbl, rs_index);
|
||||
rs_collect_tx_data(window, rs_index, tpt,
|
||||
rs_collect_tx_data(curr_tbl, rs_index,
|
||||
info->status.ampdu_ack_len,
|
||||
info->status.ampdu_ack_map);
|
||||
|
||||
|
@ -897,19 +896,13 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
|
|||
* table as active/search.
|
||||
*/
|
||||
if (table_type_matches(&tbl_type, curr_tbl))
|
||||
tpt = get_expected_tpt(curr_tbl, rs_index);
|
||||
tmp_tbl = curr_tbl;
|
||||
else if (table_type_matches(&tbl_type, other_tbl))
|
||||
tpt = get_expected_tpt(other_tbl, rs_index);
|
||||
tmp_tbl = other_tbl;
|
||||
else
|
||||
continue;
|
||||
|
||||
/* Constants mean 1 transmission, 0 successes */
|
||||
if (i < retries)
|
||||
rs_collect_tx_data(window, rs_index, tpt, 1,
|
||||
0);
|
||||
else
|
||||
rs_collect_tx_data(window, rs_index, tpt, 1,
|
||||
legacy_success);
|
||||
rs_collect_tx_data(tmp_tbl, rs_index, 1,
|
||||
i < retries ? 0 : legacy_success);
|
||||
}
|
||||
|
||||
/* Update success/fail counts if not searching for new mode */
|
||||
|
|
|
@ -308,10 +308,13 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
|
|||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Allocate and init all Tx and Command queues */
|
||||
ret = iwl_txq_ctx_reset(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
/* Allocate or reset and init all Tx and Command queues */
|
||||
if (!priv->txq) {
|
||||
ret = iwl_txq_ctx_alloc(priv);
|
||||
if (ret)
|
||||
return ret;
|
||||
} else
|
||||
iwl_txq_ctx_reset(priv);
|
||||
|
||||
set_bit(STATUS_INIT, &priv->status);
|
||||
|
||||
|
|
|
@ -442,7 +442,8 @@ void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb);
|
|||
/*****************************************************
|
||||
* TX
|
||||
******************************************************/
|
||||
int iwl_txq_ctx_reset(struct iwl_priv *priv);
|
||||
int iwl_txq_ctx_alloc(struct iwl_priv *priv);
|
||||
void iwl_txq_ctx_reset(struct iwl_priv *priv);
|
||||
void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq);
|
||||
int iwl_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
|
||||
struct iwl_tx_queue *txq,
|
||||
|
@ -456,6 +457,8 @@ void iwl_free_tfds_in_queue(struct iwl_priv *priv,
|
|||
void iwl_txq_update_write_ptr(struct iwl_priv *priv, struct iwl_tx_queue *txq);
|
||||
int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id);
|
||||
void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id);
|
||||
void iwl_tx_queue_free(struct iwl_priv *priv, int txq_id);
|
||||
int iwl_tx_agg_start(struct iwl_priv *priv, const u8 *ra, u16 tid, u16 *ssn);
|
||||
int iwl_tx_agg_stop(struct iwl_priv *priv , const u8 *ra, u16 tid);
|
||||
|
|
|
@ -194,10 +194,34 @@ void iwl_cmd_queue_free(struct iwl_priv *priv)
|
|||
struct iwl_queue *q = &txq->q;
|
||||
struct device *dev = &priv->pci_dev->dev;
|
||||
int i;
|
||||
bool huge = false;
|
||||
|
||||
if (q->n_bd == 0)
|
||||
return;
|
||||
|
||||
for (; q->read_ptr != q->write_ptr;
|
||||
q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
|
||||
/* we have no way to tell if it is a huge cmd ATM */
|
||||
i = get_cmd_index(q, q->read_ptr, 0);
|
||||
|
||||
if (txq->meta[i].flags & CMD_SIZE_HUGE) {
|
||||
huge = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
pci_unmap_addr(&txq->meta[i], mapping),
|
||||
pci_unmap_len(&txq->meta[i], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
if (huge) {
|
||||
i = q->n_window;
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
pci_unmap_addr(&txq->meta[i], mapping),
|
||||
pci_unmap_len(&txq->meta[i], len),
|
||||
PCI_DMA_BIDIRECTIONAL);
|
||||
}
|
||||
|
||||
/* De-alloc array of command/tx buffers */
|
||||
for (i = 0; i <= TFD_CMD_SLOTS; i++)
|
||||
kfree(txq->cmd[i]);
|
||||
|
@ -410,6 +434,26 @@ int iwl_tx_queue_init(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
|||
}
|
||||
EXPORT_SYMBOL(iwl_tx_queue_init);
|
||||
|
||||
void iwl_tx_queue_reset(struct iwl_priv *priv, struct iwl_tx_queue *txq,
|
||||
int slots_num, u32 txq_id)
|
||||
{
|
||||
int actual_slots = slots_num;
|
||||
|
||||
if (txq_id == IWL_CMD_QUEUE_NUM)
|
||||
actual_slots++;
|
||||
|
||||
memset(txq->meta, 0, sizeof(struct iwl_cmd_meta) * actual_slots);
|
||||
|
||||
txq->need_update = 0;
|
||||
|
||||
/* Initialize queue's high/low-water marks, and head/tail indexes */
|
||||
iwl_queue_init(priv, &txq->q, TFD_QUEUE_SIZE_MAX, slots_num, txq_id);
|
||||
|
||||
/* Tell device where to find queue */
|
||||
priv->cfg->ops->lib->txq_init(priv, txq);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tx_queue_reset);
|
||||
|
||||
/**
|
||||
* iwl_hw_txq_ctx_free - Free TXQ Context
|
||||
*
|
||||
|
@ -421,8 +465,7 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
|
|||
|
||||
/* Tx queues */
|
||||
if (priv->txq) {
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num;
|
||||
txq_id++)
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++)
|
||||
if (txq_id == IWL_CMD_QUEUE_NUM)
|
||||
iwl_cmd_queue_free(priv);
|
||||
else
|
||||
|
@ -438,15 +481,15 @@ void iwl_hw_txq_ctx_free(struct iwl_priv *priv)
|
|||
EXPORT_SYMBOL(iwl_hw_txq_ctx_free);
|
||||
|
||||
/**
|
||||
* iwl_txq_ctx_reset - Reset TX queue context
|
||||
* Destroys all DMA structures and initialize them again
|
||||
* iwl_txq_ctx_alloc - allocate TX queue context
|
||||
* Allocate all Tx DMA structures and initialize them
|
||||
*
|
||||
* @param priv
|
||||
* @return error code
|
||||
*/
|
||||
int iwl_txq_ctx_reset(struct iwl_priv *priv)
|
||||
int iwl_txq_ctx_alloc(struct iwl_priv *priv)
|
||||
{
|
||||
int ret = 0;
|
||||
int ret;
|
||||
int txq_id, slots_num;
|
||||
unsigned long flags;
|
||||
|
||||
|
@ -504,8 +547,31 @@ int iwl_txq_ctx_reset(struct iwl_priv *priv)
|
|||
return ret;
|
||||
}
|
||||
|
||||
void iwl_txq_ctx_reset(struct iwl_priv *priv)
|
||||
{
|
||||
int txq_id, slots_num;
|
||||
unsigned long flags;
|
||||
|
||||
spin_lock_irqsave(&priv->lock, flags);
|
||||
|
||||
/* Turn off all Tx DMA fifos */
|
||||
priv->cfg->ops->lib->txq_set_sched(priv, 0);
|
||||
|
||||
/* Tell NIC where to find the "keep warm" buffer */
|
||||
iwl_write_direct32(priv, FH_KW_MEM_ADDR_REG, priv->kw.dma >> 4);
|
||||
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Alloc and init all Tx queues, including the command queue (#4) */
|
||||
for (txq_id = 0; txq_id < priv->hw_params.max_txq_num; txq_id++) {
|
||||
slots_num = txq_id == IWL_CMD_QUEUE_NUM ?
|
||||
TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
|
||||
iwl_tx_queue_reset(priv, &priv->txq[txq_id], slots_num, txq_id);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* iwl_txq_ctx_stop - Stop all Tx DMA channels, free Tx queue memory
|
||||
* iwl_txq_ctx_stop - Stop all Tx DMA channels
|
||||
*/
|
||||
void iwl_txq_ctx_stop(struct iwl_priv *priv)
|
||||
{
|
||||
|
@ -525,9 +591,6 @@ void iwl_txq_ctx_stop(struct iwl_priv *priv)
|
|||
1000);
|
||||
}
|
||||
spin_unlock_irqrestore(&priv->lock, flags);
|
||||
|
||||
/* Deallocate memory for all Tx queues */
|
||||
iwl_hw_txq_ctx_free(priv);
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_txq_ctx_stop);
|
||||
|
||||
|
@ -1050,6 +1113,14 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
|
|||
|
||||
spin_lock_irqsave(&priv->hcmd_lock, flags);
|
||||
|
||||
/* If this is a huge cmd, mark the huge flag also on the meta.flags
|
||||
* of the _original_ cmd. This is used for DMA mapping clean up.
|
||||
*/
|
||||
if (cmd->flags & CMD_SIZE_HUGE) {
|
||||
idx = get_cmd_index(q, q->write_ptr, 0);
|
||||
txq->meta[idx].flags = CMD_SIZE_HUGE;
|
||||
}
|
||||
|
||||
idx = get_cmd_index(q, q->write_ptr, cmd->flags & CMD_SIZE_HUGE);
|
||||
out_cmd = txq->cmd[idx];
|
||||
out_meta = &txq->meta[idx];
|
||||
|
@ -1227,6 +1298,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
|
|||
bool huge = !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
|
||||
struct iwl_device_cmd *cmd;
|
||||
struct iwl_cmd_meta *meta;
|
||||
struct iwl_tx_queue *txq = &priv->txq[IWL_CMD_QUEUE_NUM];
|
||||
|
||||
/* If a Tx command is being handled and it isn't in the actual
|
||||
* command queue then there a command routing bug has been introduced
|
||||
|
@ -1240,9 +1312,17 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
|
|||
return;
|
||||
}
|
||||
|
||||
cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
|
||||
cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
|
||||
meta = &priv->txq[IWL_CMD_QUEUE_NUM].meta[cmd_index];
|
||||
/* If this is a huge cmd, clear the huge flag on the meta.flags
|
||||
* of the _original_ cmd. So that iwl_cmd_queue_free won't unmap
|
||||
* the DMA buffer for the scan (huge) command.
|
||||
*/
|
||||
if (huge) {
|
||||
cmd_index = get_cmd_index(&txq->q, index, 0);
|
||||
txq->meta[cmd_index].flags = 0;
|
||||
}
|
||||
cmd_index = get_cmd_index(&txq->q, index, huge);
|
||||
cmd = txq->cmd[cmd_index];
|
||||
meta = &txq->meta[cmd_index];
|
||||
|
||||
pci_unmap_single(priv->pci_dev,
|
||||
pci_unmap_addr(meta, mapping),
|
||||
|
@ -1264,6 +1344,7 @@ void iwl_tx_cmd_complete(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
|
|||
get_cmd_string(cmd->hdr.cmd));
|
||||
wake_up_interruptible(&priv->wait_command_queue);
|
||||
}
|
||||
meta->flags = 0;
|
||||
}
|
||||
EXPORT_SYMBOL(iwl_tx_cmd_complete);
|
||||
|
||||
|
|
|
@ -236,6 +236,10 @@ static int vq_memory_access_ok(void __user *log_base, struct vhost_memory *mem,
|
|||
int log_all)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (!mem)
|
||||
return 0;
|
||||
|
||||
for (i = 0; i < mem->nregions; ++i) {
|
||||
struct vhost_memory_region *m = mem->regions + i;
|
||||
unsigned long a = m->userspace_addr;
|
||||
|
|
|
@ -183,6 +183,10 @@ extern int sysctl_x25_clear_request_timeout;
|
|||
extern int sysctl_x25_ack_holdback_timeout;
|
||||
extern int sysctl_x25_forward;
|
||||
|
||||
extern int x25_parse_address_block(struct sk_buff *skb,
|
||||
struct x25_address *called_addr,
|
||||
struct x25_address *calling_addr);
|
||||
|
||||
extern int x25_addr_ntoa(unsigned char *, struct x25_address *,
|
||||
struct x25_address *);
|
||||
extern int x25_addr_aton(unsigned char *, struct x25_address *,
|
||||
|
|
|
@ -723,7 +723,7 @@ static int br_multicast_igmp3_report(struct net_bridge *br,
|
|||
if (!pskb_may_pull(skb, len))
|
||||
return -EINVAL;
|
||||
|
||||
grec = (void *)(skb->data + len);
|
||||
grec = (void *)(skb->data + len - sizeof(*grec));
|
||||
group = grec->grec_mca;
|
||||
type = grec->grec_type;
|
||||
|
||||
|
|
|
@ -445,7 +445,7 @@ static int raw_setsockopt(struct socket *sock, int level, int optname,
|
|||
return -EFAULT;
|
||||
}
|
||||
} else if (count == 1) {
|
||||
if (copy_from_user(&sfilter, optval, optlen))
|
||||
if (copy_from_user(&sfilter, optval, sizeof(sfilter)))
|
||||
return -EFAULT;
|
||||
}
|
||||
|
||||
|
|
|
@ -472,8 +472,8 @@ static struct sock *__udp4_lib_lookup(struct net *net, __be32 saddr,
|
|||
if (hslot->count < hslot2->count)
|
||||
goto begin;
|
||||
|
||||
result = udp4_lib_lookup2(net, INADDR_ANY, sport,
|
||||
daddr, hnum, dif,
|
||||
result = udp4_lib_lookup2(net, saddr, sport,
|
||||
INADDR_ANY, hnum, dif,
|
||||
hslot2, slot2);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -259,8 +259,8 @@ static struct sock *__udp6_lib_lookup(struct net *net,
|
|||
if (hslot->count < hslot2->count)
|
||||
goto begin;
|
||||
|
||||
result = udp6_lib_lookup2(net, &in6addr_any, sport,
|
||||
daddr, hnum, dif,
|
||||
result = udp6_lib_lookup2(net, saddr, sport,
|
||||
&in6addr_any, hnum, dif,
|
||||
hslot2, slot2);
|
||||
}
|
||||
rcu_read_unlock();
|
||||
|
|
|
@ -225,11 +225,11 @@ void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
|
|||
switch (sdata->vif.type) {
|
||||
case NL80211_IFTYPE_AP:
|
||||
sdata->vif.bss_conf.enable_beacon =
|
||||
!!rcu_dereference(sdata->u.ap.beacon);
|
||||
!!sdata->u.ap.beacon;
|
||||
break;
|
||||
case NL80211_IFTYPE_ADHOC:
|
||||
sdata->vif.bss_conf.enable_beacon =
|
||||
!!rcu_dereference(sdata->u.ibss.presp);
|
||||
!!sdata->u.ibss.presp;
|
||||
break;
|
||||
case NL80211_IFTYPE_MESH_POINT:
|
||||
sdata->vif.bss_conf.enable_beacon = true;
|
||||
|
|
|
@ -750,9 +750,6 @@ ieee80211_mesh_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb)
|
|||
|
||||
switch (fc & IEEE80211_FCTL_STYPE) {
|
||||
case IEEE80211_STYPE_ACTION:
|
||||
if (skb->len < IEEE80211_MIN_ACTION_SIZE)
|
||||
return RX_DROP_MONITOR;
|
||||
/* fall through */
|
||||
case IEEE80211_STYPE_PROBE_RESP:
|
||||
case IEEE80211_STYPE_BEACON:
|
||||
skb_queue_tail(&ifmsh->skb_queue, skb);
|
||||
|
|
|
@ -1974,6 +1974,11 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
|
|||
goto handled;
|
||||
}
|
||||
break;
|
||||
case MESH_PLINK_CATEGORY:
|
||||
case MESH_PATH_SEL_CATEGORY:
|
||||
if (ieee80211_vif_is_mesh(&sdata->vif))
|
||||
return ieee80211_mesh_rx_mgmt(sdata, rx->skb);
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -93,12 +93,18 @@ struct sta_info *sta_info_get(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
|
||||
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_is_held(&local->sta_lock) ||
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
while (sta) {
|
||||
if (sta->sdata == sdata &&
|
||||
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
sta = rcu_dereference(sta->hnext);
|
||||
sta = rcu_dereference_check(sta->hnext,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_is_held(&local->sta_lock) ||
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
}
|
||||
return sta;
|
||||
}
|
||||
|
@ -113,13 +119,19 @@ struct sta_info *sta_info_get_bss(struct ieee80211_sub_if_data *sdata,
|
|||
struct ieee80211_local *local = sdata->local;
|
||||
struct sta_info *sta;
|
||||
|
||||
sta = rcu_dereference(local->sta_hash[STA_HASH(addr)]);
|
||||
sta = rcu_dereference_check(local->sta_hash[STA_HASH(addr)],
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_is_held(&local->sta_lock) ||
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
while (sta) {
|
||||
if ((sta->sdata == sdata ||
|
||||
sta->sdata->bss == sdata->bss) &&
|
||||
memcmp(sta->sta.addr, addr, ETH_ALEN) == 0)
|
||||
break;
|
||||
sta = rcu_dereference(sta->hnext);
|
||||
sta = rcu_dereference_check(sta->hnext,
|
||||
rcu_read_lock_held() ||
|
||||
lockdep_is_held(&local->sta_lock) ||
|
||||
lockdep_is_held(&local->sta_mtx));
|
||||
}
|
||||
return sta;
|
||||
}
|
||||
|
|
|
@ -83,6 +83,41 @@ struct compat_x25_subscrip_struct {
|
|||
};
|
||||
#endif
|
||||
|
||||
|
||||
int x25_parse_address_block(struct sk_buff *skb,
|
||||
struct x25_address *called_addr,
|
||||
struct x25_address *calling_addr)
|
||||
{
|
||||
unsigned char len;
|
||||
int needed;
|
||||
int rc;
|
||||
|
||||
if (skb->len < 1) {
|
||||
/* packet has no address block */
|
||||
rc = 0;
|
||||
goto empty;
|
||||
}
|
||||
|
||||
len = *skb->data;
|
||||
needed = 1 + (len >> 4) + (len & 0x0f);
|
||||
|
||||
if (skb->len < needed) {
|
||||
/* packet is too short to hold the addresses it claims
|
||||
to hold */
|
||||
rc = -1;
|
||||
goto empty;
|
||||
}
|
||||
|
||||
return x25_addr_ntoa(skb->data, called_addr, calling_addr);
|
||||
|
||||
empty:
|
||||
*called_addr->x25_addr = 0;
|
||||
*calling_addr->x25_addr = 0;
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
int x25_addr_ntoa(unsigned char *p, struct x25_address *called_addr,
|
||||
struct x25_address *calling_addr)
|
||||
{
|
||||
|
@ -554,7 +589,8 @@ static int x25_create(struct net *net, struct socket *sock, int protocol,
|
|||
x25->facilities.winsize_out = X25_DEFAULT_WINDOW_SIZE;
|
||||
x25->facilities.pacsize_in = X25_DEFAULT_PACKET_SIZE;
|
||||
x25->facilities.pacsize_out = X25_DEFAULT_PACKET_SIZE;
|
||||
x25->facilities.throughput = X25_DEFAULT_THROUGHPUT;
|
||||
x25->facilities.throughput = 0; /* by default don't negotiate
|
||||
throughput */
|
||||
x25->facilities.reverse = X25_DEFAULT_REVERSE;
|
||||
x25->dte_facilities.calling_len = 0;
|
||||
x25->dte_facilities.called_len = 0;
|
||||
|
@ -922,16 +958,26 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
|
|||
/*
|
||||
* Extract the X.25 addresses and convert them to ASCII strings,
|
||||
* and remove them.
|
||||
*
|
||||
* Address block is mandatory in call request packets
|
||||
*/
|
||||
addr_len = x25_addr_ntoa(skb->data, &source_addr, &dest_addr);
|
||||
addr_len = x25_parse_address_block(skb, &source_addr, &dest_addr);
|
||||
if (addr_len <= 0)
|
||||
goto out_clear_request;
|
||||
skb_pull(skb, addr_len);
|
||||
|
||||
/*
|
||||
* Get the length of the facilities, skip past them for the moment
|
||||
* get the call user data because this is needed to determine
|
||||
* the correct listener
|
||||
*
|
||||
* Facilities length is mandatory in call request packets
|
||||
*/
|
||||
if (skb->len < 1)
|
||||
goto out_clear_request;
|
||||
len = skb->data[0] + 1;
|
||||
if (skb->len < len)
|
||||
goto out_clear_request;
|
||||
skb_pull(skb,len);
|
||||
|
||||
/*
|
||||
|
@ -1415,9 +1461,20 @@ static int x25_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
|
|||
if (facilities.winsize_in < 1 ||
|
||||
facilities.winsize_in > 127)
|
||||
break;
|
||||
if (facilities.throughput < 0x03 ||
|
||||
facilities.throughput > 0xDD)
|
||||
break;
|
||||
if (facilities.throughput) {
|
||||
int out = facilities.throughput & 0xf0;
|
||||
int in = facilities.throughput & 0x0f;
|
||||
if (!out)
|
||||
facilities.throughput |=
|
||||
X25_DEFAULT_THROUGHPUT << 4;
|
||||
else if (out < 0x30 || out > 0xD0)
|
||||
break;
|
||||
if (!in)
|
||||
facilities.throughput |=
|
||||
X25_DEFAULT_THROUGHPUT;
|
||||
else if (in < 0x03 || in > 0x0D)
|
||||
break;
|
||||
}
|
||||
if (facilities.reverse &&
|
||||
(facilities.reverse & 0x81) != 0x81)
|
||||
break;
|
||||
|
|
|
@ -35,7 +35,7 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
|
|||
struct x25_dte_facilities *dte_facs, unsigned long *vc_fac_mask)
|
||||
{
|
||||
unsigned char *p = skb->data;
|
||||
unsigned int len = *p++;
|
||||
unsigned int len;
|
||||
|
||||
*vc_fac_mask = 0;
|
||||
|
||||
|
@ -50,6 +50,14 @@ int x25_parse_facilities(struct sk_buff *skb, struct x25_facilities *facilities,
|
|||
memset(dte_facs->called_ae, '\0', sizeof(dte_facs->called_ae));
|
||||
memset(dte_facs->calling_ae, '\0', sizeof(dte_facs->calling_ae));
|
||||
|
||||
if (skb->len < 1)
|
||||
return 0;
|
||||
|
||||
len = *p++;
|
||||
|
||||
if (len >= skb->len)
|
||||
return -1;
|
||||
|
||||
while (len > 0) {
|
||||
switch (*p & X25_FAC_CLASS_MASK) {
|
||||
case X25_FAC_CLASS_A:
|
||||
|
@ -247,6 +255,8 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
|
|||
memcpy(new, ours, sizeof(*new));
|
||||
|
||||
len = x25_parse_facilities(skb, &theirs, dte, &x25->vc_facil_mask);
|
||||
if (len < 0)
|
||||
return len;
|
||||
|
||||
/*
|
||||
* They want reverse charging, we won't accept it.
|
||||
|
@ -259,9 +269,18 @@ int x25_negotiate_facilities(struct sk_buff *skb, struct sock *sk,
|
|||
new->reverse = theirs.reverse;
|
||||
|
||||
if (theirs.throughput) {
|
||||
if (theirs.throughput < ours->throughput) {
|
||||
SOCK_DEBUG(sk, "X.25: throughput negotiated down\n");
|
||||
new->throughput = theirs.throughput;
|
||||
int theirs_in = theirs.throughput & 0x0f;
|
||||
int theirs_out = theirs.throughput & 0xf0;
|
||||
int ours_in = ours->throughput & 0x0f;
|
||||
int ours_out = ours->throughput & 0xf0;
|
||||
if (!ours_in || theirs_in < ours_in) {
|
||||
SOCK_DEBUG(sk, "X.25: inbound throughput negotiated\n");
|
||||
new->throughput = (new->throughput & 0xf0) | theirs_in;
|
||||
}
|
||||
if (!ours_out || theirs_out < ours_out) {
|
||||
SOCK_DEBUG(sk,
|
||||
"X.25: outbound throughput negotiated\n");
|
||||
new->throughput = (new->throughput & 0x0f) | theirs_out;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -90,6 +90,7 @@ static int x25_queue_rx_frame(struct sock *sk, struct sk_buff *skb, int more)
|
|||
static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametype)
|
||||
{
|
||||
struct x25_address source_addr, dest_addr;
|
||||
int len;
|
||||
|
||||
switch (frametype) {
|
||||
case X25_CALL_ACCEPTED: {
|
||||
|
@ -107,11 +108,17 @@ static int x25_state1_machine(struct sock *sk, struct sk_buff *skb, int frametyp
|
|||
* Parse the data in the frame.
|
||||
*/
|
||||
skb_pull(skb, X25_STD_MIN_LEN);
|
||||
skb_pull(skb, x25_addr_ntoa(skb->data, &source_addr, &dest_addr));
|
||||
skb_pull(skb,
|
||||
x25_parse_facilities(skb, &x25->facilities,
|
||||
|
||||
len = x25_parse_address_block(skb, &source_addr,
|
||||
&dest_addr);
|
||||
if (len > 0)
|
||||
skb_pull(skb, len);
|
||||
|
||||
len = x25_parse_facilities(skb, &x25->facilities,
|
||||
&x25->dte_facilities,
|
||||
&x25->vc_facil_mask));
|
||||
&x25->vc_facil_mask);
|
||||
if (len > 0)
|
||||
skb_pull(skb, len);
|
||||
/*
|
||||
* Copy any Call User Data.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue