416 |
* port. This is supposed to allow 802.1x to work sanely, but |
* port. This is supposed to allow 802.1x to work sanely, but |
417 |
* doesn't seem to yet. |
* doesn't seem to yet. |
418 |
* |
* |
419 |
|
* v0.14alpha2 -> ??? - ???? - David Gibson |
420 |
|
* o |
421 |
|
* |
422 |
* TODO |
* TODO |
423 |
* o New wireless extensions API (patch from Moustafa |
* o New wireless extensions API (patch from Moustafa |
424 |
* Youssef, updated by Jim Carter and Pavel Roskin). |
* Youssef, updated by Jim Carter and Pavel Roskin). |
535 |
HERMES_MAX_MULTICAST : 0)*/ |
HERMES_MAX_MULTICAST : 0)*/ |
536 |
#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) |
#define MAX_MULTICAST(priv) (HERMES_MAX_MULTICAST) |
537 |
|
|
538 |
|
#define ORINOCO_INTEN (HERMES_EV_RX | HERMES_EV_ALLOC \ |
539 |
|
| HERMES_EV_TX | HERMES_EV_TXEXC \ |
540 |
|
| HERMES_EV_WTERR | HERMES_EV_INFO \ |
541 |
|
| HERMES_EV_INFDROP ) |
542 |
|
|
543 |
/********************************************************************/ |
/********************************************************************/ |
544 |
/* Data tables */ |
/* Data tables */ |
545 |
/********************************************************************/ |
/********************************************************************/ |
571 |
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) |
#define BITRATE_TABLE_SIZE ARRAY_SIZE(bitrate_table) |
572 |
|
|
573 |
/********************************************************************/ |
/********************************************************************/ |
574 |
|
/* Data types */ |
575 |
|
/********************************************************************/ |
576 |
|
|
577 |
|
/********************************************************************/ |
578 |
/* Function prototypes */ |
/* Function prototypes */ |
579 |
/********************************************************************/ |
/********************************************************************/ |
580 |
|
|
581 |
|
static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); |
582 |
|
|
583 |
|
static int orinoco_debug_dump_recs(struct net_device *dev); |
584 |
|
|
585 |
|
static int __orinoco_program_rids(struct net_device *dev); |
586 |
|
static void __orinoco_set_multicast_list(struct net_device *dev); |
587 |
|
|
588 |
|
/********************************************************************/ |
589 |
|
/* Internal helper functions */ |
590 |
|
/********************************************************************/ |
591 |
|
|
592 |
|
static inline void set_port_type(struct orinoco_private *priv) |
593 |
|
{ |
594 |
|
switch (priv->iw_mode) { |
595 |
|
case IW_MODE_INFRA: |
596 |
|
priv->port_type = 1; |
597 |
|
priv->createibss = 0; |
598 |
|
break; |
599 |
|
case IW_MODE_ADHOC: |
600 |
|
if (priv->prefer_port3) { |
601 |
|
priv->port_type = 3; |
602 |
|
priv->createibss = 0; |
603 |
|
} else { |
604 |
|
priv->port_type = priv->ibss_port; |
605 |
|
priv->createibss = 1; |
606 |
|
} |
607 |
|
break; |
608 |
|
default: |
609 |
|
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", |
610 |
|
priv->ndev->name); |
611 |
|
} |
612 |
|
} |
613 |
|
|
614 |
|
/********************************************************************/ |
615 |
|
/* Device methods */ |
616 |
|
/********************************************************************/ |
617 |
|
|
618 |
|
static int orinoco_open(struct net_device *dev) |
619 |
|
{ |
620 |
|
struct orinoco_private *priv = dev->priv; |
621 |
|
unsigned long flags; |
622 |
|
int err; |
623 |
|
|
624 |
|
err = orinoco_lock(priv, &flags); |
625 |
|
if (err) |
626 |
|
return err; |
627 |
|
|
628 |
|
err = __orinoco_up(dev); |
629 |
|
|
630 |
|
if (! err) |
631 |
|
priv->open = 1; |
632 |
|
|
633 |
|
orinoco_unlock(priv, &flags); |
634 |
|
|
635 |
|
return err; |
636 |
|
} |
637 |
|
|
638 |
|
int orinoco_stop(struct net_device *dev) |
639 |
|
{ |
640 |
|
struct orinoco_private *priv = dev->priv; |
641 |
|
int err = 0; |
642 |
|
|
643 |
|
/* We mustn't use orinoco_lock() here, because we need to be |
644 |
|
able to close the interface even if hw_unavailable is set |
645 |
|
(e.g. as we're released after a PC Card removal) */ |
646 |
|
orinoco_spin_lock(priv); |
647 |
|
|
648 |
|
priv->open = 0; |
649 |
|
|
650 |
|
err = __orinoco_down(dev); |
651 |
|
|
652 |
|
orinoco_spin_unlock(priv); |
653 |
|
|
654 |
|
return err; |
655 |
|
} |
656 |
|
|
657 |
|
struct net_device_stats *orinoco_get_stats(struct net_device *dev) |
658 |
|
{ |
659 |
|
struct orinoco_private *priv = dev->priv; |
660 |
|
|
661 |
|
return &priv->stats; |
662 |
|
} |
663 |
|
|
664 |
|
struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev) |
665 |
|
{ |
666 |
|
struct orinoco_private *priv = dev->priv; |
667 |
|
hermes_t *hw = &priv->hw; |
668 |
|
struct iw_statistics *wstats = &priv->wstats; |
669 |
|
int err = 0; |
670 |
|
unsigned long flags; |
671 |
|
|
672 |
|
if (! netif_device_present(dev)) { |
673 |
|
printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", |
674 |
|
dev->name); |
675 |
|
return NULL; /* FIXME: Can we do better than this? */ |
676 |
|
} |
677 |
|
|
678 |
|
err = orinoco_lock(priv, &flags); |
679 |
|
if (err) |
680 |
|
return NULL; /* FIXME: Erg, we've been signalled, how |
681 |
|
* do we propagate this back up? */ |
682 |
|
|
683 |
|
if (priv->iw_mode == IW_MODE_ADHOC) { |
684 |
|
memset(&wstats->qual, 0, sizeof(wstats->qual)); |
685 |
|
/* If a spy address is defined, we report stats of the |
686 |
|
* first spy address - Jean II */ |
687 |
|
if (SPY_NUMBER(priv)) { |
688 |
|
wstats->qual.qual = priv->spy_stat[0].qual; |
689 |
|
wstats->qual.level = priv->spy_stat[0].level; |
690 |
|
wstats->qual.noise = priv->spy_stat[0].noise; |
691 |
|
wstats->qual.updated = priv->spy_stat[0].updated; |
692 |
|
} |
693 |
|
} else { |
694 |
|
struct { |
695 |
|
u16 qual, signal, noise; |
696 |
|
} __attribute__ ((packed)) cq; |
697 |
|
|
698 |
|
err = HERMES_READ_RECORD(hw, USER_BAP, |
699 |
|
HERMES_RID_COMMSQUALITY, &cq); |
700 |
|
|
701 |
|
wstats->qual.qual = (int)le16_to_cpu(cq.qual); |
702 |
|
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; |
703 |
|
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; |
704 |
|
wstats->qual.updated = 7; |
705 |
|
} |
706 |
|
|
707 |
|
/* We can't really wait for the tallies inquiry command to |
708 |
|
* complete, so we just use the previous results and trigger |
709 |
|
* a new tallies inquiry command for next time - Jean II */ |
710 |
|
/* FIXME: We're in user context (I think?), so we should just |
711 |
|
wait for the tallies to come through */ |
712 |
|
err = hermes_inquire(hw, HERMES_INQ_TALLIES); |
713 |
|
|
714 |
|
orinoco_unlock(priv, &flags); |
715 |
|
|
716 |
|
if (err) |
717 |
|
return NULL; |
718 |
|
|
719 |
|
return wstats; |
720 |
|
} |
721 |
|
|
722 |
|
static void orinoco_set_multicast_list(struct net_device *dev) |
723 |
|
{ |
724 |
|
struct orinoco_private *priv = dev->priv; |
725 |
|
unsigned long flags; |
726 |
|
|
727 |
|
if (orinoco_lock(priv, &flags) != 0) { |
728 |
|
printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " |
729 |
|
"called when hw_unavailable\n", dev->name); |
730 |
|
return; |
731 |
|
} |
732 |
|
|
733 |
|
__orinoco_set_multicast_list(dev); |
734 |
|
orinoco_unlock(priv, &flags); |
735 |
|
} |
736 |
|
|
737 |
|
static int orinoco_change_mtu(struct net_device *dev, int new_mtu) |
738 |
|
{ |
739 |
|
struct orinoco_private *priv = dev->priv; |
740 |
|
|
741 |
|
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) |
742 |
|
return -EINVAL; |
743 |
|
|
744 |
|
if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > |
745 |
|
(priv->nicbuf_size - ETH_HLEN) ) |
746 |
|
return -EINVAL; |
747 |
|
|
748 |
|
dev->mtu = new_mtu; |
749 |
|
|
750 |
|
return 0; |
751 |
|
} |
752 |
|
|
753 |
|
/********************************************************************/ |
754 |
|
/* Tx path */ |
755 |
|
/********************************************************************/ |
756 |
|
|
757 |
|
static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) |
758 |
|
{ |
759 |
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
760 |
|
struct net_device_stats *stats = &priv->stats; |
761 |
|
hermes_t *hw = &priv->hw; |
762 |
|
int err = 0; |
763 |
|
u16 txfid = priv->txfid; |
764 |
|
char *p; |
765 |
|
struct ethhdr *eh; |
766 |
|
int len, data_len, data_off; |
767 |
|
struct hermes_tx_descriptor desc; |
768 |
|
unsigned long flags; |
769 |
|
|
770 |
|
TRACE_ENTER(dev->name); |
771 |
|
|
772 |
|
if (! netif_running(dev)) { |
773 |
|
printk(KERN_ERR "%s: Tx on stopped device!\n", |
774 |
|
dev->name); |
775 |
|
TRACE_EXIT(dev->name); |
776 |
|
return 1; |
777 |
|
} |
778 |
|
|
779 |
|
if (netif_queue_stopped(dev)) { |
780 |
|
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", |
781 |
|
dev->name); |
782 |
|
TRACE_EXIT(dev->name); |
783 |
|
return 1; |
784 |
|
} |
785 |
|
|
786 |
|
if (orinoco_lock(priv, &flags) != 0) { |
787 |
|
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", |
788 |
|
dev->name); |
789 |
|
TRACE_EXIT(dev->name); |
790 |
|
return 1; |
791 |
|
} |
792 |
|
|
793 |
|
if (! netif_carrier_ok(dev)) { |
794 |
|
/* Oops, the firmware hasn't established a connection, |
795 |
|
silently drop the packet (this seems to be the |
796 |
|
safest approach). */ |
797 |
|
stats->tx_errors++; |
798 |
|
orinoco_unlock(priv, &flags); |
799 |
|
dev_kfree_skb(skb); |
800 |
|
TRACE_EXIT(dev->name); |
801 |
|
return 0; |
802 |
|
} |
803 |
|
|
804 |
|
/* Length of the packet body */ |
805 |
|
/* FIXME: what if the skb is smaller than this? */ |
806 |
|
len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); |
807 |
|
|
808 |
|
eh = (struct ethhdr *)skb->data; |
809 |
|
|
810 |
|
memset(&desc, 0, sizeof(desc)); |
811 |
|
desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); |
812 |
|
err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); |
813 |
|
if (err) { |
814 |
|
printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", |
815 |
|
dev->name, err); |
816 |
|
stats->tx_errors++; |
817 |
|
goto fail; |
818 |
|
} |
819 |
|
|
820 |
|
/* Clear the 802.11 header and data length fields - some |
821 |
|
* firmwares (e.g. Lucent/Agere 8.xx) appear to get confused |
822 |
|
* if this isn't done. */ |
823 |
|
hermes_clear_words(hw, HERMES_DATA0, |
824 |
|
HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); |
825 |
|
|
826 |
|
/* Encapsulate Ethernet-II frames */ |
827 |
|
if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ |
828 |
|
struct header_struct hdr; |
829 |
|
data_len = len; |
830 |
|
data_off = HERMES_802_3_OFFSET + sizeof(hdr); |
831 |
|
p = skb->data + ETH_HLEN; |
832 |
|
|
833 |
|
/* 802.3 header */ |
834 |
|
memcpy(hdr.dest, eh->h_dest, ETH_ALEN); |
835 |
|
memcpy(hdr.src, eh->h_source, ETH_ALEN); |
836 |
|
hdr.len = htons(data_len + ENCAPS_OVERHEAD); |
837 |
|
|
838 |
|
/* 802.2 header */ |
839 |
|
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); |
840 |
|
|
841 |
|
hdr.ethertype = eh->h_proto; |
842 |
|
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), |
843 |
|
txfid, HERMES_802_3_OFFSET); |
844 |
|
if (err) { |
845 |
|
printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", |
846 |
|
dev->name, err); |
847 |
|
stats->tx_errors++; |
848 |
|
goto fail; |
849 |
|
} |
850 |
|
} else { /* IEEE 802.3 frame */ |
851 |
|
data_len = len + ETH_HLEN; |
852 |
|
data_off = HERMES_802_3_OFFSET; |
853 |
|
p = skb->data; |
854 |
|
} |
855 |
|
|
856 |
|
/* Round up for odd length packets */ |
857 |
|
err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), |
858 |
|
txfid, data_off); |
859 |
|
if (err) { |
860 |
|
printk(KERN_ERR "%s: Error %d writing packet to BAP\n", |
861 |
|
dev->name, err); |
862 |
|
stats->tx_errors++; |
863 |
|
goto fail; |
864 |
|
} |
865 |
|
|
866 |
|
/* Finally, we actually initiate the send */ |
867 |
|
netif_stop_queue(dev); |
868 |
|
|
869 |
|
err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, |
870 |
|
txfid, NULL); |
871 |
|
if (err) { |
872 |
|
netif_start_queue(dev); |
873 |
|
printk(KERN_ERR "%s: Error %d transmitting packet\n", |
874 |
|
dev->name, err); |
875 |
|
stats->tx_errors++; |
876 |
|
goto fail; |
877 |
|
} |
878 |
|
|
879 |
|
dev->trans_start = jiffies; |
880 |
|
stats->tx_bytes += data_off + data_len; |
881 |
|
|
882 |
|
orinoco_unlock(priv, &flags); |
883 |
|
|
884 |
|
dev_kfree_skb(skb); |
885 |
|
|
886 |
|
TRACE_EXIT(dev->name); |
887 |
|
|
888 |
|
return 0; |
889 |
|
fail: |
890 |
|
TRACE_EXIT(dev->name); |
891 |
|
|
892 |
|
orinoco_unlock(priv, &flags); |
893 |
|
return err; |
894 |
|
} |
895 |
|
|
896 |
|
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) |
897 |
|
{ |
898 |
|
struct orinoco_private *priv = dev->priv; |
899 |
|
u16 fid = hermes_read_regn(hw, ALLOCFID); |
900 |
|
|
901 |
|
if (fid != priv->txfid) { |
902 |
|
if (fid != DUMMY_FID) |
903 |
|
printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", |
904 |
|
dev->name, fid); |
905 |
|
return; |
906 |
|
} |
907 |
|
|
908 |
|
hermes_write_regn(hw, ALLOCFID, DUMMY_FID); |
909 |
|
} |
910 |
|
|
911 |
|
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) |
912 |
|
{ |
913 |
|
struct orinoco_private *priv = dev->priv; |
914 |
|
struct net_device_stats *stats = &priv->stats; |
915 |
|
|
916 |
|
stats->tx_packets++; |
917 |
|
|
918 |
|
netif_wake_queue(dev); |
919 |
|
|
920 |
|
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); |
921 |
|
} |
922 |
|
|
923 |
|
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) |
924 |
|
{ |
925 |
|
struct orinoco_private *priv = dev->priv; |
926 |
|
struct net_device_stats *stats = &priv->stats; |
927 |
|
u16 fid = hermes_read_regn(hw, TXCOMPLFID); |
928 |
|
struct hermes_tx_descriptor desc; |
929 |
|
int err = 0; |
930 |
|
|
931 |
|
if (fid == DUMMY_FID) |
932 |
|
return; /* Nothing's really happened */ |
933 |
|
|
934 |
|
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); |
935 |
|
if (err) { |
936 |
|
printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " |
937 |
|
"(FID=%04X error %d)\n", |
938 |
|
dev->name, fid, err); |
939 |
|
} else { |
940 |
|
DEBUG(1, "%s: Tx error, status %d\n", |
941 |
|
dev->name, le16_to_cpu(desc.status)); |
942 |
|
} |
943 |
|
|
944 |
|
stats->tx_errors++; |
945 |
|
|
946 |
|
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); |
947 |
|
} |
948 |
|
|
949 |
|
static void orinoco_tx_timeout(struct net_device *dev) |
950 |
|
{ |
951 |
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
952 |
|
struct net_device_stats *stats = &priv->stats; |
953 |
|
struct hermes *hw = &priv->hw; |
954 |
|
|
955 |
|
printk(KERN_WARNING "%s: Tx timeout! " |
956 |
|
"ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", |
957 |
|
dev->name, hermes_read_regn(hw, ALLOCFID), |
958 |
|
hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); |
959 |
|
|
960 |
|
stats->tx_errors++; |
961 |
|
|
962 |
|
schedule_work(&priv->reset_work); |
963 |
|
} |
964 |
|
|
965 |
|
/********************************************************************/ |
966 |
|
/* Rx path (data frames) */ |
967 |
|
/********************************************************************/ |
968 |
|
|
969 |
|
/* Does the frame have a SNAP header indicating it should be |
970 |
|
* de-encapsulated to Ethernet-II? */ |
971 |
|
static inline int is_ethersnap(struct header_struct *hdr) |
972 |
|
{ |
973 |
|
/* We de-encapsulate all packets which, a) have SNAP headers |
974 |
|
* (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header |
975 |
|
* and where b) the OUI of the SNAP header is 00:00:00 or |
976 |
|
* 00:00:f8 - we need both because different APs appear to use |
977 |
|
* different OUIs for some reason */ |
978 |
|
return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) |
979 |
|
&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); |
980 |
|
} |
981 |
|
|
982 |
|
static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, |
983 |
|
int level, int noise) |
984 |
|
{ |
985 |
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
986 |
|
int i; |
987 |
|
|
988 |
|
/* Gather wireless spy statistics: for each packet, compare the |
989 |
|
* source address with out list, and if match, get the stats... */ |
990 |
|
for (i = 0; i < priv->spy_number; i++) |
991 |
|
if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { |
992 |
|
priv->spy_stat[i].level = level - 0x95; |
993 |
|
priv->spy_stat[i].noise = noise - 0x95; |
994 |
|
priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; |
995 |
|
priv->spy_stat[i].updated = 7; |
996 |
|
} |
997 |
|
} |
998 |
|
|
999 |
static void orinoco_stat_gather(struct net_device *dev, |
static void orinoco_stat_gather(struct net_device *dev, |
1000 |
struct sk_buff *skb, |
struct sk_buff *skb, |
1001 |
struct hermes_rx_descriptor *desc); |
struct hermes_rx_descriptor *desc) |
1002 |
|
{ |
1003 |
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
1004 |
|
|
1005 |
static struct net_device_stats *orinoco_get_stats(struct net_device *dev); |
/* Using spy support with lots of Rx packets, like in an |
1006 |
static struct iw_statistics *orinoco_get_wireless_stats(struct net_device *dev); |
* infrastructure (AP), will really slow down everything, because |
1007 |
|
* the MAC address must be compared to each entry of the spy list. |
1008 |
|
* If the user really asks for it (set some address in the |
1009 |
|
* spy list), we do it, but he will pay the price. |
1010 |
|
* Note that to get here, you need both WIRELESS_SPY |
1011 |
|
* compiled in AND some addresses in the list !!! |
1012 |
|
*/ |
1013 |
|
/* Note : gcc will optimise the whole section away if |
1014 |
|
* WIRELESS_SPY is not defined... - Jean II */ |
1015 |
|
if (SPY_NUMBER(priv)) { |
1016 |
|
orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, |
1017 |
|
desc->signal, desc->silence); |
1018 |
|
} |
1019 |
|
} |
1020 |
|
|
1021 |
/* Hardware control routines */ |
void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) |
1022 |
|
{ |
1023 |
|
struct orinoco_private *priv = dev->priv; |
1024 |
|
struct net_device_stats *stats = &priv->stats; |
1025 |
|
struct iw_statistics *wstats = &priv->wstats; |
1026 |
|
struct sk_buff *skb = NULL; |
1027 |
|
u16 rxfid, status; |
1028 |
|
int length, data_len, data_off; |
1029 |
|
char *p; |
1030 |
|
struct hermes_rx_descriptor desc; |
1031 |
|
struct header_struct hdr; |
1032 |
|
struct ethhdr *eh; |
1033 |
|
int err; |
1034 |
|
|
1035 |
static int __orinoco_program_rids(struct net_device *dev); |
rxfid = hermes_read_regn(hw, RXFID); |
1036 |
|
|
1037 |
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv); |
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), |
1038 |
static int __orinoco_hw_setup_wep(struct orinoco_private *priv); |
rxfid, 0); |
1039 |
static int orinoco_hw_get_bssid(struct orinoco_private *priv, char buf[ETH_ALEN]); |
if (err) { |
1040 |
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, |
printk(KERN_ERR "%s: error %d reading Rx descriptor. " |
1041 |
char buf[IW_ESSID_MAX_SIZE+1]); |
"Frame dropped.\n", dev->name, err); |
1042 |
static long orinoco_hw_get_freq(struct orinoco_private *priv); |
stats->rx_errors++; |
1043 |
static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, int *numrates, |
goto drop; |
1044 |
s32 *rates, int max); |
} |
|
static void __orinoco_set_multicast_list(struct net_device *dev); |
|
1045 |
|
|
1046 |
/* Interrupt handling routines */ |
status = le16_to_cpu(desc.status); |
1047 |
static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw); |
|
1048 |
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw); |
if (status & HERMES_RXSTAT_ERR) { |
1049 |
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw); |
if (status & HERMES_RXSTAT_UNDECRYPTABLE) { |
1050 |
void __orinoco_ev_info(struct net_device *dev, hermes_t *hw); |
wstats->discard.code++; |
1051 |
void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw); |
DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", |
1052 |
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw); |
dev->name); |
1053 |
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw); |
} else { |
1054 |
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw); |
stats->rx_crc_errors++; |
1055 |
|
DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); |
1056 |
|
} |
1057 |
|
stats->rx_errors++; |
1058 |
|
goto drop; |
1059 |
|
} |
1060 |
|
|
1061 |
/* ioctl() routines */ |
/* For now we ignore the 802.11 header completely, assuming |
1062 |
static int orinoco_debug_dump_recs(struct net_device *dev); |
that the card's firmware has handled anything vital */ |
1063 |
|
|
1064 |
|
err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), |
1065 |
|
rxfid, HERMES_802_3_OFFSET); |
1066 |
|
if (err) { |
1067 |
|
printk(KERN_ERR "%s: error %d reading frame header. " |
1068 |
|
"Frame dropped.\n", dev->name, err); |
1069 |
|
stats->rx_errors++; |
1070 |
|
goto drop; |
1071 |
|
} |
1072 |
|
|
1073 |
|
length = ntohs(hdr.len); |
1074 |
|
|
1075 |
|
/* Sanity checks */ |
1076 |
|
if (length < 3) { /* No for even an 802.2 LLC header */ |
1077 |
|
/* At least on Symbol firmware with PCF we get quite a |
1078 |
|
lot of these legitimately - Poll frames with no |
1079 |
|
data. */ |
1080 |
|
stats->rx_dropped++; |
1081 |
|
goto drop; |
1082 |
|
} |
1083 |
|
if (length > IEEE802_11_DATA_LEN) { |
1084 |
|
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", |
1085 |
|
dev->name, length); |
1086 |
|
stats->rx_length_errors++; |
1087 |
|
stats->rx_errors++; |
1088 |
|
goto drop; |
1089 |
|
} |
1090 |
|
|
1091 |
|
/* We need space for the packet data itself, plus an ethernet |
1092 |
|
header, plus 2 bytes so we can align the IP header on a |
1093 |
|
32bit boundary, plus 1 byte so we can read in odd length |
1094 |
|
packets from the card, which has an IO granularity of 16 |
1095 |
|
bits */ |
1096 |
|
skb = dev_alloc_skb(length+ETH_HLEN+2+1); |
1097 |
|
if (!skb) { |
1098 |
|
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", |
1099 |
|
dev->name); |
1100 |
|
goto drop; |
1101 |
|
} |
1102 |
|
|
1103 |
|
skb_reserve(skb, 2); /* This way the IP header is aligned */ |
1104 |
|
|
1105 |
|
/* Handle decapsulation |
1106 |
|
* In most cases, the firmware tell us about SNAP frames. |
1107 |
|
* For some reason, the SNAP frames sent by LinkSys APs |
1108 |
|
* are not properly recognised by most firmwares. |
1109 |
|
* So, check ourselves */ |
1110 |
|
if(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || |
1111 |
|
((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || |
1112 |
|
is_ethersnap(&hdr)) { |
1113 |
|
/* These indicate a SNAP within 802.2 LLC within |
1114 |
|
802.11 frame which we'll need to de-encapsulate to |
1115 |
|
the original EthernetII frame. */ |
1116 |
|
|
1117 |
|
if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ |
1118 |
|
stats->rx_length_errors++; |
1119 |
|
goto drop; |
1120 |
|
} |
1121 |
|
|
1122 |
|
/* Remove SNAP header, reconstruct EthernetII frame */ |
1123 |
|
data_len = length - ENCAPS_OVERHEAD; |
1124 |
|
data_off = HERMES_802_3_OFFSET + sizeof(hdr); |
1125 |
|
|
1126 |
|
eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); |
1127 |
|
|
1128 |
|
memcpy(eh, &hdr, 2 * ETH_ALEN); |
1129 |
|
eh->h_proto = hdr.ethertype; |
1130 |
|
} else { |
1131 |
|
/* All other cases indicate a genuine 802.3 frame. No |
1132 |
|
decapsulation needed. We just throw the whole |
1133 |
|
thing in, and hope the protocol layer can deal with |
1134 |
|
it as 802.3 */ |
1135 |
|
data_len = length; |
1136 |
|
data_off = HERMES_802_3_OFFSET; |
1137 |
|
/* FIXME: we re-read from the card data we already read here */ |
1138 |
|
} |
1139 |
|
|
1140 |
|
p = skb_put(skb, data_len); |
1141 |
|
err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), |
1142 |
|
rxfid, data_off); |
1143 |
|
if (err) { |
1144 |
|
printk(KERN_ERR "%s: error %d reading frame. " |
1145 |
|
"Frame dropped.\n", dev->name, err); |
1146 |
|
stats->rx_errors++; |
1147 |
|
goto drop; |
1148 |
|
} |
1149 |
|
|
1150 |
|
dev->last_rx = jiffies; |
1151 |
|
skb->dev = dev; |
1152 |
|
skb->protocol = eth_type_trans(skb, dev); |
1153 |
|
skb->ip_summed = CHECKSUM_NONE; |
1154 |
|
|
1155 |
|
/* Process the wireless stats if needed */ |
1156 |
|
orinoco_stat_gather(dev, skb, &desc); |
1157 |
|
|
1158 |
|
/* Pass the packet to the networking stack */ |
1159 |
|
netif_rx(skb); |
1160 |
|
stats->rx_packets++; |
1161 |
|
stats->rx_bytes += length; |
1162 |
|
|
1163 |
|
return; |
1164 |
|
|
1165 |
|
drop: |
1166 |
|
stats->rx_dropped++; |
1167 |
|
|
1168 |
|
if (skb) |
1169 |
|
dev_kfree_skb_irq(skb); |
1170 |
|
return; |
1171 |
|
} |
1172 |
|
|
1173 |
/********************************************************************/ |
/********************************************************************/ |
1174 |
/* Function prototypes */ |
/* Rx path (info frames) */ |
1175 |
|
/********************************************************************/ |
1176 |
|
|
1177 |
|
static void print_linkstatus(struct net_device *dev, u16 status) |
1178 |
|
{ |
1179 |
|
char * s; |
1180 |
|
|
1181 |
|
if (suppress_linkstatus) |
1182 |
|
return; |
1183 |
|
|
1184 |
|
switch (status) { |
1185 |
|
case HERMES_LINKSTATUS_NOT_CONNECTED: |
1186 |
|
s = "Not Connected"; |
1187 |
|
break; |
1188 |
|
case HERMES_LINKSTATUS_CONNECTED: |
1189 |
|
s = "Connected"; |
1190 |
|
break; |
1191 |
|
case HERMES_LINKSTATUS_DISCONNECTED: |
1192 |
|
s = "Disconnected"; |
1193 |
|
break; |
1194 |
|
case HERMES_LINKSTATUS_AP_CHANGE: |
1195 |
|
s = "AP Changed"; |
1196 |
|
break; |
1197 |
|
case HERMES_LINKSTATUS_AP_OUT_OF_RANGE: |
1198 |
|
s = "AP Out of Range"; |
1199 |
|
break; |
1200 |
|
case HERMES_LINKSTATUS_AP_IN_RANGE: |
1201 |
|
s = "AP In Range"; |
1202 |
|
break; |
1203 |
|
case HERMES_LINKSTATUS_ASSOC_FAILED: |
1204 |
|
s = "Association Failed"; |
1205 |
|
break; |
1206 |
|
default: |
1207 |
|
s = "UNKNOWN"; |
1208 |
|
} |
1209 |
|
|
1210 |
|
printk(KERN_INFO "%s: New link status: %s (%04x)\n", |
1211 |
|
dev->name, s, status); |
1212 |
|
} |
1213 |
|
|
1214 |
|
void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) |
1215 |
|
{ |
1216 |
|
struct orinoco_private *priv = dev->priv; |
1217 |
|
u16 infofid; |
1218 |
|
struct { |
1219 |
|
u16 len; |
1220 |
|
u16 type; |
1221 |
|
} __attribute__ ((packed)) info; |
1222 |
|
int len, type; |
1223 |
|
int err; |
1224 |
|
|
1225 |
|
/* This is an answer to an INQUIRE command that we did earlier, |
1226 |
|
* or an information "event" generated by the card |
1227 |
|
* The controller return to us a pseudo frame containing |
1228 |
|
* the information in question - Jean II */ |
1229 |
|
infofid = hermes_read_regn(hw, INFOFID); |
1230 |
|
|
1231 |
|
/* Read the info frame header - don't try too hard */ |
1232 |
|
err = hermes_bap_pread(hw, IRQ_BAP, &info, sizeof(info), |
1233 |
|
infofid, 0); |
1234 |
|
if (err) { |
1235 |
|
printk(KERN_ERR "%s: error %d reading info frame. " |
1236 |
|
"Frame dropped.\n", dev->name, err); |
1237 |
|
return; |
1238 |
|
} |
1239 |
|
|
1240 |
|
len = HERMES_RECLEN_TO_BYTES(le16_to_cpu(info.len)); |
1241 |
|
type = le16_to_cpu(info.type); |
1242 |
|
|
1243 |
|
switch (type) { |
1244 |
|
case HERMES_INQ_TALLIES: { |
1245 |
|
struct hermes_tallies_frame tallies; |
1246 |
|
struct iw_statistics *wstats = &priv->wstats; |
1247 |
|
|
1248 |
|
if (len > sizeof(tallies)) { |
1249 |
|
printk(KERN_WARNING "%s: Tallies frame too long (%d bytes)\n", |
1250 |
|
dev->name, len); |
1251 |
|
len = sizeof(tallies); |
1252 |
|
} |
1253 |
|
|
1254 |
|
/* Read directly the data (no seek) */ |
1255 |
|
/* FIXME: blech! ??? */ |
1256 |
|
hermes_bap_pread(hw, IRQ_BAP, &tallies, len, infofid, sizeof(info)); |
1257 |
|
|
1258 |
|
/* Increment our various counters */ |
1259 |
|
/* wstats->discard.nwid - no wrong BSSID stuff */ |
1260 |
|
wstats->discard.code += |
1261 |
|
le16_to_cpu(tallies.RxWEPUndecryptable); |
1262 |
|
if (len == sizeof(tallies)) |
1263 |
|
wstats->discard.code += |
1264 |
|
le16_to_cpu(tallies.RxDiscards_WEPICVError) + |
1265 |
|
le16_to_cpu(tallies.RxDiscards_WEPExcluded); |
1266 |
|
wstats->discard.misc += |
1267 |
|
le16_to_cpu(tallies.TxDiscardsWrongSA); |
1268 |
|
#if WIRELESS_EXT > 11 |
1269 |
|
wstats->discard.fragment += |
1270 |
|
le16_to_cpu(tallies.RxMsgInBadMsgFragments); |
1271 |
|
wstats->discard.retries += |
1272 |
|
le16_to_cpu(tallies.TxRetryLimitExceeded); |
1273 |
|
/* wstats->miss.beacon - no match */ |
1274 |
|
#endif /* WIRELESS_EXT > 11 */ |
1275 |
|
} |
1276 |
|
break; |
1277 |
|
case HERMES_INQ_LINKSTATUS: { |
1278 |
|
struct hermes_linkstatus linkstatus; |
1279 |
|
u16 newstatus; |
1280 |
|
|
1281 |
|
if (len != sizeof(linkstatus)) { |
1282 |
|
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", |
1283 |
|
dev->name, len); |
1284 |
|
break; |
1285 |
|
} |
1286 |
|
|
1287 |
|
hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len, infofid, sizeof(info)); |
1288 |
|
|
1289 |
|
newstatus = le16_to_cpu(linkstatus.linkstatus); |
1290 |
|
|
1291 |
|
if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) |
1292 |
|
|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE) |
1293 |
|
|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) |
1294 |
|
netif_carrier_on(dev); |
1295 |
|
else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) |
1296 |
|
|| (newstatus == HERMES_LINKSTATUS_DISCONNECTED) |
1297 |
|
|| (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) |
1298 |
|
|| (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) |
1299 |
|
netif_carrier_off(dev); |
1300 |
|
|
1301 |
|
if (newstatus != priv->last_linkstatus) |
1302 |
|
print_linkstatus(dev, newstatus); |
1303 |
|
|
1304 |
|
priv->last_linkstatus = newstatus; |
1305 |
|
} |
1306 |
|
break; |
1307 |
|
default: |
1308 |
|
printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n", |
1309 |
|
dev->name, type); |
1310 |
|
/* We don't actually do anything about it */ |
1311 |
|
break; |
1312 |
|
} |
1313 |
|
} |
1314 |
|
|
1315 |
|
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) |
1316 |
|
{ |
1317 |
|
printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); |
1318 |
|
} |
1319 |
|
|
1320 |
|
/********************************************************************/ |
1321 |
|
/* Internal hardware control routines */ |
1322 |
/********************************************************************/ |
/********************************************************************/ |
1323 |
|
|
1324 |
int __orinoco_up(struct net_device *dev) |
int __orinoco_up(struct net_device *dev) |
1409 |
return err; |
return err; |
1410 |
} |
} |
1411 |
|
|
1412 |
static int orinoco_open(struct net_device *dev) |
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) |
1413 |
{ |
{ |
1414 |
struct orinoco_private *priv = dev->priv; |
hermes_t *hw = &priv->hw; |
1415 |
unsigned long flags; |
int err = 0; |
|
int err; |
|
1416 |
|
|
1417 |
err = orinoco_lock(priv, &flags); |
if (priv->bitratemode >= BITRATE_TABLE_SIZE) { |
1418 |
if (err) |
printk(KERN_ERR "%s: BUG: Invalid bitrate mode %d\n", |
1419 |
return err; |
priv->ndev->name, priv->bitratemode); |
1420 |
|
return -EINVAL; |
1421 |
|
} |
1422 |
|
|
1423 |
err = __orinoco_up(dev); |
switch (priv->firmware_type) { |
1424 |
|
case FIRMWARE_TYPE_AGERE: |
1425 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1426 |
|
HERMES_RID_CNFTXRATECONTROL, |
1427 |
|
bitrate_table[priv->bitratemode].agere_txratectrl); |
1428 |
|
break; |
1429 |
|
case FIRMWARE_TYPE_INTERSIL: |
1430 |
|
case FIRMWARE_TYPE_SYMBOL: |
1431 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1432 |
|
HERMES_RID_CNFTXRATECONTROL, |
1433 |
|
bitrate_table[priv->bitratemode].intersil_txratectrl); |
1434 |
|
break; |
1435 |
|
default: |
1436 |
|
BUG(); |
1437 |
|
} |
1438 |
|
|
1439 |
if (! err) |
return err; |
1440 |
priv->open = 1; |
} |
1441 |
|
|
1442 |
orinoco_unlock(priv, &flags); |
/* Just switch the WEP key, without changing other WEP/authentication |
1443 |
|
* parameters. Used on firmware that can handle it to switch the key |
1444 |
|
* without breaking the association, which is necessary for 802.1x */ |
1445 |
|
static int __orinoco_fastkeychange(struct orinoco_private *priv) |
1446 |
|
{ |
1447 |
|
hermes_t *hw = &priv->hw; |
1448 |
|
int err = 0; |
1449 |
|
|
1450 |
return err; |
if (! priv->wep_on) { |
1451 |
|
printk(KERN_DEBUG "%s: __orinoco_fastkeychange while WEP disabled!?\n", |
1452 |
|
priv->ndev->name); |
1453 |
|
return 0; |
1454 |
|
} |
1455 |
|
|
1456 |
|
if (! priv->has_fastkeychange) |
1457 |
|
return -EAGAIN; |
1458 |
|
|
1459 |
|
switch (priv->firmware_type) { |
1460 |
|
case FIRMWARE_TYPE_AGERE: |
1461 |
|
err = HERMES_WRITE_RECORD(hw, USER_BAP, |
1462 |
|
HERMES_RID_CNFWEPKEYS_AGERE, |
1463 |
|
&priv->keys); |
1464 |
|
if (err) |
1465 |
|
return err; |
1466 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1467 |
|
HERMES_RID_CNFTXKEY_AGERE, |
1468 |
|
priv->tx_key); |
1469 |
|
if (err) |
1470 |
|
return err; |
1471 |
|
break; |
1472 |
|
case FIRMWARE_TYPE_INTERSIL: |
1473 |
|
case FIRMWARE_TYPE_SYMBOL: |
1474 |
|
/* FIXME: do any non-Agere firmwares support fast key |
1475 |
|
* change? */ |
1476 |
|
return -EAGAIN; |
1477 |
|
break; |
1478 |
|
} |
1479 |
|
|
1480 |
|
return 0; |
1481 |
} |
} |
1482 |
|
|
1483 |
int orinoco_stop(struct net_device *dev) |
static int __orinoco_hw_setup_wep(struct orinoco_private *priv) |
1484 |
{ |
{ |
1485 |
struct orinoco_private *priv = dev->priv; |
hermes_t *hw = &priv->hw; |
1486 |
int err = 0; |
int err = 0; |
1487 |
|
int master_wep_flag; |
1488 |
|
int auth_flag; |
1489 |
|
|
1490 |
/* We mustn't use orinoco_lock() here, because we need to be |
switch (priv->firmware_type) { |
1491 |
able to close the interface even if hw_unavailable is set |
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ |
1492 |
(e.g. as we're released after a PC Card removal) */ |
if (priv->wep_on) { |
1493 |
orinoco_spin_lock(priv); |
/* Enable the shared-key authentication. */ |
1494 |
|
/* FIXME: We never clear the authentication flag... */ |
1495 |
|
if (priv->wep_restrict) |
1496 |
|
auth_flag = 0x2; |
1497 |
|
else |
1498 |
|
auth_flag = 0x0; |
1499 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1500 |
|
HERMES_RID_CNFAUTHENTICATION_AGERE, |
1501 |
|
auth_flag); |
1502 |
|
if (err) |
1503 |
|
return err; |
1504 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1505 |
|
HERMES_RID_CNFTXKEY_AGERE, |
1506 |
|
priv->tx_key); |
1507 |
|
if (err) |
1508 |
|
return err; |
1509 |
|
|
1510 |
|
err = HERMES_WRITE_RECORD(hw, USER_BAP, |
1511 |
|
HERMES_RID_CNFWEPKEYS_AGERE, |
1512 |
|
&priv->keys); |
1513 |
|
if (err) |
1514 |
|
return err; |
1515 |
|
} |
1516 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1517 |
|
HERMES_RID_CNFWEPENABLED_AGERE, |
1518 |
|
priv->wep_on); |
1519 |
|
if (err) |
1520 |
|
return err; |
1521 |
|
break; |
1522 |
|
|
1523 |
priv->open = 0; |
case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ |
1524 |
|
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ |
1525 |
|
master_wep_flag = 0; /* Off */ |
1526 |
|
if (priv->wep_on) { |
1527 |
|
int keylen; |
1528 |
|
int i; |
1529 |
|
|
1530 |
err = __orinoco_down(dev); |
/* Fudge around firmware weirdness */ |
1531 |
|
keylen = le16_to_cpu(priv->keys[priv->tx_key].len); |
1532 |
|
|
1533 |
|
/* Write all 4 keys */ |
1534 |
|
for(i = 0; i < ORINOCO_MAX_KEYS; i++) { |
1535 |
|
/* int keylen = le16_to_cpu(priv->keys[i].len); */ |
1536 |
|
|
1537 |
|
if (keylen > LARGE_KEY_SIZE) { |
1538 |
|
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", |
1539 |
|
priv->ndev->name, i, keylen); |
1540 |
|
return -E2BIG; |
1541 |
|
} |
1542 |
|
|
1543 |
orinoco_spin_unlock(priv); |
err = hermes_write_ltv(hw, USER_BAP, |
1544 |
|
HERMES_RID_CNFDEFAULTKEY0 + i, |
1545 |
|
HERMES_BYTES_TO_RECLEN(keylen), |
1546 |
|
priv->keys[i].data); |
1547 |
|
if (err) |
1548 |
|
return err; |
1549 |
|
} |
1550 |
|
|
1551 |
return err; |
/* Write the index of the key used in transmission */ |
1552 |
|
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, |
1553 |
|
priv->tx_key); |
1554 |
|
if (err) |
1555 |
|
return err; |
1556 |
|
|
1557 |
|
if (priv->wep_restrict) { |
1558 |
|
auth_flag = 2; |
1559 |
|
master_wep_flag = 3; |
1560 |
|
} else { |
1561 |
|
/* Authentication is where Intersil and Symbol |
1562 |
|
* firmware differ... */ |
1563 |
|
auth_flag = 1; |
1564 |
|
if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) |
1565 |
|
master_wep_flag = 3; /* Symbol */ |
1566 |
|
else |
1567 |
|
master_wep_flag = 1; /* Intersil */ |
1568 |
|
} |
1569 |
|
|
1570 |
|
|
1571 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1572 |
|
HERMES_RID_CNFAUTHENTICATION, auth_flag); |
1573 |
|
if (err) |
1574 |
|
return err; |
1575 |
|
} |
1576 |
|
|
1577 |
|
/* Master WEP setting : on/off */ |
1578 |
|
err = hermes_write_wordrec(hw, USER_BAP, |
1579 |
|
HERMES_RID_CNFWEPFLAGS_INTERSIL, |
1580 |
|
master_wep_flag); |
1581 |
|
if (err) |
1582 |
|
return err; |
1583 |
|
|
1584 |
|
break; |
1585 |
|
|
1586 |
|
default: |
1587 |
|
if (priv->wep_on) { |
1588 |
|
printk(KERN_ERR "%s: WEP enabled, although not supported!\n", |
1589 |
|
priv->ndev->name); |
1590 |
|
return -EINVAL; |
1591 |
|
} |
1592 |
|
} |
1593 |
|
|
1594 |
|
return 0; |
1595 |
} |
} |
1596 |
|
|
1597 |
static int __orinoco_program_rids(struct net_device *dev) |
static int __orinoco_program_rids(struct net_device *dev) |
1802 |
return 0; |
return 0; |
1803 |
} |
} |
1804 |
|
|
1805 |
/* xyzzy */ |
/* FIXME: return int? */ |
1806 |
static int orinoco_reconfigure(struct net_device *dev) |
static void |
1807 |
|
__orinoco_set_multicast_list(struct net_device *dev) |
1808 |
{ |
{ |
1809 |
struct orinoco_private *priv = dev->priv; |
struct orinoco_private *priv = dev->priv; |
1810 |
struct hermes *hw = &priv->hw; |
hermes_t *hw = &priv->hw; |
|
unsigned long flags; |
|
1811 |
int err = 0; |
int err = 0; |
1812 |
|
int promisc, mc_count; |
1813 |
|
|
1814 |
if (priv->broken_disableport) { |
/* The Hermes doesn't seem to have an allmulti mode, so we go |
1815 |
schedule_work(&priv->reset_work); |
* into promiscuous mode and let the upper levels deal. */ |
1816 |
return 0; |
if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || |
1817 |
|
(dev->mc_count > MAX_MULTICAST(priv)) ) { |
1818 |
|
promisc = 1; |
1819 |
|
mc_count = 0; |
1820 |
|
} else { |
1821 |
|
promisc = 0; |
1822 |
|
mc_count = dev->mc_count; |
1823 |
} |
} |
1824 |
|
|
1825 |
err = orinoco_lock(priv, &flags); |
if (promisc != priv->promiscuous) { |
1826 |
if (err) |
err = hermes_write_wordrec(hw, USER_BAP, |
1827 |
return err; |
HERMES_RID_CNFPROMISCUOUSMODE, |
1828 |
|
promisc); |
1829 |
|
if (err) { |
1830 |
err = hermes_disable_port(hw, 0); |
printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", |
1831 |
if (err) { |
dev->name, err); |
1832 |
printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", |
} else |
1833 |
dev->name); |
priv->promiscuous = promisc; |
|
priv->broken_disableport = 1; |
|
|
goto out; |
|
1834 |
} |
} |
1835 |
|
|
1836 |
err = __orinoco_program_rids(dev); |
if (! promisc && (mc_count || priv->mc_count) ) { |
1837 |
if (err) { |
struct dev_mc_list *p = dev->mc_list; |
1838 |
printk(KERN_WARNING "%s: Unable to reconfigure card\n", |
hermes_multicast_t mclist; |
1839 |
dev->name); |
int i; |
|
goto out; |
|
|
} |
|
1840 |
|
|
1841 |
err = hermes_enable_port(hw, 0); |
for (i = 0; i < mc_count; i++) { |
1842 |
if (err) { |
/* paranoia: is list shorter than mc_count? */ |
1843 |
printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", |
BUG_ON(! p); |
1844 |
dev->name); |
/* paranoia: bad address size in list? */ |
1845 |
goto out; |
BUG_ON(p->dmi_addrlen != ETH_ALEN); |
1846 |
} |
|
1847 |
|
memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); |
1848 |
|
p = p->next; |
1849 |
|
} |
1850 |
|
|
1851 |
|
if (p) |
1852 |
|
printk(KERN_WARNING "Multicast list is longer than mc_count\n"); |
1853 |
|
|
1854 |
out: |
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, |
1855 |
if (err) { |
HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), |
1856 |
printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); |
&mclist); |
1857 |
schedule_work(&priv->reset_work); |
if (err) |
1858 |
err = 0; |
printk(KERN_ERR "%s: Error %d setting multicast list.\n", |
1859 |
|
dev->name, err); |
1860 |
|
else |
1861 |
|
priv->mc_count = mc_count; |
1862 |
} |
} |
1863 |
|
|
1864 |
orinoco_unlock(priv, &flags); |
/* Since we can set the promiscuous flag when it wasn't asked |
1865 |
return err; |
for, make sure the net_device knows about it. */ |
1866 |
|
if (priv->promiscuous) |
1867 |
|
dev->flags |= IFF_PROMISC; |
1868 |
|
else |
1869 |
|
dev->flags &= ~IFF_PROMISC; |
1870 |
} |
} |
1871 |
|
|
1872 |
/* This must be called from user context, without locks held - use |
/* This must be called from user context, without locks held - use |
1934 |
} |
} |
1935 |
|
|
1936 |
/********************************************************************/ |
/********************************************************************/ |
1937 |
/* Internal helper functions */ |
/* Interrupt handler */ |
|
/********************************************************************/ |
|
|
|
|
|
static inline void |
|
|
set_port_type(struct orinoco_private *priv) |
|
|
{ |
|
|
switch (priv->iw_mode) { |
|
|
case IW_MODE_INFRA: |
|
|
priv->port_type = 1; |
|
|
priv->createibss = 0; |
|
|
break; |
|
|
case IW_MODE_ADHOC: |
|
|
if (priv->prefer_port3) { |
|
|
priv->port_type = 3; |
|
|
priv->createibss = 0; |
|
|
} else { |
|
|
priv->port_type = priv->ibss_port; |
|
|
priv->createibss = 1; |
|
|
} |
|
|
break; |
|
|
default: |
|
|
printk(KERN_ERR "%s: Invalid priv->iw_mode in set_port_type()\n", |
|
|
priv->ndev->name); |
|
|
} |
|
|
} |
|
|
|
|
|
/* Does the frame have a SNAP header indicating it should be |
|
|
* de-encapsulated to Ethernet-II? */ |
|
|
static inline int |
|
|
is_ethersnap(struct header_struct *hdr) |
|
|
{ |
|
|
/* We de-encapsulate all packets which, a) have SNAP headers |
|
|
* (i.e. SSAP=DSAP=0xaa and CTRL=0x3 in the 802.2 LLC header |
|
|
* and where b) the OUI of the SNAP header is 00:00:00 or |
|
|
* 00:00:f8 - we need both because different APs appear to use |
|
|
* different OUIs for some reason */ |
|
|
return (memcmp(&hdr->dsap, &encaps_hdr, 5) == 0) |
|
|
&& ( (hdr->oui[2] == 0x00) || (hdr->oui[2] == 0xf8) ); |
|
|
} |
|
|
|
|
|
static void |
|
|
orinoco_set_multicast_list(struct net_device *dev) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
unsigned long flags; |
|
|
|
|
|
if (orinoco_lock(priv, &flags) != 0) { |
|
|
printk(KERN_DEBUG "%s: orinoco_set_multicast_list() " |
|
|
"called when hw_unavailable\n", dev->name); |
|
|
return; |
|
|
} |
|
|
|
|
|
__orinoco_set_multicast_list(dev); |
|
|
orinoco_unlock(priv, &flags); |
|
|
} |
|
|
|
|
|
/********************************************************************/ |
|
|
/* Hardware control functions */ |
|
1938 |
/********************************************************************/ |
/********************************************************************/ |
1939 |
|
|
1940 |
|
static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) |
|
static int __orinoco_hw_set_bitrate(struct orinoco_private *priv) |
|
|
{ |
|
|
hermes_t *hw = &priv->hw; |
|
|
int err = 0; |
|
|
|
|
|
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(); |
|
|
} |
|
|
|
|
|
return err; |
|
|
} |
|
|
|
|
|
/* Just switch the WEP key, without changing other WEP/authentication |
|
|
* parameters. Used on firmware that can handle it to switch the key |
|
|
* without breaking the association, which is necessary for 802.1x */ |
|
|
static int __orinoco_fastkeychange(struct orinoco_private *priv) |
|
|
{ |
|
|
hermes_t *hw = &priv->hw; |
|
|
int err = 0; |
|
|
|
|
|
if (! priv->wep_on) { |
|
|
printk(KERN_DEBUG "%s: __orinoco_fastkeychange while WEP disabled!?\n", |
|
|
priv->ndev->name); |
|
|
return 0; |
|
|
} |
|
|
|
|
|
if (! priv->has_fastkeychange) |
|
|
return -EAGAIN; |
|
|
|
|
|
switch (priv->firmware_type) { |
|
|
case FIRMWARE_TYPE_AGERE: |
|
|
err = HERMES_WRITE_RECORD(hw, USER_BAP, |
|
|
HERMES_RID_CNFWEPKEYS_AGERE, |
|
|
&priv->keys); |
|
|
if (err) |
|
|
return err; |
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFTXKEY_AGERE, |
|
|
priv->tx_key); |
|
|
if (err) |
|
|
return err; |
|
|
break; |
|
|
case FIRMWARE_TYPE_INTERSIL: |
|
|
case FIRMWARE_TYPE_SYMBOL: |
|
|
/* FIXME: do any non-Agere firmwares support fast key |
|
|
* change? */ |
|
|
return -EAGAIN; |
|
|
break; |
|
|
} |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
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; |
|
|
|
|
|
switch (priv->firmware_type) { |
|
|
case FIRMWARE_TYPE_AGERE: /* Agere style WEP */ |
|
|
if (priv->wep_on) { |
|
|
/* Enable the shared-key authentication. */ |
|
|
/* FIXME: We never clear the authentication flag... */ |
|
|
if (priv->wep_restrict) |
|
|
auth_flag = 0x2; |
|
|
else |
|
|
auth_flag = 0x0; |
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFAUTHENTICATION_AGERE, |
|
|
auth_flag); |
|
|
if (err) |
|
|
return err; |
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFTXKEY_AGERE, |
|
|
priv->tx_key); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
err = HERMES_WRITE_RECORD(hw, USER_BAP, |
|
|
HERMES_RID_CNFWEPKEYS_AGERE, |
|
|
&priv->keys); |
|
|
if (err) |
|
|
return err; |
|
|
} |
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFWEPENABLED_AGERE, |
|
|
priv->wep_on); |
|
|
if (err) |
|
|
return err; |
|
|
break; |
|
|
|
|
|
case FIRMWARE_TYPE_INTERSIL: /* Intersil style WEP */ |
|
|
case FIRMWARE_TYPE_SYMBOL: /* Symbol style WEP */ |
|
|
master_wep_flag = 0; /* Off */ |
|
|
if (priv->wep_on) { |
|
|
int keylen; |
|
|
int i; |
|
|
|
|
|
/* Fudge around firmware weirdness */ |
|
|
keylen = le16_to_cpu(priv->keys[priv->tx_key].len); |
|
|
|
|
|
/* Write all 4 keys */ |
|
|
for(i = 0; i < ORINOCO_MAX_KEYS; i++) { |
|
|
/* int keylen = le16_to_cpu(priv->keys[i].len); */ |
|
|
|
|
|
if (keylen > LARGE_KEY_SIZE) { |
|
|
printk(KERN_ERR "%s: BUG: Key %d has oversize length %d.\n", |
|
|
priv->ndev->name, i, keylen); |
|
|
return -E2BIG; |
|
|
} |
|
|
|
|
|
err = hermes_write_ltv(hw, USER_BAP, |
|
|
HERMES_RID_CNFDEFAULTKEY0 + i, |
|
|
HERMES_BYTES_TO_RECLEN(keylen), |
|
|
priv->keys[i].data); |
|
|
if (err) |
|
|
return err; |
|
|
} |
|
|
|
|
|
/* Write the index of the key used in transmission */ |
|
|
err = hermes_write_wordrec(hw, USER_BAP, HERMES_RID_CNFWEPDEFAULTKEYID, |
|
|
priv->tx_key); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
if (priv->wep_restrict) { |
|
|
auth_flag = 2; |
|
|
master_wep_flag = 3; |
|
|
} else { |
|
|
/* Authentication is where Intersil and Symbol |
|
|
* firmware differ... */ |
|
|
auth_flag = 1; |
|
|
if (priv->firmware_type == FIRMWARE_TYPE_SYMBOL) |
|
|
master_wep_flag = 3; /* Symbol */ |
|
|
else |
|
|
master_wep_flag = 1; /* Intersil */ |
|
|
} |
|
|
|
|
|
|
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFAUTHENTICATION, auth_flag); |
|
|
if (err) |
|
|
return err; |
|
|
} |
|
|
|
|
|
/* Master WEP setting : on/off */ |
|
|
err = hermes_write_wordrec(hw, USER_BAP, |
|
|
HERMES_RID_CNFWEPFLAGS_INTERSIL, |
|
|
master_wep_flag); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
break; |
|
|
|
|
|
default: |
|
|
if (priv->wep_on) { |
|
|
printk(KERN_ERR "%s: WEP enabled, although not supported!\n", |
|
|
priv->ndev->name); |
|
|
return -EINVAL; |
|
|
} |
|
|
} |
|
|
|
|
|
return 0; |
|
|
} |
|
|
|
|
|
static int orinoco_hw_get_bssid(struct orinoco_private *priv, |
|
|
char buf[ETH_ALEN]) |
|
|
{ |
|
|
hermes_t *hw = &priv->hw; |
|
|
int err = 0; |
|
|
unsigned long flags; |
|
|
|
|
|
err = orinoco_lock(priv, &flags); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, |
|
|
ETH_ALEN, NULL, buf); |
|
|
|
|
|
orinoco_unlock(priv, &flags); |
|
|
|
|
|
return err; |
|
|
} |
|
|
|
|
|
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, |
|
|
char buf[IW_ESSID_MAX_SIZE+1]) |
|
|
{ |
|
|
hermes_t *hw = &priv->hw; |
|
|
int err = 0; |
|
|
struct hermes_idstring essidbuf; |
|
|
char *p = (char *)(&essidbuf.val); |
|
|
int len; |
|
|
unsigned long flags; |
|
|
|
|
|
err = orinoco_lock(priv, &flags); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
if (strlen(priv->desired_essid) > 0) { |
|
|
/* We read the desired SSID from the hardware rather |
|
|
than from priv->desired_essid, just in case the |
|
|
firmware is allowed to change it on us. I'm not |
|
|
sure about this */ |
|
|
/* My guess is that the OWNSSID should always be whatever |
|
|
* we set to the card, whereas CURRENT_SSID is the one that |
|
|
* may change... - Jean II */ |
|
|
u16 rid; |
|
|
|
|
|
*active = 1; |
|
|
|
|
|
rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : |
|
|
HERMES_RID_CNFDESIREDSSID; |
|
|
|
|
|
err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), |
|
|
NULL, &essidbuf); |
|
|
if (err) |
|
|
goto fail_unlock; |
|
|
} else { |
|
|
*active = 0; |
|
|
|
|
|
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, |
|
|
sizeof(essidbuf), NULL, &essidbuf); |
|
|
if (err) |
|
|
goto fail_unlock; |
|
|
} |
|
|
|
|
|
len = le16_to_cpu(essidbuf.len); |
|
|
BUG_ON(len > IW_ESSID_MAX_SIZE); |
|
|
|
|
|
memset(buf, 0, IW_ESSID_MAX_SIZE+1); |
|
|
memcpy(buf, p, len); |
|
|
buf[len] = '\0'; |
|
|
|
|
|
fail_unlock: |
|
|
orinoco_unlock(priv, &flags); |
|
|
|
|
|
return err; |
|
|
} |
|
|
|
|
|
static long orinoco_hw_get_freq(struct orinoco_private *priv) |
|
|
{ |
|
|
|
|
|
hermes_t *hw = &priv->hw; |
|
|
int err = 0; |
|
|
u16 channel; |
|
|
long freq = 0; |
|
|
unsigned long flags; |
|
|
|
|
|
err = orinoco_lock(priv, &flags); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); |
|
|
if (err) |
|
|
goto out; |
|
|
|
|
|
/* Intersil firmware 1.3.5 returns 0 when the interface is down */ |
|
|
if (channel == 0) { |
|
|
err = -EBUSY; |
|
|
goto out; |
|
|
} |
|
|
|
|
|
if ( (channel < 1) || (channel > NUM_CHANNELS) ) { |
|
|
printk(KERN_WARNING "%s: Channel out of range (%d)!\n", |
|
|
priv->ndev->name, channel); |
|
|
err = -EBUSY; |
|
|
goto out; |
|
|
|
|
|
} |
|
|
freq = channel_frequency[channel-1] * 100000; |
|
|
|
|
|
out: |
|
|
orinoco_unlock(priv, &flags); |
|
|
|
|
|
if (err > 0) |
|
|
err = -EBUSY; |
|
|
return err ? err : freq; |
|
|
} |
|
|
|
|
|
static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, |
|
|
int *numrates, s32 *rates, int max) |
|
1941 |
{ |
{ |
1942 |
hermes_t *hw = &priv->hw; |
printk(KERN_DEBUG "%s: TICK\n", dev->name); |
|
struct hermes_idstring list; |
|
|
unsigned char *p = (unsigned char *)&list.val; |
|
|
int err = 0; |
|
|
int num; |
|
|
int i; |
|
|
unsigned long flags; |
|
|
|
|
|
err = orinoco_lock(priv, &flags); |
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, |
|
|
sizeof(list), NULL, &list); |
|
|
orinoco_unlock(priv, &flags); |
|
|
|
|
|
if (err) |
|
|
return err; |
|
|
|
|
|
num = le16_to_cpu(list.len); |
|
|
*numrates = num; |
|
|
num = min(num, max); |
|
|
|
|
|
for (i = 0; i < num; i++) { |
|
|
rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ |
|
|
} |
|
|
|
|
|
return 0; |
|
1943 |
} |
} |
1944 |
|
|
1945 |
#if 0 |
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) |
|
static void show_rx_frame(struct orinoco_rxframe_hdr *frame) |
|
1946 |
{ |
{ |
1947 |
printk(KERN_DEBUG "RX descriptor:\n"); |
/* This seems to happen a fair bit under load, but ignoring it |
1948 |
printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); |
seems to work fine...*/ |
1949 |
printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); |
printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", |
1950 |
printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); |
dev->name); |
|
printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); |
|
|
printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); |
|
|
printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); |
|
|
printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); |
|
|
|
|
|
printk(KERN_DEBUG "IEEE 802.11 header:\n"); |
|
|
printk(KERN_DEBUG " frame_ctl = 0x%04x\n", |
|
|
frame->p80211.frame_ctl); |
|
|
printk(KERN_DEBUG " duration_id = 0x%04x\n", |
|
|
frame->p80211.duration_id); |
|
|
printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p80211.addr1[0], frame->p80211.addr1[1], |
|
|
frame->p80211.addr1[2], frame->p80211.addr1[3], |
|
|
frame->p80211.addr1[4], frame->p80211.addr1[5]); |
|
|
printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p80211.addr2[0], frame->p80211.addr2[1], |
|
|
frame->p80211.addr2[2], frame->p80211.addr2[3], |
|
|
frame->p80211.addr2[4], frame->p80211.addr2[5]); |
|
|
printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p80211.addr3[0], frame->p80211.addr3[1], |
|
|
frame->p80211.addr3[2], frame->p80211.addr3[3], |
|
|
frame->p80211.addr3[4], frame->p80211.addr3[5]); |
|
|
printk(KERN_DEBUG " seq_ctl = 0x%04x\n", |
|
|
frame->p80211.seq_ctl); |
|
|
printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p80211.addr4[0], frame->p80211.addr4[1], |
|
|
frame->p80211.addr4[2], frame->p80211.addr4[3], |
|
|
frame->p80211.addr4[4], frame->p80211.addr4[5]); |
|
|
printk(KERN_DEBUG " data_len = 0x%04x\n", |
|
|
frame->p80211.data_len); |
|
|
|
|
|
printk(KERN_DEBUG "IEEE 802.3 header:\n"); |
|
|
printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p8023.h_dest[0], frame->p8023.h_dest[1], |
|
|
frame->p8023.h_dest[2], frame->p8023.h_dest[3], |
|
|
frame->p8023.h_dest[4], frame->p8023.h_dest[5]); |
|
|
printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", |
|
|
frame->p8023.h_source[0], frame->p8023.h_source[1], |
|
|
frame->p8023.h_source[2], frame->p8023.h_source[3], |
|
|
frame->p8023.h_source[4], frame->p8023.h_source[5]); |
|
|
printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); |
|
|
|
|
|
printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); |
|
|
printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); |
|
|
printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); |
|
|
printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); |
|
|
printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", |
|
|
frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); |
|
|
printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); |
|
1951 |
} |
} |
|
#endif /* 0 */ |
|
1952 |
|
|
|
/* |
|
|
* Interrupt handler |
|
|
*/ |
|
1953 |
irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
irqreturn_t orinoco_interrupt(int irq, void *dev_id, struct pt_regs *regs) |
1954 |
{ |
{ |
1955 |
struct net_device *dev = (struct net_device *)dev_id; |
struct net_device *dev = (struct net_device *)dev_id; |
2025 |
return IRQ_HANDLED; |
return IRQ_HANDLED; |
2026 |
} |
} |
2027 |
|
|
2028 |
static void __orinoco_ev_tick(struct net_device *dev, hermes_t *hw) |
/********************************************************************/ |
2029 |
{ |
/* Initialization */ |
2030 |
printk(KERN_DEBUG "%s: TICK\n", dev->name); |
/********************************************************************/ |
|
} |
|
|
|
|
|
static void __orinoco_ev_wterr(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
/* This seems to happen a fair bit under load, but ignoring it |
|
|
seems to work fine...*/ |
|
|
printk(KERN_DEBUG "%s: MAC controller error (WTERR). Ignoring.\n", |
|
|
dev->name); |
|
|
} |
|
|
|
|
|
static void __orinoco_ev_infdrop(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
printk(KERN_DEBUG "%s: Information frame lost.\n", dev->name); |
|
|
} |
|
|
|
|
|
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); |
|
|
} |
|
|
|
|
|
void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
u16 infofid; |
|
|
struct { |
|
|
u16 len; |
|
|
u16 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); |
|
|
} |
|
|
|
|
|
/* Read directly the data (no seek) */ |
|
|
/* FIXME: blech! ??? */ |
|
|
hermes_bap_pread(hw, IRQ_BAP, &tallies, len, infofid, sizeof(info)); |
|
|
|
|
|
/* 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); |
|
|
#if WIRELESS_EXT > 11 |
|
|
wstats->discard.fragment += |
|
|
le16_to_cpu(tallies.RxMsgInBadMsgFragments); |
|
|
wstats->discard.retries += |
|
|
le16_to_cpu(tallies.TxRetryLimitExceeded); |
|
|
/* wstats->miss.beacon - no match */ |
|
|
#endif /* WIRELESS_EXT > 11 */ |
|
|
} |
|
|
break; |
|
|
case HERMES_INQ_LINKSTATUS: { |
|
|
struct hermes_linkstatus linkstatus; |
|
|
u16 newstatus; |
|
|
|
|
|
if (len != sizeof(linkstatus)) { |
|
|
printk(KERN_WARNING "%s: Unexpected size for linkstatus frame (%d bytes)\n", |
|
|
dev->name, len); |
|
|
break; |
|
|
} |
|
|
|
|
|
hermes_bap_pread(hw, IRQ_BAP, &linkstatus, len, infofid, sizeof(info)); |
|
|
|
|
|
newstatus = le16_to_cpu(linkstatus.linkstatus); |
|
|
|
|
|
if ( (newstatus == HERMES_LINKSTATUS_CONNECTED) |
|
|
|| (newstatus == HERMES_LINKSTATUS_AP_CHANGE) |
|
|
|| (newstatus == HERMES_LINKSTATUS_AP_IN_RANGE) ) |
|
|
netif_carrier_on(dev); |
|
|
else if ( (newstatus == HERMES_LINKSTATUS_NOT_CONNECTED) |
|
|
|| (newstatus == HERMES_LINKSTATUS_DISCONNECTED) |
|
|
|| (newstatus == HERMES_LINKSTATUS_AP_OUT_OF_RANGE) |
|
|
|| (newstatus == HERMES_LINKSTATUS_ASSOC_FAILED) ) |
|
|
netif_carrier_off(dev); |
|
|
|
|
|
if (newstatus != priv->last_linkstatus) |
|
|
print_linkstatus(dev, newstatus); |
|
|
|
|
|
priv->last_linkstatus = newstatus; |
|
|
} |
|
|
break; |
|
|
default: |
|
|
printk(KERN_DEBUG "%s: Unknown information frame received (type %04x).\n", |
|
|
dev->name, type); |
|
|
/* We don't actually do anything about it */ |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
void __orinoco_ev_rx(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
struct net_device_stats *stats = &priv->stats; |
|
|
struct iw_statistics *wstats = &priv->wstats; |
|
|
struct sk_buff *skb = NULL; |
|
|
u16 rxfid, status; |
|
|
int length, data_len, data_off; |
|
|
char *p; |
|
|
struct hermes_rx_descriptor desc; |
|
|
struct header_struct hdr; |
|
|
struct ethhdr *eh; |
|
|
int err; |
|
|
|
|
|
rxfid = hermes_read_regn(hw, RXFID); |
|
|
|
|
|
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), |
|
|
rxfid, 0); |
|
|
if (err) { |
|
|
printk(KERN_ERR "%s: error %d reading Rx descriptor. " |
|
|
"Frame dropped.\n", dev->name, err); |
|
|
stats->rx_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
status = le16_to_cpu(desc.status); |
|
|
|
|
|
if (status & HERMES_RXSTAT_ERR) { |
|
|
if (status & HERMES_RXSTAT_UNDECRYPTABLE) { |
|
|
wstats->discard.code++; |
|
|
DEBUG(1, "%s: Undecryptable frame on Rx. Frame dropped.\n", |
|
|
dev->name); |
|
|
} else { |
|
|
stats->rx_crc_errors++; |
|
|
DEBUG(1, "%s: Bad CRC on Rx. Frame dropped.\n", dev->name); |
|
|
} |
|
|
stats->rx_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
/* For now we ignore the 802.11 header completely, assuming |
|
|
that the card's firmware has handled anything vital */ |
|
|
|
|
|
err = hermes_bap_pread(hw, IRQ_BAP, &hdr, sizeof(hdr), |
|
|
rxfid, HERMES_802_3_OFFSET); |
|
|
if (err) { |
|
|
printk(KERN_ERR "%s: error %d reading frame header. " |
|
|
"Frame dropped.\n", dev->name, err); |
|
|
stats->rx_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
length = ntohs(hdr.len); |
|
|
|
|
|
/* Sanity checks */ |
|
|
if (length < 3) { /* No for even an 802.2 LLC header */ |
|
|
/* At least on Symbol firmware with PCF we get quite a |
|
|
lot of these legitimately - Poll frames with no |
|
|
data. */ |
|
|
stats->rx_dropped++; |
|
|
goto drop; |
|
|
} |
|
|
if (length > IEEE802_11_DATA_LEN) { |
|
|
printk(KERN_WARNING "%s: Oversized frame received (%d bytes)\n", |
|
|
dev->name, length); |
|
|
stats->rx_length_errors++; |
|
|
stats->rx_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
/* We need space for the packet data itself, plus an ethernet |
|
|
header, plus 2 bytes so we can align the IP header on a |
|
|
32bit boundary, plus 1 byte so we can read in odd length |
|
|
packets from the card, which has an IO granularity of 16 |
|
|
bits */ |
|
|
skb = dev_alloc_skb(length+ETH_HLEN+2+1); |
|
|
if (!skb) { |
|
|
printk(KERN_WARNING "%s: Can't allocate skb for Rx\n", |
|
|
dev->name); |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
skb_reserve(skb, 2); /* This way the IP header is aligned */ |
|
|
|
|
|
/* 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(((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_1042) || |
|
|
((status & HERMES_RXSTAT_MSGTYPE) == HERMES_RXSTAT_TUNNEL) || |
|
|
is_ethersnap(&hdr)) { |
|
|
/* These indicate a SNAP within 802.2 LLC within |
|
|
802.11 frame which we'll need to de-encapsulate to |
|
|
the original EthernetII frame. */ |
|
|
|
|
|
if (length < ENCAPS_OVERHEAD) { /* No room for full LLC+SNAP */ |
|
|
stats->rx_length_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
/* Remove SNAP header, reconstruct EthernetII frame */ |
|
|
data_len = length - ENCAPS_OVERHEAD; |
|
|
data_off = HERMES_802_3_OFFSET + sizeof(hdr); |
|
|
|
|
|
eh = (struct ethhdr *)skb_put(skb, ETH_HLEN); |
|
|
|
|
|
memcpy(eh, &hdr, 2 * ETH_ALEN); |
|
|
eh->h_proto = hdr.ethertype; |
|
|
} else { |
|
|
/* All other cases indicate a genuine 802.3 frame. No |
|
|
decapsulation needed. We just throw the whole |
|
|
thing in, and hope the protocol layer can deal with |
|
|
it as 802.3 */ |
|
|
data_len = length; |
|
|
data_off = HERMES_802_3_OFFSET; |
|
|
/* FIXME: we re-read from the card data we already read here */ |
|
|
} |
|
|
|
|
|
p = skb_put(skb, data_len); |
|
|
err = hermes_bap_pread(hw, IRQ_BAP, p, ALIGN(data_len, 2), |
|
|
rxfid, data_off); |
|
|
if (err) { |
|
|
printk(KERN_ERR "%s: error %d reading frame. " |
|
|
"Frame dropped.\n", dev->name, err); |
|
|
stats->rx_errors++; |
|
|
goto drop; |
|
|
} |
|
|
|
|
|
dev->last_rx = jiffies; |
|
|
skb->dev = dev; |
|
|
skb->protocol = eth_type_trans(skb, dev); |
|
|
skb->ip_summed = CHECKSUM_NONE; |
|
|
|
|
|
/* 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: |
|
|
stats->rx_dropped++; |
|
|
|
|
|
if (skb) |
|
|
dev_kfree_skb_irq(skb); |
|
|
return; |
|
|
} |
|
|
|
|
|
static void __orinoco_ev_txexc(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
struct net_device_stats *stats = &priv->stats; |
|
|
u16 fid = hermes_read_regn(hw, TXCOMPLFID); |
|
|
struct hermes_tx_descriptor desc; |
|
|
int err = 0; |
|
|
|
|
|
if (fid == DUMMY_FID) |
|
|
return; /* Nothing's really happened */ |
|
|
|
|
|
err = hermes_bap_pread(hw, IRQ_BAP, &desc, sizeof(desc), fid, 0); |
|
|
if (err) { |
|
|
printk(KERN_WARNING "%s: Unable to read descriptor on Tx error " |
|
|
"(FID=%04X error %d)\n", |
|
|
dev->name, fid, err); |
|
|
} else { |
|
|
DEBUG(1, "%s: Tx error, status %d\n", |
|
|
dev->name, le16_to_cpu(desc.status)); |
|
|
} |
|
|
|
|
|
stats->tx_errors++; |
|
|
|
|
|
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); |
|
|
} |
|
|
|
|
|
static void __orinoco_ev_tx(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
struct net_device_stats *stats = &priv->stats; |
|
|
|
|
|
stats->tx_packets++; |
|
|
|
|
|
netif_wake_queue(dev); |
|
|
|
|
|
hermes_write_regn(hw, TXCOMPLFID, DUMMY_FID); |
|
|
} |
|
|
|
|
|
static void __orinoco_ev_alloc(struct net_device *dev, hermes_t *hw) |
|
|
{ |
|
|
struct orinoco_private *priv = dev->priv; |
|
|
u16 fid = hermes_read_regn(hw, ALLOCFID); |
|
|
|
|
|
if (fid != priv->txfid) { |
|
|
if (fid != DUMMY_FID) |
|
|
printk(KERN_WARNING "%s: Allocate event on unexpected fid (%04X)\n", |
|
|
dev->name, fid); |
|
|
return; |
|
|
} |
|
|
|
|
|
hermes_write_regn(hw, ALLOCFID, DUMMY_FID); |
|
|
} |
|
2031 |
|
|
2032 |
struct sta_id { |
struct sta_id { |
2033 |
u16 id, variant, major, minor; |
u16 id, variant, major, minor; |
2182 |
} |
} |
2183 |
} |
} |
2184 |
|
|
2185 |
/* |
static int orinoco_init(struct net_device *dev) |
|
* struct net_device methods |
|
|
*/ |
|
|
|
|
|
static int |
|
|
orinoco_init(struct net_device *dev) |
|
2186 |
{ |
{ |
2187 |
struct orinoco_private *priv = dev->priv; |
struct orinoco_private *priv = dev->priv; |
2188 |
hermes_t *hw = &priv->hw; |
hermes_t *hw = &priv->hw; |
2364 |
return err; |
return err; |
2365 |
} |
} |
2366 |
|
|
2367 |
struct net_device_stats * |
struct net_device *alloc_orinocodev(int sizeof_card, |
2368 |
orinoco_get_stats(struct net_device *dev) |
int (*hard_reset)(struct orinoco_private *)) |
2369 |
{ |
{ |
2370 |
struct orinoco_private *priv = dev->priv; |
struct net_device *dev; |
2371 |
|
struct orinoco_private *priv; |
2372 |
return &priv->stats; |
|
2373 |
|
dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); |
2374 |
|
priv = (struct orinoco_private *)dev->priv; |
2375 |
|
priv->ndev = dev; |
2376 |
|
if (sizeof_card) |
2377 |
|
priv->card = (void *)((unsigned long)dev->priv |
2378 |
|
+ sizeof(struct orinoco_private)); |
2379 |
|
else |
2380 |
|
priv->card = NULL; |
2381 |
|
|
2382 |
|
/* Setup / override net_device fields */ |
2383 |
|
dev->init = orinoco_init; |
2384 |
|
dev->hard_start_xmit = orinoco_xmit; |
2385 |
|
dev->tx_timeout = orinoco_tx_timeout; |
2386 |
|
dev->watchdog_timeo = HZ; /* 1 second timeout */ |
2387 |
|
dev->get_stats = orinoco_get_stats; |
2388 |
|
dev->get_wireless_stats = orinoco_get_wireless_stats; |
2389 |
|
dev->do_ioctl = orinoco_ioctl; |
2390 |
|
dev->change_mtu = orinoco_change_mtu; |
2391 |
|
dev->set_multicast_list = orinoco_set_multicast_list; |
2392 |
|
/* we use the default eth_mac_addr for setting the MAC addr */ |
2393 |
|
|
2394 |
|
/* Set up default callbacks */ |
2395 |
|
dev->open = orinoco_open; |
2396 |
|
dev->stop = orinoco_stop; |
2397 |
|
priv->hard_reset = hard_reset; |
2398 |
|
|
2399 |
|
spin_lock_init(&priv->lock); |
2400 |
|
priv->open = 0; |
2401 |
|
priv->hw_unavailable = 1; /* orinoco_init() must clear this |
2402 |
|
* before anything else touches the |
2403 |
|
* hardware */ |
2404 |
|
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); |
2405 |
|
|
2406 |
|
netif_carrier_off(dev); |
2407 |
|
priv->last_linkstatus = 0xffff; |
2408 |
|
|
2409 |
|
return dev; |
2410 |
|
|
2411 |
} |
} |
2412 |
|
|
2413 |
struct iw_statistics * |
/********************************************************************/ |
2414 |
orinoco_get_wireless_stats(struct net_device *dev) |
/* Wireless extensions */ |
2415 |
|
/********************************************************************/ |
2416 |
|
|
2417 |
|
static int orinoco_reconfigure(struct net_device *dev) |
2418 |
{ |
{ |
2419 |
struct orinoco_private *priv = dev->priv; |
struct orinoco_private *priv = dev->priv; |
2420 |
hermes_t *hw = &priv->hw; |
struct hermes *hw = &priv->hw; |
|
struct iw_statistics *wstats = &priv->wstats; |
|
|
int err = 0; |
|
2421 |
unsigned long flags; |
unsigned long flags; |
2422 |
|
int err = 0; |
2423 |
|
|
2424 |
if (! netif_device_present(dev)) { |
if (priv->broken_disableport) { |
2425 |
printk(KERN_WARNING "%s: get_wireless_stats() called while device not present\n", |
schedule_work(&priv->reset_work); |
2426 |
dev->name); |
return 0; |
|
return NULL; /* FIXME: Can we do better than this? */ |
|
2427 |
} |
} |
2428 |
|
|
2429 |
err = orinoco_lock(priv, &flags); |
err = orinoco_lock(priv, &flags); |
2430 |
if (err) |
if (err) |
2431 |
return NULL; /* FIXME: Erg, we've been signalled, how |
return err; |
|
* do we propagate this back up? */ |
|
|
|
|
|
if (priv->iw_mode == IW_MODE_ADHOC) { |
|
|
memset(&wstats->qual, 0, sizeof(wstats->qual)); |
|
|
/* If a spy address is defined, we report stats of the |
|
|
* first spy address - Jean II */ |
|
|
if (SPY_NUMBER(priv)) { |
|
|
wstats->qual.qual = priv->spy_stat[0].qual; |
|
|
wstats->qual.level = priv->spy_stat[0].level; |
|
|
wstats->qual.noise = priv->spy_stat[0].noise; |
|
|
wstats->qual.updated = priv->spy_stat[0].updated; |
|
|
} |
|
|
} else { |
|
|
struct { |
|
|
u16 qual, signal, noise; |
|
|
} __attribute__ ((packed)) cq; |
|
2432 |
|
|
|
err = HERMES_READ_RECORD(hw, USER_BAP, |
|
|
HERMES_RID_COMMSQUALITY, &cq); |
|
2433 |
|
|
2434 |
wstats->qual.qual = (int)le16_to_cpu(cq.qual); |
err = hermes_disable_port(hw, 0); |
2435 |
wstats->qual.level = (int)le16_to_cpu(cq.signal) - 0x95; |
if (err) { |
2436 |
wstats->qual.noise = (int)le16_to_cpu(cq.noise) - 0x95; |
printk(KERN_WARNING "%s: Unable to disable port while reconfiguring card\n", |
2437 |
wstats->qual.updated = 7; |
dev->name); |
2438 |
|
priv->broken_disableport = 1; |
2439 |
|
goto out; |
2440 |
} |
} |
2441 |
|
|
2442 |
/* We can't really wait for the tallies inquiry command to |
err = __orinoco_program_rids(dev); |
2443 |
* complete, so we just use the previous results and trigger |
if (err) { |
2444 |
* a new tallies inquiry command for next time - Jean II */ |
printk(KERN_WARNING "%s: Unable to reconfigure card\n", |
2445 |
/* FIXME: We're in user context (I think?), so we should just |
dev->name); |
2446 |
wait for the tallies to come through */ |
goto out; |
2447 |
err = hermes_inquire(hw, HERMES_INQ_TALLIES); |
} |
|
|
|
|
orinoco_unlock(priv, &flags); |
|
|
|
|
|
if (err) |
|
|
return NULL; |
|
|
|
|
|
return wstats; |
|
|
} |
|
2448 |
|
|
2449 |
static inline void orinoco_spy_gather(struct net_device *dev, u_char *mac, |
err = hermes_enable_port(hw, 0); |
2450 |
int level, int noise) |
if (err) { |
2451 |
{ |
printk(KERN_WARNING "%s: Unable to enable port while reconfiguring card\n", |
2452 |
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
dev->name); |
2453 |
int i; |
goto out; |
2454 |
|
} |
2455 |
|
|
2456 |
/* Gather wireless spy statistics: for each packet, compare the |
out: |
2457 |
* source address with out list, and if match, get the stats... */ |
if (err) { |
2458 |
for (i = 0; i < priv->spy_number; i++) |
printk(KERN_WARNING "%s: Resetting instead...\n", dev->name); |
2459 |
if (!memcmp(mac, priv->spy_address[i], ETH_ALEN)) { |
schedule_work(&priv->reset_work); |
2460 |
priv->spy_stat[i].level = level - 0x95; |
err = 0; |
2461 |
priv->spy_stat[i].noise = noise - 0x95; |
} |
|
priv->spy_stat[i].qual = (level > noise) ? (level - noise) : 0; |
|
|
priv->spy_stat[i].updated = 7; |
|
|
} |
|
|
} |
|
2462 |
|
|
2463 |
void |
orinoco_unlock(priv, &flags); |
2464 |
orinoco_stat_gather(struct net_device *dev, |
return err; |
|
struct sk_buff *skb, |
|
|
struct hermes_rx_descriptor *desc) |
|
|
{ |
|
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
|
2465 |
|
|
|
/* Using spy support with lots of Rx packets, like in an |
|
|
* infrastructure (AP), will really slow down everything, because |
|
|
* the MAC address must be compared to each entry of the spy list. |
|
|
* If the user really asks for it (set some address in the |
|
|
* spy list), we do it, but he will pay the price. |
|
|
* Note that to get here, you need both WIRELESS_SPY |
|
|
* compiled in AND some addresses in the list !!! |
|
|
*/ |
|
|
/* Note : gcc will optimise the whole section away if |
|
|
* WIRELESS_SPY is not defined... - Jean II */ |
|
|
if (SPY_NUMBER(priv)) { |
|
|
orinoco_spy_gather(dev, skb->mac.raw + ETH_ALEN, |
|
|
desc->signal, desc->silence); |
|
|
} |
|
2466 |
} |
} |
2467 |
|
|
2468 |
static int |
static int orinoco_hw_get_bssid(struct orinoco_private *priv, |
2469 |
orinoco_xmit(struct sk_buff *skb, struct net_device *dev) |
char buf[ETH_ALEN]) |
2470 |
{ |
{ |
|
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
|
|
struct net_device_stats *stats = &priv->stats; |
|
2471 |
hermes_t *hw = &priv->hw; |
hermes_t *hw = &priv->hw; |
2472 |
int err = 0; |
int err = 0; |
|
u16 txfid = priv->txfid; |
|
|
char *p; |
|
|
struct ethhdr *eh; |
|
|
int len, data_len, data_off; |
|
|
struct hermes_tx_descriptor desc; |
|
2473 |
unsigned long flags; |
unsigned long flags; |
2474 |
|
|
2475 |
TRACE_ENTER(dev->name); |
err = orinoco_lock(priv, &flags); |
2476 |
|
if (err) |
2477 |
|
return err; |
2478 |
|
|
2479 |
if (! netif_running(dev)) { |
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTBSSID, |
2480 |
printk(KERN_ERR "%s: Tx on stopped device!\n", |
ETH_ALEN, NULL, buf); |
|
dev->name); |
|
|
TRACE_EXIT(dev->name); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (netif_queue_stopped(dev)) { |
|
|
printk(KERN_DEBUG "%s: Tx while transmitter busy!\n", |
|
|
dev->name); |
|
|
TRACE_EXIT(dev->name); |
|
|
return 1; |
|
|
} |
|
|
|
|
|
if (orinoco_lock(priv, &flags) != 0) { |
|
|
printk(KERN_ERR "%s: orinoco_xmit() called while hw_unavailable\n", |
|
|
dev->name); |
|
|
TRACE_EXIT(dev->name); |
|
|
/* BUG(); */ |
|
|
return 1; |
|
|
} |
|
2481 |
|
|
2482 |
if (! netif_carrier_ok(dev)) { |
orinoco_unlock(priv, &flags); |
|
/* Oops, the firmware hasn't established a connection, |
|
|
silently drop the packet (this seems to be the |
|
|
safest approach). */ |
|
|
stats->tx_errors++; |
|
|
orinoco_unlock(priv, &flags); |
|
|
dev_kfree_skb(skb); |
|
|
TRACE_EXIT(dev->name); |
|
|
return 0; |
|
|
} |
|
2483 |
|
|
2484 |
/* Length of the packet body */ |
return err; |
2485 |
/* FIXME: what if the skb is smaller than this? */ |
} |
|
len = max_t(int,skb->len - ETH_HLEN, ETH_ZLEN - ETH_HLEN); |
|
2486 |
|
|
2487 |
eh = (struct ethhdr *)skb->data; |
static int orinoco_hw_get_essid(struct orinoco_private *priv, int *active, |
2488 |
|
char buf[IW_ESSID_MAX_SIZE+1]) |
2489 |
|
{ |
2490 |
|
hermes_t *hw = &priv->hw; |
2491 |
|
int err = 0; |
2492 |
|
struct hermes_idstring essidbuf; |
2493 |
|
char *p = (char *)(&essidbuf.val); |
2494 |
|
int len; |
2495 |
|
unsigned long flags; |
2496 |
|
|
2497 |
memset(&desc, 0, sizeof(desc)); |
err = orinoco_lock(priv, &flags); |
2498 |
desc.tx_control = cpu_to_le16(HERMES_TXCTRL_TX_OK | HERMES_TXCTRL_TX_EX); |
if (err) |
2499 |
err = hermes_bap_pwrite(hw, USER_BAP, &desc, sizeof(desc), txfid, 0); |
return err; |
|
if (err) { |
|
|
printk(KERN_ERR "%s: Error %d writing Tx descriptor to BAP\n", |
|
|
dev->name, err); |
|
|
stats->tx_errors++; |
|
|
goto fail; |
|
|
} |
|
2500 |
|
|
2501 |
/* Clear the 802.11 header and data length fields - some |
if (strlen(priv->desired_essid) > 0) { |
2502 |
* firmwares (e.g. Lucent/Agere 8.xx) appear to get confused |
/* We read the desired SSID from the hardware rather |
2503 |
* if this isn't done. */ |
than from priv->desired_essid, just in case the |
2504 |
hermes_clear_words(hw, HERMES_DATA0, |
firmware is allowed to change it on us. I'm not |
2505 |
HERMES_802_3_OFFSET - HERMES_802_11_OFFSET); |
sure about this */ |
2506 |
|
/* My guess is that the OWNSSID should always be whatever |
2507 |
|
* we set to the card, whereas CURRENT_SSID is the one that |
2508 |
|
* may change... - Jean II */ |
2509 |
|
u16 rid; |
2510 |
|
|
2511 |
/* Encapsulate Ethernet-II frames */ |
*active = 1; |
|
if (ntohs(eh->h_proto) > 1500) { /* Ethernet-II frame */ |
|
|
struct header_struct hdr; |
|
|
data_len = len; |
|
|
data_off = HERMES_802_3_OFFSET + sizeof(hdr); |
|
|
p = skb->data + ETH_HLEN; |
|
2512 |
|
|
2513 |
/* 802.3 header */ |
rid = (priv->port_type == 3) ? HERMES_RID_CNFOWNSSID : |
2514 |
memcpy(hdr.dest, eh->h_dest, ETH_ALEN); |
HERMES_RID_CNFDESIREDSSID; |
|
memcpy(hdr.src, eh->h_source, ETH_ALEN); |
|
|
hdr.len = htons(data_len + ENCAPS_OVERHEAD); |
|
2515 |
|
|
2516 |
/* 802.2 header */ |
err = hermes_read_ltv(hw, USER_BAP, rid, sizeof(essidbuf), |
2517 |
memcpy(&hdr.dsap, &encaps_hdr, sizeof(encaps_hdr)); |
NULL, &essidbuf); |
2518 |
|
if (err) |
2519 |
hdr.ethertype = eh->h_proto; |
goto fail_unlock; |
2520 |
err = hermes_bap_pwrite(hw, USER_BAP, &hdr, sizeof(hdr), |
} else { |
2521 |
txfid, HERMES_802_3_OFFSET); |
*active = 0; |
|
if (err) { |
|
|
printk(KERN_ERR "%s: Error %d writing packet header to BAP\n", |
|
|
dev->name, err); |
|
|
stats->tx_errors++; |
|
|
goto fail; |
|
|
} |
|
|
} else { /* IEEE 802.3 frame */ |
|
|
data_len = len + ETH_HLEN; |
|
|
data_off = HERMES_802_3_OFFSET; |
|
|
p = skb->data; |
|
|
} |
|
2522 |
|
|
2523 |
/* Round up for odd length packets */ |
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_CURRENTSSID, |
2524 |
err = hermes_bap_pwrite(hw, USER_BAP, p, ALIGN(data_len, 2), |
sizeof(essidbuf), NULL, &essidbuf); |
2525 |
txfid, data_off); |
if (err) |
2526 |
if (err) { |
goto fail_unlock; |
|
printk(KERN_ERR "%s: Error %d writing packet to BAP\n", |
|
|
dev->name, err); |
|
|
stats->tx_errors++; |
|
|
goto fail; |
|
2527 |
} |
} |
2528 |
|
|
2529 |
/* Finally, we actually initiate the send */ |
len = le16_to_cpu(essidbuf.len); |
2530 |
netif_stop_queue(dev); |
BUG_ON(len > IW_ESSID_MAX_SIZE); |
|
|
|
|
err = hermes_docmd_wait(hw, HERMES_CMD_TX | HERMES_CMD_RECL, |
|
|
txfid, NULL); |
|
|
if (err) { |
|
|
netif_start_queue(dev); |
|
|
printk(KERN_ERR "%s: Error %d transmitting packet\n", |
|
|
dev->name, err); |
|
|
stats->tx_errors++; |
|
|
goto fail; |
|
|
} |
|
2531 |
|
|
2532 |
dev->trans_start = jiffies; |
memset(buf, 0, IW_ESSID_MAX_SIZE+1); |
2533 |
stats->tx_bytes += data_off + data_len; |
memcpy(buf, p, len); |
2534 |
|
buf[len] = '\0'; |
2535 |
|
|
2536 |
|
fail_unlock: |
2537 |
orinoco_unlock(priv, &flags); |
orinoco_unlock(priv, &flags); |
2538 |
|
|
2539 |
dev_kfree_skb(skb); |
return err; |
|
|
|
|
TRACE_EXIT(dev->name); |
|
|
|
|
|
return 0; |
|
|
fail: |
|
|
TRACE_EXIT(dev->name); |
|
|
|
|
|
orinoco_unlock(priv, &flags); |
|
|
return err; |
|
2540 |
} |
} |
2541 |
|
|
2542 |
static void |
static long orinoco_hw_get_freq(struct orinoco_private *priv) |
|
orinoco_tx_timeout(struct net_device *dev) |
|
2543 |
{ |
{ |
2544 |
struct orinoco_private *priv = (struct orinoco_private *)dev->priv; |
|
2545 |
struct net_device_stats *stats = &priv->stats; |
hermes_t *hw = &priv->hw; |
2546 |
struct hermes *hw = &priv->hw; |
int err = 0; |
2547 |
|
u16 channel; |
2548 |
printk(KERN_WARNING "%s: Tx timeout! " |
long freq = 0; |
2549 |
"ALLOCFID=%04x, TXCOMPLFID=%04x, EVSTAT=%04x\n", |
unsigned long flags; |
|
dev->name, hermes_read_regn(hw, ALLOCFID), |
|
|
hermes_read_regn(hw, TXCOMPLFID), hermes_read_regn(hw, EVSTAT)); |
|
|
|
|
|
stats->tx_errors++; |
|
2550 |
|
|
2551 |
schedule_work(&priv->reset_work); |
err = orinoco_lock(priv, &flags); |
2552 |
} |
if (err) |
2553 |
|
return err; |
2554 |
|
|
2555 |
|
err = hermes_read_wordrec(hw, USER_BAP, HERMES_RID_CURRENTCHANNEL, &channel); |
2556 |
|
if (err) |
2557 |
|
goto out; |
2558 |
|
|
2559 |
static int |
/* Intersil firmware 1.3.5 returns 0 when the interface is down */ |
2560 |
orinoco_change_mtu(struct net_device *dev, int new_mtu) |
if (channel == 0) { |
2561 |
{ |
err = -EBUSY; |
2562 |
struct orinoco_private *priv = dev->priv; |
goto out; |
2563 |
|
} |
2564 |
|
|
2565 |
if ( (new_mtu < ORINOCO_MIN_MTU) || (new_mtu > ORINOCO_MAX_MTU) ) |
if ( (channel < 1) || (channel > NUM_CHANNELS) ) { |
2566 |
return -EINVAL; |
printk(KERN_WARNING "%s: Channel out of range (%d)!\n", |
2567 |
|
priv->ndev->name, channel); |
2568 |
|
err = -EBUSY; |
2569 |
|
goto out; |
2570 |
|
|
2571 |
if ( (new_mtu + ENCAPS_OVERHEAD + IEEE802_11_HLEN) > |
} |
2572 |
(priv->nicbuf_size - ETH_HLEN) ) |
freq = channel_frequency[channel-1] * 100000; |
|
return -EINVAL; |
|
2573 |
|
|
2574 |
dev->mtu = new_mtu; |
out: |
2575 |
|
orinoco_unlock(priv, &flags); |
2576 |
|
|
2577 |
return 0; |
if (err > 0) |
2578 |
|
err = -EBUSY; |
2579 |
|
return err ? err : freq; |
2580 |
} |
} |
2581 |
|
|
2582 |
/* FIXME: return int? */ |
static int orinoco_hw_get_bitratelist(struct orinoco_private *priv, |
2583 |
static void |
int *numrates, s32 *rates, int max) |
|
__orinoco_set_multicast_list(struct net_device *dev) |
|
2584 |
{ |
{ |
|
struct orinoco_private *priv = dev->priv; |
|
2585 |
hermes_t *hw = &priv->hw; |
hermes_t *hw = &priv->hw; |
2586 |
|
struct hermes_idstring list; |
2587 |
|
unsigned char *p = (unsigned char *)&list.val; |
2588 |
int err = 0; |
int err = 0; |
2589 |
int promisc, mc_count; |
int num; |
2590 |
|
int i; |
2591 |
/* The Hermes doesn't seem to have an allmulti mode, so we go |
unsigned long flags; |
|
* into promiscuous mode and let the upper levels deal. */ |
|
|
if ( (dev->flags & IFF_PROMISC) || (dev->flags & IFF_ALLMULTI) || |
|
|
(dev->mc_count > MAX_MULTICAST(priv)) ) { |
|
|
promisc = 1; |
|
|
mc_count = 0; |
|
|
} else { |
|
|
promisc = 0; |
|
|
mc_count = dev->mc_count; |
|
|
} |
|
2592 |
|
|
2593 |
if (promisc != priv->promiscuous) { |
err = orinoco_lock(priv, &flags); |
2594 |
err = hermes_write_wordrec(hw, USER_BAP, |
if (err) |
2595 |
HERMES_RID_CNFPROMISCUOUSMODE, |
return err; |
|
promisc); |
|
|
if (err) { |
|
|
printk(KERN_ERR "%s: Error %d setting PROMISCUOUSMODE to 1.\n", |
|
|
dev->name, err); |
|
|
} else |
|
|
priv->promiscuous = promisc; |
|
|
} |
|
2596 |
|
|
2597 |
if (! promisc && (mc_count || priv->mc_count) ) { |
err = hermes_read_ltv(hw, USER_BAP, HERMES_RID_SUPPORTEDDATARATES, |
2598 |
struct dev_mc_list *p = dev->mc_list; |
sizeof(list), NULL, &list); |
2599 |
hermes_multicast_t mclist; |
orinoco_unlock(priv, &flags); |
|
int i; |
|
2600 |
|
|
2601 |
for (i = 0; i < mc_count; i++) { |
if (err) |
2602 |
/* Paranoia: */ |
return err; |
2603 |
if (! p) |
|
2604 |
BUG(); /* Multicast list shorter than mc_count */ |
num = le16_to_cpu(list.len); |
2605 |
if (p->dmi_addrlen != ETH_ALEN) |
*numrates = num; |
2606 |
BUG(); /* Bad address size in multicast list */ |
num = min(num, max); |
|
|
|
|
memcpy(mclist.addr[i], p->dmi_addr, ETH_ALEN); |
|
|
p = p->next; |
|
|
} |
|
|
|
|
|
if (p) |
|
|
printk(KERN_WARNING "Multicast list is longer than mc_count\n"); |
|
2607 |
|
|
2608 |
err = hermes_write_ltv(hw, USER_BAP, HERMES_RID_CNFGROUPADDRESSES, |
for (i = 0; i < num; i++) { |
2609 |
HERMES_BYTES_TO_RECLEN(priv->mc_count * ETH_ALEN), |
rates[i] = (p[i] & 0x7f) * 500000; /* convert to bps */ |
|
&mclist); |
|
|
if (err) |
|
|
printk(KERN_ERR "%s: Error %d setting multicast list.\n", |
|
|
dev->name, err); |
|
|
else |
|
|
priv->mc_count = mc_count; |
|
2610 |
} |
} |
2611 |
|
|
2612 |
/* Since we can set the promiscuous flag when it wasn't asked |
return 0; |
|
for, make sure the net_device knows about it. */ |
|
|
if (priv->promiscuous) |
|
|
dev->flags |= IFF_PROMISC; |
|
|
else |
|
|
dev->flags &= ~IFF_PROMISC; |
|
2613 |
} |
} |
2614 |
|
|
|
/********************************************************************/ |
|
|
/* Wireless extensions support */ |
|
|
/********************************************************************/ |
|
|
|
|
2615 |
static int orinoco_ioctl_getiwrange(struct net_device *dev, |
static int orinoco_ioctl_getiwrange(struct net_device *dev, |
2616 |
struct iw_point *rrq) |
struct iw_point *rrq) |
2617 |
{ |
{ |
3270 |
|
|
3271 |
ratemode = priv->bitratemode; |
ratemode = priv->bitratemode; |
3272 |
|
|
3273 |
if ( (ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE) ) |
BUG_ON((ratemode < 0) || (ratemode >= BITRATE_TABLE_SIZE)); |
|
BUG(); |
|
3274 |
|
|
3275 |
rrq->value = bitrate_table[ratemode].bitrate * 100000; |
rrq->value = bitrate_table[ratemode].bitrate * 100000; |
3276 |
rrq->fixed = ! bitrate_table[ratemode].automatic; |
rrq->fixed = ! bitrate_table[ratemode].automatic; |
3667 |
return 0; |
return 0; |
3668 |
} |
} |
3669 |
|
|
3670 |
static int |
static int orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
|
orinoco_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) |
|
3671 |
{ |
{ |
3672 |
struct orinoco_private *priv = dev->priv; |
struct orinoco_private *priv = dev->priv; |
3673 |
struct iwreq *wrq = (struct iwreq *)rq; |
struct iwreq *wrq = (struct iwreq *)rq; |
4013 |
return err; |
return err; |
4014 |
} |
} |
4015 |
|
|
4016 |
|
/********************************************************************/ |
4017 |
|
/* Debugging */ |
4018 |
|
/********************************************************************/ |
4019 |
|
|
4020 |
|
#if 0 |
4021 |
|
static void show_rx_frame(struct orinoco_rxframe_hdr *frame) |
4022 |
|
{ |
4023 |
|
printk(KERN_DEBUG "RX descriptor:\n"); |
4024 |
|
printk(KERN_DEBUG " status = 0x%04x\n", frame->desc.status); |
4025 |
|
printk(KERN_DEBUG " time = 0x%08x\n", frame->desc.time); |
4026 |
|
printk(KERN_DEBUG " silence = 0x%02x\n", frame->desc.silence); |
4027 |
|
printk(KERN_DEBUG " signal = 0x%02x\n", frame->desc.signal); |
4028 |
|
printk(KERN_DEBUG " rate = 0x%02x\n", frame->desc.rate); |
4029 |
|
printk(KERN_DEBUG " rxflow = 0x%02x\n", frame->desc.rxflow); |
4030 |
|
printk(KERN_DEBUG " reserved = 0x%08x\n", frame->desc.reserved); |
4031 |
|
|
4032 |
|
printk(KERN_DEBUG "IEEE 802.11 header:\n"); |
4033 |
|
printk(KERN_DEBUG " frame_ctl = 0x%04x\n", |
4034 |
|
frame->p80211.frame_ctl); |
4035 |
|
printk(KERN_DEBUG " duration_id = 0x%04x\n", |
4036 |
|
frame->p80211.duration_id); |
4037 |
|
printk(KERN_DEBUG " addr1 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4038 |
|
frame->p80211.addr1[0], frame->p80211.addr1[1], |
4039 |
|
frame->p80211.addr1[2], frame->p80211.addr1[3], |
4040 |
|
frame->p80211.addr1[4], frame->p80211.addr1[5]); |
4041 |
|
printk(KERN_DEBUG " addr2 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4042 |
|
frame->p80211.addr2[0], frame->p80211.addr2[1], |
4043 |
|
frame->p80211.addr2[2], frame->p80211.addr2[3], |
4044 |
|
frame->p80211.addr2[4], frame->p80211.addr2[5]); |
4045 |
|
printk(KERN_DEBUG " addr3 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4046 |
|
frame->p80211.addr3[0], frame->p80211.addr3[1], |
4047 |
|
frame->p80211.addr3[2], frame->p80211.addr3[3], |
4048 |
|
frame->p80211.addr3[4], frame->p80211.addr3[5]); |
4049 |
|
printk(KERN_DEBUG " seq_ctl = 0x%04x\n", |
4050 |
|
frame->p80211.seq_ctl); |
4051 |
|
printk(KERN_DEBUG " addr4 = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4052 |
|
frame->p80211.addr4[0], frame->p80211.addr4[1], |
4053 |
|
frame->p80211.addr4[2], frame->p80211.addr4[3], |
4054 |
|
frame->p80211.addr4[4], frame->p80211.addr4[5]); |
4055 |
|
printk(KERN_DEBUG " data_len = 0x%04x\n", |
4056 |
|
frame->p80211.data_len); |
4057 |
|
|
4058 |
|
printk(KERN_DEBUG "IEEE 802.3 header:\n"); |
4059 |
|
printk(KERN_DEBUG " dest = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4060 |
|
frame->p8023.h_dest[0], frame->p8023.h_dest[1], |
4061 |
|
frame->p8023.h_dest[2], frame->p8023.h_dest[3], |
4062 |
|
frame->p8023.h_dest[4], frame->p8023.h_dest[5]); |
4063 |
|
printk(KERN_DEBUG " src = %02x:%02x:%02x:%02x:%02x:%02x\n", |
4064 |
|
frame->p8023.h_source[0], frame->p8023.h_source[1], |
4065 |
|
frame->p8023.h_source[2], frame->p8023.h_source[3], |
4066 |
|
frame->p8023.h_source[4], frame->p8023.h_source[5]); |
4067 |
|
printk(KERN_DEBUG " len = 0x%04x\n", frame->p8023.h_proto); |
4068 |
|
|
4069 |
|
printk(KERN_DEBUG "IEEE 802.2 LLC/SNAP header:\n"); |
4070 |
|
printk(KERN_DEBUG " DSAP = 0x%02x\n", frame->p8022.dsap); |
4071 |
|
printk(KERN_DEBUG " SSAP = 0x%02x\n", frame->p8022.ssap); |
4072 |
|
printk(KERN_DEBUG " ctrl = 0x%02x\n", frame->p8022.ctrl); |
4073 |
|
printk(KERN_DEBUG " OUI = %02x:%02x:%02x\n", |
4074 |
|
frame->p8022.oui[0], frame->p8022.oui[1], frame->p8022.oui[2]); |
4075 |
|
printk(KERN_DEBUG " ethertype = 0x%04x\n", frame->ethertype); |
4076 |
|
} |
4077 |
|
#endif /* 0 */ |
4078 |
|
|
4079 |
struct { |
struct { |
4080 |
u16 rid; |
u16 rid; |
4081 |
char *name; |
char *name; |
4259 |
return 0; |
return 0; |
4260 |
} |
} |
4261 |
|
|
|
struct net_device *alloc_orinocodev(int sizeof_card, |
|
|
int (*hard_reset)(struct orinoco_private *)) |
|
|
{ |
|
|
struct net_device *dev; |
|
|
struct orinoco_private *priv; |
|
|
|
|
|
dev = alloc_etherdev(sizeof(struct orinoco_private) + sizeof_card); |
|
|
priv = (struct orinoco_private *)dev->priv; |
|
|
priv->ndev = dev; |
|
|
if (sizeof_card) |
|
|
priv->card = (void *)((unsigned long)dev->priv |
|
|
+ sizeof(struct orinoco_private)); |
|
|
else |
|
|
priv->card = NULL; |
|
|
|
|
|
/* Setup / override net_device fields */ |
|
|
dev->init = orinoco_init; |
|
|
dev->hard_start_xmit = orinoco_xmit; |
|
|
dev->tx_timeout = orinoco_tx_timeout; |
|
|
dev->watchdog_timeo = HZ; /* 1 second timeout */ |
|
|
dev->get_stats = orinoco_get_stats; |
|
|
dev->get_wireless_stats = orinoco_get_wireless_stats; |
|
|
dev->do_ioctl = orinoco_ioctl; |
|
|
dev->change_mtu = orinoco_change_mtu; |
|
|
dev->set_multicast_list = orinoco_set_multicast_list; |
|
|
/* we use the default eth_mac_addr for setting the MAC addr */ |
|
|
|
|
|
/* Set up default callbacks */ |
|
|
dev->open = orinoco_open; |
|
|
dev->stop = orinoco_stop; |
|
|
priv->hard_reset = hard_reset; |
|
|
|
|
|
spin_lock_init(&priv->lock); |
|
|
priv->open = 0; |
|
|
priv->hw_unavailable = 1; /* orinoco_init() must clear this |
|
|
* before anything else touches the |
|
|
* hardware */ |
|
|
INIT_WORK(&priv->reset_work, (void (*)(void *))orinoco_reset, dev); |
|
|
|
|
|
netif_carrier_off(dev); |
|
|
priv->last_linkstatus = 0xffff; |
|
|
|
|
|
return dev; |
|
|
|
|
|
} |
|
|
|
|
4262 |
/********************************************************************/ |
/********************************************************************/ |
4263 |
/* Module initialization */ |
/* Module initialization */ |
4264 |
/********************************************************************/ |
/********************************************************************/ |