📄 orinoco.c
字号:
u8 dest[ETH_ALEN]; u8 src[ETH_ALEN]; u16 len; /* 802.2 */ u8 dsap; u8 ssap; u8 ctrl; /* SNAP */ u8 oui[3]; u16 ethertype;} __attribute__ ((packed));/* 802.2 LLC/SNAP header used for Ethernet encapsulation over 802.11 */u8 encaps_hdr[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};#define ENCAPS_OVERHEAD (sizeof(encaps_hdr) + 2)#define TX_TIMEOUT (HZ) /* 1 second timeout *//* * Function prototypes */static void orinoco_stat_gather(struct net_device *dev, struct sk_buff *skb, struct hermes_rx_descriptor *desc);static struct net_device_stats *orinoco_get_stats(struct net_device *dev);static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev);/* Hardware control routines */static int __orinoco_hw_set_bitrate(struct orinoco_private *priv);static int __orinoco_hw_setup_wep(struct orinoco_private *priv);static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]);static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, char buf[IW_ESSID_MAX_SIZE+1]);static long orinoco_hw_get_freq(struct orinoco_private *priv);static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, s32 *rates, int max);static void __orinoco_set_multicast_list(struct net_device *dev);static void orinoco_tx_timeout(struct net_device *dev);/* Interrupt handling routines */static void __orinoco_ev_tick(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_wterr(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_infdrop(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_info(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_rx(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_txexc(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_tx(struct orinoco_private *priv, hermes_t *hw);static void __orinoco_ev_alloc(struct orinoco_private *priv, hermes_t *hw);static int orinoco_ioctl_getiwrange(struct net_device *dev, struct iw_point *rrq);static int orinoco_ioctl_setiwencode(struct net_device *dev, struct iw_point *erq);static int orinoco_ioctl_getiwencode(struct net_device *dev, struct iw_point *erq);static int orinoco_ioctl_setessid(struct net_device *dev, struct iw_point *erq);static int orinoco_ioctl_getessid(struct net_device *dev, struct iw_point *erq);static int orinoco_ioctl_setnick(struct net_device *dev, struct iw_point *nrq);static int orinoco_ioctl_getnick(struct net_device *dev, struct iw_point *nrq);static int orinoco_ioctl_setfreq(struct net_device *dev, struct iw_freq *frq);static int orinoco_ioctl_getsens(struct net_device *dev, struct iw_param *srq);static int orinoco_ioctl_setsens(struct net_device *dev, struct iw_param *srq);static int orinoco_ioctl_setrts(struct net_device *dev, struct iw_param *rrq);static int orinoco_ioctl_setfrag(struct net_device *dev, struct iw_param *frq);static int orinoco_ioctl_getfrag(struct net_device *dev, struct iw_param *frq);static int orinoco_ioctl_setrate(struct net_device *dev, struct iw_param *frq);static int orinoco_ioctl_getrate(struct net_device *dev, struct iw_param *frq);static int orinoco_ioctl_setpower(struct net_device *dev, struct iw_param *prq);static int orinoco_ioctl_getpower(struct net_device *dev, struct iw_param *prq);static int orinoco_ioctl_setport3(struct net_device *dev, struct iwreq *wrq);static int orinoco_ioctl_getport3(struct net_device *dev, struct iwreq *wrq);/* /proc debugging stuff */static int orinoco_proc_init(void);static void orinoco_proc_cleanup(void);/* * Inline functions */#ifndef spin_lock_bhstatic long __flags;#define spin_lock_bh(lock) spin_lock_irqsave(lock, __flags)#define spin_unlock_bh(lock) spin_unlock_irqrestore(lock, __flags)#endifstatic inline voidorinoco_lock(struct orinoco_private *priv){ spin_lock_bh(&priv->lock);}static inline voidorinoco_unlock(struct orinoco_private *priv){ spin_unlock_bh(&priv->lock);}static inline intorinoco_irqs_allowed(struct orinoco_private *priv){ return test_bit(ORINOCO_STATE_DOIRQ, &priv->state);}static inline void__orinoco_stop_irqs(struct orinoco_private *priv){ hermes_t *hw = &priv->hw; hermes_set_irqmask(hw, 0); clear_bit(ORINOCO_STATE_DOIRQ, &priv->state); while (test_bit(ORINOCO_STATE_INIRQ, &priv->state)) ;}static inline void__orinoco_start_irqs(struct orinoco_private *priv, u16 irqmask){ hermes_t *hw = &priv->hw; TRACE_ENTER(priv->ndev->name); __cli(); /* FIXME: is this necessary? */ set_bit(ORINOCO_STATE_DOIRQ, &priv->state); hermes_set_irqmask(hw, irqmask); __sti(); TRACE_EXIT(priv->ndev->name);}static inline voidset_port_type(struct orinoco_private *priv){ switch (priv->iw_mode) { case IW_MODE_INFRA: priv->port_type = 1; priv->allow_ibss = 0; break; case IW_MODE_ADHOC: if (priv->prefer_port3) { priv->port_type = 3; priv->allow_ibss = 0; } else { priv->port_type = priv->ibss_port; priv->allow_ibss = 1; } break; default: printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", priv->ndev->name); }}static inline intis_snap(struct header_struct *hdr){ return (hdr->dsap == 0xAA) && (hdr->ssap == 0xAA) && (hdr->ctrl == 0x3);}static voidorinoco_set_multicast_list(struct net_device *dev){ struct orinoco_private *priv = dev->priv; orinoco_lock(priv); __orinoco_set_multicast_list(dev); orinoco_unlock(priv);}/* * Hardware control routines */voidorinoco_shutdown(struct orinoco_private *priv){ int err = 0; TRACE_ENTER(priv->ndev->name); orinoco_lock(priv); __orinoco_stop_irqs(priv); err = hermes_reset(&priv->hw); if (err && err != -ENODEV) /* If the card is gone, we don't care about shutting it down */ printk(KERN_ERR "%s: Error %d shutting down Hermes chipset\n", priv->ndev->name, err); orinoco_unlock(priv); TRACE_EXIT(priv->ndev->name);}intorinoco_reset(struct orinoco_private *priv){ struct net_device *dev = priv->ndev; hermes_t *hw = &priv->hw; int err = 0; struct hermes_idstring idbuf; TRACE_ENTER(priv->ndev->name); /* Stop other people bothering us */ orinoco_lock(priv); __orinoco_stop_irqs(priv); /* Check if we need a card reset */ if (priv->hard_reset) priv->hard_reset(priv); /* Do standard firmware reset if we can */ err = hermes_reset(hw); if (err) goto out; err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); if (err == -EIO) { /* Try workaround for old Symbol firmware bug */ priv->nicbuf_size = TX_NICBUF_SIZE_BUG; err = hermes_allocate(hw, priv->nicbuf_size, &priv->txfid); if (err) goto out; } /* Now set up all the parameters on the card */ /* Set up the link mode */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPORTTYPE, priv->port_type); if (err) goto out; if (priv->has_ibss) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFCREATEIBSS, priv->allow_ibss); if (err) goto out; if((strlen(priv->desired_essid) == 0) && (priv->allow_ibss) && (!priv->has_ibss_any)) { printk(KERN_WARNING "%s: This firmware requires an \ESSID in IBSS-Ad-Hoc mode.\n", dev->name); /* With wvlan_cs, in this case, we would crash. * hopefully, this driver will behave better... * Jean II */ } } /* Set the desired ESSID */ idbuf.len = cpu_to_le16(strlen(priv->desired_essid)); memcpy(&idbuf.val, priv->desired_essid, sizeof(idbuf.val)); /* WinXP wants partner to configure OWNSSID even in IBSS mode. (jimc) */ err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNSSID, HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) goto out; err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFDESIREDSSID, HERMES_BYTES_TO_RECLEN(strlen(priv->desired_essid)+2), &idbuf); if (err) goto out; /* Set the station name */ idbuf.len = cpu_to_le16(strlen(priv->nick)); memcpy(&idbuf.val, priv->nick, sizeof(idbuf.val)); err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFOWNNAME, HERMES_BYTES_TO_RECLEN(strlen(priv->nick)+2), &idbuf); if (err) goto out; /* Set the channel/frequency */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFOWNCHANNEL, priv->channel); if (err) goto out; /* Set AP density */ if (priv->has_sensitivity) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFSYSTEMSCALE, priv->ap_density); if (err) priv->has_sensitivity = 0; } /* Set RTS threshold */ err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFRTSTHRESHOLD, priv->rts_thresh); if (err) goto out; /* Set fragmentation threshold or MWO robustness */ if (priv->has_mwo) err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMWOROBUST_AGERE, priv->mwo_robust); else err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFFRAGMENTATIONTHRESHOLD, priv->frag_thresh); if (err) goto out; /* Set bitrate */ err = __orinoco_hw_set_bitrate(priv); if (err) goto out; /* Set power management */ if (priv->has_pm) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMENABLED, priv->pm_on); if (err) goto out; err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMULTICASTRECEIVE, priv->pm_mcast); if (err) goto out; err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFMAXSLEEPDURATION, priv->pm_period); if (err) goto out; err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPMHOLDOVERDURATION, priv->pm_timeout); if (err) goto out; } /* Set preamble - only for Symbol so far... */ if (priv->has_preamble) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFPREAMBLE_SYMBOL, priv->preamble); if (err) { printk(KERN_WARNING "%s: Can't set preamble!\n", dev->name); goto out; } } /* Set up encryption */ if (priv->has_wep) { err = __orinoco_hw_setup_wep(priv); if (err) { printk(KERN_ERR "%s: Error %d activating WEP.\n", dev->name, err); goto out; } } /* Set promiscuity / multicast*/ priv->promiscuous = 0; priv->mc_count = 0; __orinoco_set_multicast_list(dev); __orinoco_start_irqs(priv, HERMES_EV_RX | HERMES_EV_ALLOC | HERMES_EV_TX | HERMES_EV_TXEXC | HERMES_EV_WTERR | HERMES_EV_INFO | HERMES_EV_INFDROP); err = hermes_enable_port(hw, 0); if (err) goto out; out: orinoco_unlock(priv); TRACE_EXIT(priv->ndev->name); return err;}static int __orinoco_hw_set_bitrate(struct orinoco_private *priv){ hermes_t *hw = &priv->hw; int err = 0; TRACE_ENTER(priv->ndev->name); if (priv->bitratemode >= BITRATE_TABLE_SIZE) { printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", priv->ndev->name, priv->bitratemode); return -EINVAL; } switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFTXRATECONTROL, bitrate_table[priv->bitratemode].agere_txratectrl); break; case FIRMWARE_TYPE_INTERSIL: case FIRMWARE_TYPE_SYMBOL: err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFTXRATECONTROL, bitrate_table[priv->bitratemode].intersil_txratectrl); break; default: BUG(); } TRACE_EXIT(priv->ndev->name); return err;}static int __orinoco_hw_setup_wep(struct orinoco_private *priv){ hermes_t *hw = &priv->hw; int err = 0; int master_wep_flag; int auth_flag; TRACE_ENTER(priv->ndev->name); switch (priv->firmware_type) { case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ if (priv->wep_on) { err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFTXKEY_AGERE, priv->tx_key);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -