⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 orinoco.c

📁 linux-2.6.15.6
💻 C
📖 第 1 页 / 共 5 页
字号:
	/* We'll prepend the header, so reserve space for it.  The worst	   case is no decapsulation, when 802.3 header is prepended and	   nothing is removed.  2 is for aligning the IP header.  */	skb_reserve(skb, ETH_HLEN + 2);	err = hermes_bap_pread(hw, IRQ_BAP, skb_put(skb, length),			       ALIGN(length, 2), rxfid,			       HERMES_802_2_OFFSET);	if (err) {		printk(KERN_ERR "%s: error %d reading frame. "		       "Frame dropped.\n", dev->name, err);		goto drop;	}	/* Handle decapsulation	 * In most cases, the firmware tell us about SNAP frames.	 * For some reason, the SNAP frames sent by LinkSys APs	 * are not properly recognised by most firmwares.	 * So, check ourselves */	if (length >= ENCAPS_OVERHEAD &&	    (((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) ||	     ((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) ||	     is_ethersnap(skb->data))) {		/* These indicate a SNAP within 802.2 LLC within		   802.11 frame which we'll need to de-encapsulate to		   the original EthernetII frame. */		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN - ENCAPS_OVERHEAD);	} else {		/* 802.3 frame - prepend 802.3 header as is */		hdr = (struct ethhdr *)skb_push(skb, ETH_HLEN);		hdr->h_proto = htons(length);	}	memcpy(hdr->h_dest, desc.addr1, ETH_ALEN);	if (fc & IEEE80211_FCTL_FROMDS)		memcpy(hdr->h_source, desc.addr3, ETH_ALEN);	else		memcpy(hdr->h_source, desc.addr2, ETH_ALEN);	dev->last_rx = jiffies;	skb->dev = dev;	skb->protocol = eth_type_trans(skb, dev);	skb->ip_summed = CHECKSUM_NONE;	if (fc & IEEE80211_FCTL_TODS)		skb->pkt_type = PACKET_OTHERHOST;		/* Process the wireless stats if needed */	orinoco_stat_gather(dev, skb, &desc);	/* Pass the packet to the networking stack */	netif_rx(skb);	stats->rx_packets++;	stats->rx_bytes += length;	return; drop:		dev_kfree_skb_irq(skb); update_stats:	stats->rx_errors++;	stats->rx_dropped++;}/********************************************************************//* Rx path (info frames)                                            *//********************************************************************/static void print_linkstatus(struct net_device *dev, u16 status){	char * s;	if (suppress_linkstatus)		return;	switch (status) {	case HERMES_LINKSTATUS_NOT_CONNECTED:		s = "Not Connected";		break;	case HERMES_LINKSTATUS_CONNECTED:		s = "Connected";		break;	case HERMES_LINKSTATUS_DISCONNECTED:		s = "Disconnected";		break;	case HERMES_LINKSTATUS_AP_CHANGE:		s = "AP Changed";		break;	case HERMES_LINKSTATUS_AP_OUT_OF_RANGE:		s = "AP Out of Range";		break;	case HERMES_LINKSTATUS_AP_IN_RANGE:		s = "AP In Range";		break;	case HERMES_LINKSTATUS_ASSOC_FAILED:		s = "Association Failed";		break;	default:		s = "UNKNOWN";	}		printk(KERN_INFO "%s: New link status: %s (%04x)\n",	       dev->name, s, status);}/* Search scan results for requested BSSID, join it if found */static void orinoco_join_ap(struct net_device *dev){	struct orinoco_private *priv = netdev_priv(dev);	struct hermes *hw = &priv->hw;	int err;	unsigned long flags;	struct join_req {		u8 bssid[ETH_ALEN];		__le16 channel;	} __attribute__ ((packed)) req;	const int atom_len = offsetof(struct prism2_scan_apinfo, atim);	struct prism2_scan_apinfo *atom = NULL;	int offset = 4;	int found = 0;	u8 *buf;	u16 len;	/* Allocate buffer for scan results */	buf = kmalloc(MAX_SCAN_LEN, GFP_KERNEL);	if (! buf)		return;	if (orinoco_lock(priv, &flags) != 0)		goto fail_lock;	/* Sanity checks in case user changed something in the meantime */	if (! priv->bssid_fixed)		goto out;	if (strlen(priv->desired_essid) == 0)		goto out;	/* Read scan results from the firmware */	err = hermes_read_ltv(hw, USER_BAP,			      HERMES_RID_SCANRESULTSTABLE,			      MAX_SCAN_LEN, &len, buf);	if (err) {		printk(KERN_ERR "%s: Cannot read scan results\n",		       dev->name);		goto out;	}	len = HERMES_RECLEN_TO_BYTES(len);	/* Go through the scan results looking for the channel of the AP	 * we were requested to join */	for (; offset + atom_len <= len; offset += atom_len) {		atom = (struct prism2_scan_apinfo *) (buf + offset);		if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) {			found = 1;			break;		}	}	if (! found) {		DEBUG(1, "%s: Requested AP not found in scan results\n",		      dev->name);		goto out;	}	memcpy(req.bssid, priv->desired_bssid, ETH_ALEN);	req.channel = atom->channel;	/* both are little-endian */	err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST,				  &req);	if (err)		printk(KERN_ERR "%s: Error issuing join request\n", dev->name); out:	orinoco_unlock(priv, &flags); fail_lock:	kfree(buf);}/* Send new BSSID to userspace */static void orinoco_send_wevents(struct net_device *dev){	struct orinoco_private *priv = netdev_priv(dev);	struct hermes *hw = &priv->hw;	union iwreq_data wrqu;	int err;	unsigned long flags;	if (orinoco_lock(priv, &flags) != 0)		return;	err = hermes_read_ltv(hw, IRQ_BAP, HERMES_RID_CURRENTBSSID,			      ETH_ALEN, NULL, wrqu.ap_addr.sa_data);	if (err != 0)		goto out;	wrqu.ap_addr.sa_family = ARPHRD_ETHER;	/* Send event to user space */	wireless_send_event(dev, SIOCGIWAP, &wrqu, NULL); out:	orinoco_unlock(priv, &flags);}static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw){	struct orinoco_private *priv = netdev_priv(dev);	u16 infofid;	struct {		__le16 len;		__le16 type;	} __attribute__ ((packed)) info;	int len, type;	int err;	/* This is an answer to an INQUIRE command that we did earlier,	 * or an information "event" generated by the card	 * The controller return to us a pseudo frame containing	 * the information in question - Jean II */	infofid = hermes_read_regn(hw, INFOFID);	/* Read the info frame header - don't try too hard */	err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info),			       infofid, 0);	if (err) {		printk(KERN_ERR "%s: error %d reading info frame. "		       "Frame dropped.\n", dev->name, err);		return;	}		len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len));	type = le16_to_cpu(info.type);	switch (type) {	case HERMES_INQ_TALLIES: {		struct hermes_tallies_frame tallies;		struct iw_statistics *wstats = &priv->wstats;				if (len > sizeof(tallies)) {			printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n",			       dev->name, len);			len = sizeof(tallies);		}				err = hermes_bap_pread(hw, IRQ_BAP, &tallies, len,				       infofid, sizeof(info));		if (err)			break;				/* Increment our various counters */		/* wstats->discard.nwid - no wrong BSSID stuff */		wstats->discard.code +=			le16_to_cpu(tallies.RxWEPUndecryptable);		if (len == sizeof(tallies))  			wstats->discard.code +=				le16_to_cpu(tallies.RxDiscards_WEPICVError) +				le16_to_cpu(tallies.RxDiscards_WEPExcluded);		wstats->discard.misc +=			le16_to_cpu(tallies.TxDiscardsWrongSA);		wstats->discard.fragment +=			le16_to_cpu(tallies.RxMsgInBadMsgFragments);		wstats->discard.retries +=			le16_to_cpu(tallies.TxRetryLimitExceeded);		/* wstats->miss.beacon - no match */	}	break;	case HERMES_INQ_LINKSTATUS: {		struct hermes_linkstatus linkstatus;		u16 newstatus;		int connected;		if (priv->iw_mode == IW_MODE_MONITOR)			break;		if (len != sizeof(linkstatus)) {			printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n",			       dev->name, len);			break;		}		err = hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len,				       infofid, sizeof(info));		if (err)			break;		newstatus = le16_to_cpu(linkstatus.linkstatus);		/* Symbol firmware uses "out of range" to signal that		 * the hostscan frame can be requested.  */		if (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE &&		    priv->firmware_type == FIRMWARE_TYPE_SYMBOL &&		    priv->has_hostscan && priv->scan_inprogress) {			hermes_inquire(hw, HERMES_INQ_HOSTSCAN_SYMBOL);			break;		}		connected = (newstatus == HERMES_LINKSTATUS_CONNECTED)			|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE)			|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE);		if (connected)			netif_carrier_on(dev);		else if (!ignore_disconnect)			netif_carrier_off(dev);		if (newstatus != priv->last_linkstatus) {			priv->last_linkstatus = newstatus;			print_linkstatus(dev, newstatus);			/* The info frame contains only one word which is the			 * status (see hermes.h). The status is pretty boring			 * in itself, that's why we export the new BSSID...			 * Jean II */			schedule_work(&priv->wevent_work);		}	}	break;	case HERMES_INQ_SCAN:		if (!priv->scan_inprogress && priv->bssid_fixed &&		    priv->firmware_type == FIRMWARE_TYPE_INTERSIL) {			schedule_work(&priv->join_work);			break;		}		/* fall through */	case HERMES_INQ_HOSTSCAN:	case HERMES_INQ_HOSTSCAN_SYMBOL: {		/* Result of a scanning. Contains information about		 * cells in the vicinity - Jean II */		union iwreq_data	wrqu;		unsigned char *buf;		/* Sanity check */		if (len > 4096) {			printk(KERN_WARNING "%s: Scan results too large (%d bytes)\n",			       dev->name, len);			break;		}		/* We are a strict producer. If the previous scan results		 * have not been consumed, we just have to drop this		 * frame. We can't remove the previous results ourselves,		 * that would be *very* racy... Jean II */		if (priv->scan_result != NULL) {			printk(KERN_WARNING "%s: Previous scan results not consumed, dropping info frame.\n", dev->name);			break;		}		/* Allocate buffer for results */		buf = kmalloc(len, GFP_ATOMIC);		if (buf == NULL)			/* No memory, so can't printk()... */			break;		/* Read scan data */		err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len,				       infofid, sizeof(info));		if (err) {			kfree(buf);			break;		}#ifdef ORINOCO_DEBUG		{			int	i;			printk(KERN_DEBUG "Scan result [%02X", buf[0]);			for(i = 1; i < (len * 2); i++)				printk(":%02X", buf[i]);			printk("]\n");		}#endif	/* ORINOCO_DEBUG */		/* Allow the clients to access the results */		priv->scan_len = len;		priv->scan_result = buf;		/* Send an empty event to user space.		 * We don't send the received data on the event because		 * it would require us to do complex transcoding, and		 * we want to minimise the work done in the irq handler		 * Use a request to extract the data - Jean II */		wrqu.data.length = 0;		wrqu.data.flags = 0;		wireless_send_event(dev, SIOCGIWSCAN, &wrqu, NULL);	}	break;	case HERMES_INQ_SEC_STAT_AGERE:		/* Security status (Agere specific) */		/* Ignore this frame for now */		if (priv->firmware_type == FIRMWARE_TYPE_AGERE)			break;		/* fall through */	default:		printk(KERN_DEBUG "%s: Unknown information frame received: "		       "type 0x%04x, length %d\n", dev->name, type, len);		/* We don't actually do anything about it */		break;	}}static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw){	if (net_ratelimit())		printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name);}/********************************************************************//* Internal hardware control routines                               *//********************************************************************/int __orinoco_up(struct net_device *dev){	struct orinoco_private *priv = netdev_priv(dev);	struct hermes *hw = &priv->hw;	int err;	netif_carrier_off(dev); /* just to make sure */	err = __orinoco_program_rids(dev);	if (err) {		printk(KERN_ERR "%s: Error %d configuring card\n",		       dev->name, err);		return err;	}	/* Fire things up again */	hermes_set_irqmask(hw, ORINOCO_INTEN);	err = hermes_enable_port(hw, 0);	if (err) {		printk(KERN_ERR "%s: Error %d enabling MAC port\n",		       dev->name, err);		return err;	}	netif_start_queue(dev);	return 0;}int __orinoco_down(struct net_device *dev){	struct orinoco_private *priv = netdev_priv(dev);	struct hermes *hw = &priv->hw;	int err;	netif_stop_queue(dev);	if (! priv->hw_unavailable) {		if (! priv->broken_disableport) {			err = hermes_disable_port(hw, 0);			if (err) {				/* Some firmwares (e.g. Intersil 1.3.x) seem				 * to have problems disabling the port, oh				 * well, too bad. */				printk(KERN_WARNING "%s: Error %d disabling MAC port\n",				       dev->name, err);				priv->broken_disableport = 1;			}		}		hermes_set_irqmask(hw, 0);		hermes_write_regn(hw, EVACK, 0xffff);	}		/* firmware will have to reassociate */	netif_carrier_off(dev);	priv->last_linkstatus = 0xffff;	return 0;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -