Index: /src/router/rt2860apd/COPYING
===================================================================
--- /src/router/rt2860apd/COPYING	(revision 10789)
+++ /src/router/rt2860apd/COPYING	(revision 10789)
@@ -0,0 +1,345 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                       59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+			    Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+
+		    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+			    NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+		     END OF TERMS AND CONDITIONS
+
+
+	    How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) 19yy  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) 19yy name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Library General
+Public License instead of this License.
Index: /src/router/rt2860apd/Makefile
===================================================================
--- /src/router/rt2860apd/Makefile	(revision 10789)
+++ /src/router/rt2860apd/Makefile	(revision 10789)
@@ -0,0 +1,28 @@
+PLATFORM = RT2880
+
+ifndef CFLAGS
+CFLAGS = -O2 -Wall -g
+endif
+
+# If you want to support multiple radius server for multiple bssid, add following line
+CFLAGS +=  -DMULTIPLE_RADIUS -DNEED_PRINTF
+
+# If you want to debug daemon, add following line
+CFLAGS +=  -DDBG 
+
+OBJS =	rt2860apd.o eloop.o eapol_sm.o radius.o md5.o  \
+	config.o ieee802_1x.o  \
+	sta_info.o   radius_client.o
+
+all: rt2860apd
+
+rt2860apd: $(OBJS)
+	$(CC) -o rt2860apd $(OBJS)
+
+clean:
+	rm -f core *~ *.o rt2860apd *.d
+
+install:
+	install -d $(INSTALLDIR)/usr/sbin
+	install rt2860apd $(INSTALLDIR)/usr/sbin/rt2860apd
+
Index: /src/router/rt2860apd/Makefile.release
===================================================================
--- /src/router/rt2860apd/Makefile.release	(revision 10789)
+++ /src/router/rt2860apd/Makefile.release	(revision 10789)
@@ -0,0 +1,11 @@
+all: rt2860apd
+
+rt2860apd: $(OBJS)
+	$(CC) -o rt2860apd $(OBJS)
+
+clean:
+	rm -f core *~ *.o  *.d
+
+romfs:
+	$(ROMFSINST) rt2860apd /bin/rt2860apd
+
Index: /src/router/rt2860apd/README
===================================================================
--- /src/router/rt2860apd/README	(revision 10789)
+++ /src/router/rt2860apd/README	(revision 10789)
@@ -0,0 +1,176 @@
+
+RT2860apd - user space IEEE 802.1X Authenticator
+          for RT2860 linux driver, Ralink Tech Corp.
+=================================================================
+Copyright (c) 2002-2003, Jouni Malinen <jkmaline@cc.hut.fi>
+
+This program is free software; you can redistribute it and/or modify
+it under the terms of the GNU General Public License version 2 as
+published by the Free Software Foundation. See COPYING for more
+details.
+
+=================================================================
+
+This is the README file for the 802.1x daemon - rt2860apd, which comes with RT2860 linux driver.
+This README explains the relationship between the linux driver and 802.1x daemon.
+In addtiion, this will teach you how to use this 802.1x daemon.
+For programmers who want to add other interfaces for linux driver or 802.1x daemon,
+This README has also mentions below.
+
+I.  Introduction
+=================================================================
+rt2860apd is an optional user space component for RT2860 linux driver. 
+It adds 802.1x Authenticator feature using external RADIUS Authentication
+Server(AS).
+ 
+
+II.  IEEE 802.1X features in rt2860apd
+=================================================================
+IEEE Std 802.1X-2001 is a standard for port-based network access
+control. It introduces a extensible mechanism for authenticating 
+and authorizing users.
+
+rt2860apd implements partial IEEE 802.1x features that helps AS authenrizing
+Supplicant and in the mean time proves itself a valid Authenticator for AS.
+Noticed that Key management state machine is not included in rt2860apd. 
+And those key management is included in RT2860 linux driver.
+
+rt2860apd relays the frames between the Supplicant and the AS.
+Not until either one timeout or Success or Fail frame
+indicated does rt2860apd finish the authentication process.
+The port control entity is implemented in linux driver for RT2860.
+
+
+III.  How to start rt2860apd
+=================================================================
+1. First we need to compile the source code using 'make' command
+2.	The command synopsis as below,
+	rt2860apd [-d debug_level] [-i card_number]
+
+		-d debug_level
+				Allow user to set debug level. This debug_level 
+				parameter must be 0~4.
+				0 : RT_DEBUG_OFF
+   	  			1 : RT_DEBUG_ERROR
+   	  			2 : RT_DEBUG_WARN
+   	  			3 : RT_DEBUG_TRACE
+   	  			4 : RT_DEBUG_INFO	
+				
+		-i card_number
+				Only work for multiple card function of RT2860 linux 
+				driver. This command provides users to assign the 
+				corresponding wireless card. 
+				p.s.
+					The card_number set 1, it mean that the daemon works with the 1st card(ra00-x). 		
+					The card_number set 2, it mean that the daemon works with the 2nd card(ra01-x).
+					....
+	
+3. 	Manually start rt2860apd, default type $rt2860apd
+
+IV.  rt2860apd configuration for IEEE 802.1X
+=================================================================
+When rt2860apd starts, it reads the configuraion file to derive parameters.
+For any changes to make, one need to first edit the configuration file, then
+restart rt2860apd. Noted that manually restarting rt2860apd is unnecessary,
+because setting linux driver's SSID with command 'iwpriv' will automatically restart rt2860apd.
+In a word, edit the configuraion file and then set its SSID is all to do to change
+any settings related to 802.1x authenticaion.
+
+This common configuraion file is RT2860AP.dat, located in /etc/Wireless/RT2860AP/.
+The format of configuraion file is "Paramater = Value". Each line contains one parameter setting.
+The following describes how to achieve :
+
+1.) How to configure RT2860 driver?
+========================================
+Add correct values for AuthMode and EncrypType parameters.
+If you edit like this, 
+AuthMode=WPA
+EncrypType=TKIP
+you would like the AP to use WPA with TKIP to encrypt the data packets.
+
+To change SSID, you can type $iwpriv ra0 set SSID=yourssid
+
+
+2.) How to configure 802.1x daemon?
+========================================
+4 essential paramters for 802.1x authenticaion are RADIUS_Server, RADIUS_Port, RADIUS_Key and own_ip_addr.
+for example,
+RADIUS_Server=192.168.2.3
+RADIUS_Port=1812
+RADIUS_Key=password
+own_ip_addr=192.168.1.123
+This implies the RADIUS Server' IP is 192.168.2.3. Port 1812 is used for 802.1x authenticaion.
+The RADIUS secret between AP(RADIUS client) and RADIUS server is password. AP's IP is 192.168.1.123.
+For any changes to make, edit the configuraion file, and set the AP's SSID again to restart rt2860apd.
+
+The optional variables as below,
+session_timeout_interval is for 802.1x reauthentication setting.
+set zero to disable 802.1x reauthentication service for each session.
+session_timeout_interval unit is second and must be larger than 60.
+for example,
+session_timeout_interval = 120
+will reauthenticate each session every 2 minutes.
+session_timeout_interval = 0
+will disable reauthenticate service.
+
+EAPifname is assigned as the binding interface for EAP negotiation.
+Its default value is "br0". But if the wireless interface doesn't attach to bridge interface 
+or the bridge interface name isn't "br0", please modify it.
+for example,
+	EAPifname=br0
+
+PreAuthifname is assigned as the binding interface for WPA2 Pre-authentication.
+Its default value is "br0". But if the ethernet interface doesn't attach to bridge interface 
+or the bridge interface name isn't "br0", please modify it.
+for example,
+	PreAuthifname=br0
+
+V.  How to add other interfaces to this linux driver and 802.1x daemon?
+=================================================================
+For programmers who want to add interface for 802.1x daemon and linux driver,
+edit the configuration file and reset its SSID via linux IOCTL. 
+Detailed linux IOCTL informtaion is in the interface.txt come with 802.1x daemon.
+Please refer to that.
+
+
+VI. Multiple RADIUS Server supporting
+=================================================================
+We use complier option to turn on/off the multiple RADIUS servers for 802.1x. 
+	If you want to enable the feature, make sure that "MULTIPLE_RADIUS" is defined in Makefile.
+	Default is disabled. Besides, you must modify the file "RT2860AP.dat" to co-operate with 802.1x.
+We extend some variables to support individual RADIUS server IP address, port and secret key for MBSS. 
+
+	For example :
+		RADIUS_Server=192.168.2.1;192.168.2.2;192.168.2.3;192.168.2.4
+		RADIUS_Port=1811;1812;1813;1814
+		RADIUS_Key=ralink_1;ralink_2;ralink_3;ralink_4
+		or
+		RADIUS_Key1=ralink_1
+		RADIUS_Key2=ralink_2
+		RADIUS_Key3=ralink_3
+		RADIUS_Key4=ralink_4
+
+		For backward compatible, driver would parse "RADIUS_Key" or "RADIUS_KeyX"(X=1~4) for radius key usage.
+		But the paramter "RADIUS_Key" has the first priority.
+
+		p.s. This implies the RADIUS server IP of ra0 is 192.168.2.1, its port is 1811 and its secret key is ralink_1. 
+			 The RADIUS server IP of ra1 is 192.168.2.2, its port is 1812 and its secret key is ralink_2. 	
+			 The RADIUS server IP of ra2 is 192.168.2.3, its port is 1813 and its secret key is ralink_3. 	
+			 The RADIUS server IP of ra3 is 192.168.2.4, its port is 1814 and its secret key is ralink_4. 	
+
+VII. Enhance dynamic wep keying
+=================================================================
+In OPEN-WEP with 802.1x mode, the authentication process generates broadcast and unicast key.
+The unicast key is unique for every individual client so it is always generated randomly by 
+802.1x daemon. 
+But the broadcast key is shared for all associated clients, it can be pre-set manually by users or 
+generated randomly by 802.1x daemon.
+
+Through the parameter "DefaultKeyID" and its corresponding parameter "KeyXStr"(i.e. X = the value of DefaultKeyID)
+in RT2860Ap.dat, the 802.1x daemon would use it as the broadcast key material. But if the corresponding parameter "KeyXStr" is
+empty or unsuitable, the broadcast key would be generated randomly by the 802.1x daemon.
+
+The 802.1x daemon need to read RT2860AP.dat to decide whether the broadcast key is generated
+randomly or not, so please update the RT2860AP.dat and restart rt2860apd if those correlative parameters are changed. 
+
+
Index: /src/router/rt2860apd/ap.h
===================================================================
--- /src/router/rt2860apd/ap.h	(revision 10789)
+++ /src/router/rt2860apd/ap.h	(revision 10789)
@@ -0,0 +1,82 @@
+#ifndef AP_H
+#define AP_H
+
+/* STA flags */
+#define WLAN_STA_AUTH           BIT(0)
+#define WLAN_STA_ASSOC          BIT(1)
+#define WLAN_STA_PS             BIT(2)
+#define WLAN_STA_TIM            BIT(3)
+#define WLAN_STA_PERM           BIT(4)
+#define WLAN_STA_PENDING_POLL   BIT(6) /* pending activity poll not ACKed */
+
+#define WLAN_RATE_1M            BIT(0)
+#define WLAN_RATE_2M            BIT(1)
+#define WLAN_RATE_5M5           BIT(2)
+#define WLAN_RATE_11M           BIT(3)
+#define WLAN_RATE_COUNT         4
+
+/* Maximum size of Supported Rates info element. IEEE 802.11 has a limit of 8,
+ * but some pre-standard IEEE 802.11g products use longer elements. */
+#define WLAN_SUPP_RATES_MAX     32
+
+
+struct sta_info {
+	struct sta_info         *next; /* next entry in sta list */
+	struct sta_info         *hnext; /* next entry in hash table list */
+	u8                      addr[6];
+	u16                     aid; /* STA's unique AID (1 .. 2007) or 0 if not yet assigned */
+	u32                     flags;
+	u16                     capability;
+	u16                     listen_interval; /* or beacon_int for APs */
+	u8                      supported_rates[WLAN_SUPP_RATES_MAX];
+	u8                      tx_supp_rates;
+
+	enum { STA_NULLFUNC = 0, STA_DISASSOC, STA_DEAUTH } timeout_next;
+
+	/* IEEE 802.1X related data */
+	struct                  eapol_state_machine *eapol_sm;
+	int                     radius_identifier;
+	/* TODO: check when the last messages can be released */
+	struct radius_msg       *last_recv_radius;
+	u8                      *last_eap_supp; /* last received EAP Response from Supplicant */
+	size_t                  last_eap_supp_len;
+	u8                      *last_eap_radius; /* last received EAP Response from Authentication Server */
+	size_t                  last_eap_radius_len;
+	u8                      *identity;
+	size_t                  identity_len;
+
+	/* Keys for encrypting and signing EAPOL-Key frames */
+	u8                      *eapol_key_sign;
+	size_t                  eapol_key_sign_len;
+	u8                      *eapol_key_crypt;
+	size_t                  eapol_key_crypt_len;
+
+	/* IEEE 802.11f (IAPP) related data */
+	struct ieee80211_mgmt   *last_assoc_req;
+
+	// Multiple SSID interface
+	u8						ApIdx;
+	u16						ethertype;
+};
+
+#define MAX_STA_COUNT           1024
+
+/* Maximum number of AIDs to use for STAs; must be 2007 or lower
+ * (8802.11 limitation) */
+#define MAX_AID_TABLE_SIZE      256
+
+#define STA_HASH_SIZE           256
+#define STA_HASH(sta)           (sta[5])
+
+/* Default value for maximum station inactivity. After AP_MAX_INACTIVITY has
+ * passed since last received frame from the station, a nullfunc data frame is
+ * sent to the station. If this frame is not acknowledged and no other frames
+ * have been received, the station will be disassociated after
+ * AP_DISASSOC_DELAY. Similarily, a the station will be deauthenticated after
+ * AP_DEAUTH_DELAY. AP_TIMEOUT_RESOLUTION is the resolution that is used with
+ * max inactivity timer. All these times are in seconds. */
+#define AP_MAX_INACTIVITY       (5* 60)
+#define AP_DISASSOC_DELAY       (1)
+#define AP_DEAUTH_DELAY         (1)
+
+#endif /* AP_H */
Index: /src/router/rt2860apd/common.h
===================================================================
--- /src/router/rt2860apd/common.h	(revision 10789)
+++ /src/router/rt2860apd/common.h	(revision 10789)
@@ -0,0 +1,48 @@
+#ifndef COMMON_H
+#define COMMON_H
+
+#include <endian.h>
+#include <byteswap.h>
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define le_to_host16(n) (n)
+#define host_to_le16(n) (n)
+#define be_to_host16(n) bswap_16(n)
+#define host_to_be16(n) bswap_16(n)
+#else
+#define le_to_host16(n) bswap_16(n)
+#define host_to_le16(n) bswap_16(n)
+#define be_to_host16(n) (n)
+#define host_to_be16(n) (n)
+#endif
+
+
+#include <stdint.h>
+typedef uint64_t u64;
+typedef uint32_t u32;
+typedef uint16_t u16;
+typedef uint8_t u8;
+typedef int64_t s64;
+typedef int32_t s32;
+typedef int16_t s16;
+typedef int8_t s8;
+
+void hostapd_hexdump(const char *title, u8 *buf, size_t len);
+int hwaddr_aton(char *txt, u8 *addr);
+
+static inline void print_char(char c)
+{
+	if (c >= 32 && c < 127)
+		printf("%c", c);
+	else
+		printf("<%02x>", c);
+}
+
+static inline void fprint_char(FILE *f, char c)
+{
+	if (c >= 32 && c < 127)
+		fprintf(f, "%c", c);
+	else
+		fprintf(f, "<%02x>", c);
+}
+
+#endif /* COMMON_H */
Index: /src/router/rt2860apd/config.c
===================================================================
--- /src/router/rt2860apd/config.c	(revision 10789)
+++ /src/router/rt2860apd/config.c	(revision 10789)
@@ -0,0 +1,501 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+    Module Name:
+    config.c
+
+    Revision History:
+    Who         When          What
+    --------    ----------    ----------------------------------------------
+    Jan, Lee    Dec --2003    modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/ioctl.h>
+
+#include <linux/if.h>			/* for IFNAMSIZ and co... */
+#include <linux/wireless.h>
+
+#include "rt2860apd.h"
+#include "ieee802_1x.h"
+#include "md5.h"
+
+unsigned char BtoH(
+    unsigned char ch)
+{
+    if (ch >= '0' && ch <= '9') return (ch - '0');        // Handle numerals
+    if (ch >= 'A' && ch <= 'F') return (ch - 'A' + 0xA);  // Handle capitol hex digits
+    if (ch >= 'a' && ch <= 'f') return (ch - 'a' + 0xA);  // Handle small hex digits
+    return(255);
+}
+
+//
+//  PURPOSE:  Converts ascii string to network order hex
+//
+//  PARAMETERS:
+//    src    - pointer to input ascii string
+//    dest   - pointer to output hex
+//    destlen - size of dest
+//
+//  COMMENTS:
+//
+//    2 ascii bytes make a hex byte so must put 1st ascii byte of pair
+//    into upper nibble and 2nd ascii byte of pair into lower nibble.
+//
+void AtoH(
+    char            *src,
+    unsigned char	*dest,
+    int		        destlen)
+{
+    char *srcptr;
+    unsigned char *destTemp;
+
+    srcptr = src;   
+    destTemp = (unsigned char *) dest; 
+
+    while(destlen--)
+    {
+        *destTemp = BtoH(*srcptr++) << 4;    // Put 1st ascii byte in upper nibble.
+        *destTemp += BtoH(*srcptr++);      // Add 2nd ascii byte to above.
+        destTemp++;
+    }
+}
+
+/**
+ * rstrtok - Split a string into tokens
+ * @s: The string to be searched
+ * @ct: The characters to search for
+ * * WARNING: strtok is deprecated, use strsep instead. However strsep is not compatible with old architecture.
+ */
+char * __rstrtok;
+char * rstrtok(char * s,const char * ct)
+{
+	char *sbegin, *send;
+
+	sbegin  = s ? s : __rstrtok;
+	if (!sbegin)
+	{
+		return NULL;
+	}
+
+	sbegin += strspn(sbegin,ct);
+	if (*sbegin == '\0')
+	{
+		__rstrtok = NULL;
+		return( NULL );
+	}
+
+	send = strpbrk( sbegin, ct);
+	if (send && *send != '\0')
+		*send++ = '\0';
+
+	__rstrtok = send;
+
+	return (sbegin);
+}
+
+
+static int
+Config_read_radius_addr(struct hostapd_radius_server **server,
+                int *num_server, unsigned int addr, int def_port,
+                struct hostapd_radius_server **curr_serv)
+{
+    struct hostapd_radius_server *nserv;
+    int ret = 0;
+
+	if (addr == 0)
+		return -1;
+
+    nserv = realloc(*server, (*num_server + 1) * sizeof(*nserv));
+    if (nserv == NULL)
+        return -1;
+
+    *server = nserv;
+    nserv = &nserv[*num_server];
+    (*num_server)++;
+    (*curr_serv) = nserv;
+
+    memset(nserv, 0, sizeof(*nserv));
+    nserv->port = def_port;
+	
+	//if (addr == 0)
+	//	ret = -1;		
+	//else		
+    	nserv->addr.s_addr = addr;	
+
+    return ret;
+}
+
+BOOLEAN Query_config_from_driver(int ioctl_sock, char *prefix_name, struct rtapd_config *conf, int *errors, int *flag)
+{
+	char 	*buf;	
+	int 	len;	
+    int		i, idx, m_num; 
+	int		radius_count = 0, radius_port_count = 0, radius_key_count = 0;    
+	PRADIUS_CONF pRadiusConf;
+
+	*flag = 0;
+	*errors = 0;	
+
+	len = sizeof(RADIUS_CONF);	
+	buf = (char *) malloc(len + 1);
+	if (buf == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "malloc() failed for Query_config_from_driver(len=%d)\n", len);
+		return FALSE;
+	}
+	else
+	{
+		DBGPRINT(RT_DEBUG_TRACE, "alloc memory(%d) for Query_config_from_driver. \n", len);
+		memset(buf, 0, len);
+	}
+				    
+	if((RT_ioctl(ioctl_sock, RT_PRIV_IOCTL, buf, len, prefix_name, 0, OID_802_11_RADIUS_QUERY_SETTING)) != 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"ioctl failed for Query_config_from_driver(len=%d, ifname=%s0)\n", len, prefix_name);
+		free(buf);
+		return FALSE;
+	}
+			
+	pRadiusConf = (PRADIUS_CONF)buf;
+
+	// BssidNum
+	conf->SsidNum = pRadiusConf->mbss_num;
+	if(conf->SsidNum > MAX_MBSSID_NUM)			
+		conf->SsidNum = 1;			
+	DBGPRINT(RT_DEBUG_TRACE, "MBSS number: %d\n", conf->SsidNum);
+
+#if MULTIPLE_RADIUS
+	m_num = conf->SsidNum;
+#else
+	m_num = 1;
+#endif
+
+	// own_ip_addr
+	conf->own_ip_addr.s_addr = pRadiusConf->own_ip_addr;
+	if (conf->own_ip_addr.s_addr != 0)
+	{		
+		(*flag) |= 0x01;
+		DBGPRINT(RT_DEBUG_TRACE, "own ip address: '%s'(%x)\n", inet_ntoa(conf->own_ip_addr), conf->own_ip_addr.s_addr);					
+	}
+	else
+	{
+		(*errors)++;
+		DBGPRINT(RT_DEBUG_ERROR, "Invalid own ip address \n");
+	}
+
+		
+	for (i = 0; i < m_num; i++)
+	{
+		for (idx = 0; idx < pRadiusConf->RadiusInfo[i].radius_srv_num; idx++)
+		{			
+#if MULTIPLE_RADIUS  	
+			// RADIUS_Server ip address
+		if (!Config_read_radius_addr(
+            &conf->mbss_auth_servers[i],
+	            &conf->mbss_num_auth_servers[i], 
+	            pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_ip, 
+	            1812,
+            &conf->mbss_auth_server[i]))
+    	{        	
+            radius_count++;
+				DBGPRINT(RT_DEBUG_TRACE, "(no.%d) Radius ip address: '%s'(%x) for %s%d\n", conf->mbss_num_auth_servers[i],
+										inet_ntoa(conf->mbss_auth_server[i]->addr), 
+										conf->mbss_auth_server[i]->addr.s_addr, prefix_name, i);
+	}				
+
+	// RADIUS_Port and RADIUS_Key      
+		if (conf->mbss_auth_server[i] && conf->mbss_auth_server[i]->addr.s_addr != 0)
+		{					
+				if (pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_port > 0)
+			{
+				radius_port_count++;
+					conf->mbss_auth_server[i]->port = pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_port;           					
+					DBGPRINT(RT_DEBUG_TRACE, "(no.%d) Radius port: '%d' for %s%d\n", conf->mbss_num_auth_servers[i], conf->mbss_auth_server[i]->port, prefix_name, i);
+			}
+			else
+					DBGPRINT(RT_DEBUG_ERROR, "(no.%d) Radius port is invalid for %s%d\n", conf->mbss_num_auth_servers[i], prefix_name, i);
+
+				if (pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_keylen > 0)
+			{
+				radius_key_count++;
+					conf->mbss_auth_server[i]->shared_secret = (u8 *)strdup((const char *)pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_key);            
+	    	        conf->mbss_auth_server[i]->shared_secret_len = pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_keylen;
+					DBGPRINT(RT_DEBUG_TRACE,"(no.%d) Radius key: '%s', key_len: %d for %s%d \n", 
+						conf->mbss_num_auth_servers[i], conf->mbss_auth_server[i]->shared_secret, conf->mbss_auth_server[i]->shared_secret_len, prefix_name, i);	
+			}
+			else
+					DBGPRINT(RT_DEBUG_ERROR, "(no.%d) Radius key is invalid for %s%d\n", conf->mbss_num_auth_servers[i], prefix_name, i);
+			
+		}
+#else
+			// RADIUS_Server ip address
+			if (!Config_read_radius_addr(
+	            &conf->auth_servers,
+	            &conf->num_auth_servers, 
+	            pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_ip, 
+	            1812,
+	            &conf->auth_server))
+		    {        	
+		            radius_count++;
+	}	
+		    DBGPRINT(RT_DEBUG_TRACE, "(no.%d) Radius ip address: '%s'(%x)\n", 
+												conf->num_auth_servers,
+												inet_ntoa(conf->auth_server->addr), 
+												conf->auth_server->addr.s_addr);
+
+			// RADIUS_Port and RADIUS_Key  
+	if (conf->auth_server && conf->auth_server->addr.s_addr != 0)
+	{
+				if (pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_port > 0)
+		{
+			radius_port_count++;
+		    		conf->auth_server->port = pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_port;
+					DBGPRINT(RT_DEBUG_TRACE,"(no.%d) Radius port: '%d'\n", conf->num_auth_servers, conf->auth_server->port);
+		}
+		else
+					DBGPRINT(RT_DEBUG_ERROR, "(no.%d) Radius port is invalid\n", conf->num_auth_servers);
+
+				if (pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_keylen > 0)
+		{
+			radius_key_count++;
+					conf->auth_server->shared_secret = (u8 *)strdup((const char *)pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_key);            
+		        	conf->auth_server->shared_secret_len = pRadiusConf->RadiusInfo[i].radius_srv_info[idx].radius_keylen;
+					DBGPRINT(RT_DEBUG_TRACE,"(no.%d) Radius key: '%s', key_len: %d \n", conf->num_auth_servers, 
+					conf->auth_server->shared_secret, conf->auth_server->shared_secret_len);	
+		} 
+		else
+					DBGPRINT(RT_DEBUG_ERROR, "(no.%d) Radius key is invalid\n", conf->num_auth_servers);
+		
+	}       
+#endif			
+		}			
+	}				
+			
+	// Sanity check for radius ip address
+	if (radius_count != 0)
+		(*flag) |= 0x02;
+	else
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "No any valid radius ip address \n");
+		(*errors)++;
+	}
+	// Sanity check for radius port number
+    if (radius_count == radius_port_count)
+		(*flag) |= 0x04;
+	else
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "No enough radius port \n");
+		(*errors)++;           
+	}         
+
+	// Sanity check for radius key 
+	if (radius_count == radius_key_count)
+		(*flag) |= 0x08;
+	else
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "No enough radius key \n");
+		(*errors)++;   
+	}   
+
+   	// radius_retry_primary_interval
+   	conf->radius_retry_primary_interval = pRadiusConf->retry_interval;
+	if (conf->radius_retry_primary_interval > 0)
+		DBGPRINT(RT_DEBUG_TRACE,"Radius retry primary interval %d seconds. \n", conf->radius_retry_primary_interval);
+
+	// session_timeout_interval
+	conf->session_timeout_interval = pRadiusConf->session_timeout_interval;                   
+    if (conf->session_timeout_interval == 0)
+    {
+        conf->session_timeout_set= 0;		
+    }	
+    else
+    {
+        conf->session_timeout_set= 1;
+
+		if (conf->session_timeout_interval < 60)
+			conf->session_timeout_interval = REAUTH_TIMER_DEFAULT_reAuthPeriod;
+				    	
+    	DBGPRINT(RT_DEBUG_TRACE,"Radius session timeout interval %d seconds. \n", conf->session_timeout_interval);
+    }
+    DBGPRINT(RT_DEBUG_TRACE,"session_timeout policy is %s \n", conf->session_timeout_set ? "enabled" : "disabled");
+
+	// EAPifname
+	if (pRadiusConf->EAPifname_len > 0)
+	{
+		memset(conf->EAPifname, 0, IFNAMSIZ);	
+		memcpy(conf->EAPifname, pRadiusConf->EAPifname, pRadiusConf->EAPifname_len);	 
+		DBGPRINT(RT_DEBUG_TRACE,"EAPifname: %s \n", conf->EAPifname);
+	}
+
+	// PreAuthifname
+	if (pRadiusConf->PreAuthifname_len > 0)
+	{
+		memset(conf->PreAuthifname, 0, IFNAMSIZ);	
+		memcpy(conf->PreAuthifname, pRadiusConf->PreAuthifname, pRadiusConf->PreAuthifname_len);	 
+		DBGPRINT(RT_DEBUG_TRACE,"PreAuthifname: %s \n", conf->PreAuthifname);
+	}
+
+	// DefaultKeyID		
+	for (i = 0; i < conf->SsidNum; i++)
+	{
+		int	g_key_len = 0;
+
+		if (pRadiusConf->RadiusInfo[i].ieee8021xWEP)
+		{
+			// set group key index
+			conf->DefaultKeyID[i] = pRadiusConf->RadiusInfo[i].key_index;	
+
+			// set unicast key index
+			if (conf->DefaultKeyID[i] == 3)
+				conf->individual_wep_key_idx[i] = 0;	
+			else
+				conf->individual_wep_key_idx[i] = 3;	
+					
+			DBGPRINT(RT_DEBUG_TRACE,"IEEE8021X WEP: group key index(%d) and unicast key index(%d) for %s%d\n", 
+																	conf->DefaultKeyID[i], conf->individual_wep_key_idx[i], prefix_name, i);
+
+			g_key_len = pRadiusConf->RadiusInfo[i].key_length;
+			if (g_key_len == 5 || g_key_len == 13)
+			{
+				conf->individual_wep_key_len[i] = g_key_len;
+				memset(conf->IEEE8021X_ikey[i], 0, WEP8021X_KEY_LEN);
+	            memcpy(conf->IEEE8021X_ikey[i], pRadiusConf->RadiusInfo[i].key_material, g_key_len);
+
+				DBGPRINT(RT_DEBUG_TRACE,"IEEE8021X WEP: use Key%dStr as shared Key and its key_len is %d for %s%d\n",
+											conf->DefaultKeyID[i]+1, g_key_len, prefix_name, i);			
+			}
+		}
+	}
+
+	free(buf);
+
+	return TRUE;
+				
+}
+
+
+struct rtapd_config * Config_read(int ioctl_sock, char *prefix_name)
+{
+    struct rtapd_config *conf;        
+    int errors = 0, i = 0;
+    int flag = 0;
+                 
+    conf = malloc(sizeof(*conf));
+    if (conf == NULL)
+    {
+        DBGPRINT(RT_DEBUG_TRACE, "Failed to allocate memory for configuration data.\n");        
+        return NULL;
+    }
+    memset(conf, 0, sizeof(*conf));
+
+    conf->SsidNum = 1;
+    conf->session_timeout_set = 0xffff;
+    
+    // initial default shared-key material and index
+    for (i = 0; i < MAX_MBSSID_NUM; i++)
+    {
+		conf->DefaultKeyID[i] = 0;										// broadcast key index
+		conf->individual_wep_key_idx[i] = 3;							// unicast key index 
+    	conf->individual_wep_key_len[i] = WEP8021X_KEY_LEN;				// key length
+    	hostapd_get_rand(conf->IEEE8021X_ikey[i], WEP8021X_KEY_LEN);    // generate shared key randomly
+  	}
+  
+	// initial default EAP IF name and Pre-Auth IF name	as "br0"
+	strcpy(conf->EAPifname, "br0");
+	strcpy(conf->PreAuthifname, "br0");
+
+	// Get parameters from deiver through IOCTL cmd
+	if(!Query_config_from_driver(ioctl_sock, prefix_name, conf, &errors, &flag))
+	{
+		Config_free(conf);
+    	return NULL;
+	}
+       
+#if MULTIPLE_RADIUS
+	for (i = 0; i < MAX_MBSSID_NUM; i++)
+	{
+		struct hostapd_radius_server *servs, *cserv, *nserv;
+		int c;
+
+		conf->mbss_auth_server[i] = conf->mbss_auth_servers[i];
+
+		if (!conf->mbss_auth_server[i])
+			continue;
+						
+		cserv	= conf->mbss_auth_server[i];
+		servs 	= conf->mbss_auth_servers[i];								
+			
+		DBGPRINT(RT_DEBUG_TRACE, "%s%d, Current IP: %s \n", prefix_name, i, inet_ntoa(cserv->addr));			
+		for (c = 0; c < conf->mbss_num_auth_servers[i]; c++)
+		{				
+			nserv = &servs[c];             
+			DBGPRINT(RT_DEBUG_TRACE, "	   Server IP List: %s \n", inet_ntoa(nserv->addr));
+		}				
+	}
+#else
+    conf->auth_server = conf->auth_servers;
+#endif
+	
+    if (errors)
+    {
+        DBGPRINT(RT_DEBUG_ERROR,"%d errors for radius setting\n", errors);
+        Config_free(conf);
+        conf = NULL;
+    }
+    if ((flag&0x0f)!=0x0f)
+    {
+        DBGPRINT(RT_DEBUG_ERROR,"Not enough necessary parameters are found, flag = %x\n", flag);
+        Config_free(conf);
+        conf = NULL;
+    }
+		
+    return conf;
+}
+
+
+static void Config_free_radius(struct hostapd_radius_server *servers, int num_servers)
+{
+    int i;
+
+    for (i = 0; i < num_servers; i++)
+    {
+        free(servers[i].shared_secret);
+    }
+    free(servers);
+}
+
+void Config_free(struct rtapd_config *conf)
+{
+#if MULTIPLE_RADIUS
+	int	i;
+#endif
+	
+    if (conf == NULL)
+        return;
+
+#if MULTIPLE_RADIUS
+	for (i = 0; i < MAX_MBSSID_NUM; i++)
+	{
+		if (conf->mbss_auth_servers[i])
+			Config_free_radius(conf->mbss_auth_servers[i], conf->mbss_num_auth_servers[i]);
+	}
+#else
+    Config_free_radius(conf->auth_servers, conf->num_auth_servers);
+#endif
+    free(conf);
+}
+
Index: /src/router/rt2860apd/config.h
===================================================================
--- /src/router/rt2860apd/config.h	(revision 10789)
+++ /src/router/rt2860apd/config.h	(revision 10789)
@@ -0,0 +1,58 @@
+#ifndef CONFIG_H
+#define CONFIG_H
+
+typedef u8 macaddr[ETH_ALEN];
+
+struct hostapd_radius_server {
+	struct in_addr addr;
+	int port;
+	u8 *shared_secret;
+	size_t shared_secret_len;
+};
+
+struct rtapd_config {
+	char iface_name[IFNAMSIZ + 1];
+	int SsidNum;
+	
+	int DefaultKeyID[MAX_MBSSID_NUM];
+	int individual_wep_key_len[MAX_MBSSID_NUM];
+	int	individual_wep_key_idx[MAX_MBSSID_NUM];
+	u8 IEEE8021X_ikey[MAX_MBSSID_NUM][WEP8021X_KEY_LEN];
+	
+#define HOSTAPD_MODULE_IEEE80211 BIT(0)
+#define HOSTAPD_MODULE_IEEE8021X BIT(1)
+#define HOSTAPD_MODULE_RADIUS BIT(2)
+
+	enum { HOSTAPD_DEBUG_NO = 0, HOSTAPD_DEBUG_MINIMAL = 1,
+	       HOSTAPD_DEBUG_VERBOSE = 2,
+	       HOSTAPD_DEBUG_MSGDUMPS = 3 } debug; /* debug verbosity level */
+	int daemonize; /* fork into background */
+
+	struct in_addr own_ip_addr;
+	
+	/* RADIUS Authentication and Accounting servers in priority order */
+#if MULTIPLE_RADIUS
+	struct hostapd_radius_server *mbss_auth_servers[MAX_MBSSID_NUM], *mbss_auth_server[MAX_MBSSID_NUM];
+	int mbss_num_auth_servers[MAX_MBSSID_NUM];
+#else
+	struct hostapd_radius_server *auth_servers, *auth_server;
+	int num_auth_servers;
+#endif
+	
+	char EAPifname[IFNAMSIZ];
+	char PreAuthifname[IFNAMSIZ];
+
+	int radius_retry_primary_interval;
+
+#define HOSTAPD_AUTH_OPEN BIT(0)
+#define HOSTAPD_AUTH_SHARED_KEY BIT(1)
+	int session_timeout_set;
+	int session_timeout_interval;
+};
+
+
+struct rtapd_config * Config_read(int ioctl_sock, char *prefix_name);
+void Config_free(struct rtapd_config *conf);
+
+
+#endif /* CONFIG_H */
Index: /src/router/rt2860apd/eapol_sm.c
===================================================================
--- /src/router/rt2860apd/eapol_sm.c	(revision 10789)
+++ /src/router/rt2860apd/eapol_sm.c	(revision 10789)
@@ -0,0 +1,643 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	eapol_sm.c
+
+	Revision History:
+	Who         When          What
+	--------    ----------    ----------------------------------------------
+	Jan, Lee    Dec --2003    modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/socket.h>
+
+#include "rt2860apd.h"
+#include "ieee802_1x.h"
+#include "eapol_sm.h"
+#include "eloop.h"
+
+/* TODO:
+ * implement state machines: Controlled Directions and Key Receive
+ */
+
+
+/* EAPOL state machines are described in IEEE Std 802.1X-2001, Chap. 8.5 */
+
+#define setPortAuthorized() \
+ieee802_1x_set_sta_authorized(sm->rtapd, sm->sta, 1)
+#define setPortUnauthorized() \
+ieee802_1x_set_sta_authorized(sm->rtapd, sm->sta, 0)
+
+/* procedures */
+#define txCannedFail(x) ieee802_1x_tx_canned_eap(sm->rtapd, sm->sta, (x), 0)
+#define txCannedSuccess(x) ieee802_1x_tx_canned_eap(sm->rtapd, sm->sta, (x), 1)
+/* TODO: IEEE 802.1aa/D4 replaces txReqId(x) with txInitialMsg(x); value of
+ * initialEAPMsg should be used to select which type of EAP packet is sent;
+ * Currently, hostapd only supports EAP Request/Identity, so this can be
+ * hardcoded. */
+#define txInitialMsg(x) ieee802_1x_request_identity(sm->rtapd, sm->sta, (x))
+#define txReq(x) ieee802_1x_tx_req(sm->rtapd, sm->sta, (x))
+#define sendRespToServer ieee802_1x_send_resp_to_server(sm->rtapd, sm->sta)
+/* TODO: check if abortAuth would be needed for something */
+#define abortAuth do { } while (0)
+#define txKey(x) ieee802_1x_tx_key(sm->rtapd, sm->sta, (x))
+
+/* Definitions for clarifying state machine implementation */
+#define SM_STATE(machine, state) \
+static void sm_ ## machine ## _ ## state ## _Enter(struct eapol_state_machine \
+*sm)
+
+#define SM_ENTRY(machine, _state, _data) \
+sm->_data.state = machine ## _ ## _state; \
+if (sm->rtapd->conf->debug >= HOSTAPD_DEBUG_MINIMAL) \
+	DBGPRINT(RT_DEBUG_ERROR,"IEEE 802.1X: " MACSTR " " #machine " entering state " #_state \
+		"\n", MAC2STR(sm->sta->addr));
+
+#define SM_ENTER(machine, state) sm_ ## machine ## _ ## state ## _Enter(sm)
+
+#define SM_STEP(machine) \
+static void sm_ ## machine ## _Step(struct eapol_state_machine *sm)
+
+#define SM_STEP_RUN(machine) sm_ ## machine ## _Step(sm)
+
+/* Port Timers state machine - implemented as a function that will be called
+ * once a second as a registered event loop timeout */
+
+static void eapol_port_timers_tick(void *eloop_ctx, void *timeout_ctx)
+{
+	struct eapol_state_machine *state = timeout_ctx;
+
+	if (state->aWhile > 0)
+		state->aWhile--;
+	if (state->quietWhile > 0)
+		state->quietWhile--;
+	if (state->reAuthWhen > 0)
+		state->reAuthWhen--;
+	if (state->txWhen > 0)
+		state->txWhen--;
+
+	eapol_sm_step(state);
+
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, eloop_ctx, state);
+}
+
+
+
+/* Authenticator PAE state machine */
+
+SM_STATE(AUTH_PAE, INITIALIZE)
+{
+	SM_ENTRY(AUTH_PAE, INITIALIZE, auth_pae);
+	sm->currentId = 1;
+	sm->auth_pae.portMode = Auto;
+}
+
+
+SM_STATE(AUTH_PAE, DISCONNECTED)
+{
+	int from_initialize = sm->auth_pae.state == AUTH_PAE_INITIALIZE;
+
+	if (sm->auth_pae.state == AUTH_PAE_CONNECTING &&
+	    sm->auth_pae.eapLogoff)
+		sm->auth_pae.authEapLogoffsWhileConnecting++;
+
+	SM_ENTRY(AUTH_PAE, DISCONNECTED, auth_pae);
+
+	sm->portStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->auth_pae.eapLogoff = FALSE;
+	sm->auth_pae.reAuthCount = 0;
+	/* IEEE 802.1X state machine uses txCannedFail() always in this state.
+	 * However, sending EAP packet with failure code seems to cause WinXP
+	 * Supplicant to deauthenticate, which will set portEnabled = FALSE and
+	 * state machines end back to INITIALIZE and then back here to send
+	 * canned failure, and so on.. Avoid this by not sending failure packet
+	 * when DISCONNECTED state is entered from INITIALIZE state. */
+ 	if (!from_initialize) {
+		txCannedFail(sm->currentId);
+		sm->currentId++;
+	}
+}
+
+
+SM_STATE(AUTH_PAE, CONNECTING)
+{
+	if (sm->auth_pae.state != AUTH_PAE_CONNECTING)
+		sm->auth_pae.authEntersConnecting++;
+
+	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATED) {
+		if (sm->reAuthenticate)
+			sm->auth_pae.authAuthReauthsWhileAuthenticated++;
+		if (sm->auth_pae.eapStart)
+			sm->auth_pae.authAuthEapStartsWhileAuthenticated++;
+		if (sm->auth_pae.eapLogoff)
+			sm->auth_pae.authAuthEapLogoffWhileAuthenticated++;
+	}
+
+	SM_ENTRY(AUTH_PAE, CONNECTING, auth_pae);
+
+	sm->auth_pae.eapStart = FALSE;
+	sm->reAuthenticate = FALSE;
+	sm->txWhen = sm->auth_pae.txPeriod;
+	sm->auth_pae.rxInitialRsp = FALSE;
+	txInitialMsg(sm->currentId);
+	sm->auth_pae.reAuthCount++;
+}
+
+
+SM_STATE(AUTH_PAE, HELD)
+{
+	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authFail)
+		sm->auth_pae.authAuthFailWhileAuthenticating++;
+
+	SM_ENTRY(AUTH_PAE, HELD, auth_pae);
+
+	sm->portStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->quietWhile = sm->auth_pae.quietPeriod;
+	sm->auth_pae.eapLogoff = FALSE;
+	sm->currentId++;
+
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATED)
+{
+	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING && sm->authSuccess)
+		sm->auth_pae.authAuthSuccessesWhileAuthenticating++;
+							
+	SM_ENTRY(AUTH_PAE, AUTHENTICATED, auth_pae);
+
+	sm->portStatus = Authorized;
+	setPortAuthorized();
+	sm->auth_pae.reAuthCount = 0;
+	sm->currentId++;
+}
+
+
+SM_STATE(AUTH_PAE, AUTHENTICATING)
+{
+	if (sm->auth_pae.state == AUTH_PAE_CONNECTING &&
+	    sm->auth_pae.rxInitialRsp)
+		sm->auth_pae.authEntersAuthenticating++;
+
+	SM_ENTRY(AUTH_PAE, AUTHENTICATING, auth_pae);
+
+	sm->authSuccess = FALSE;
+	sm->authFail = FALSE;
+	sm->authTimeout = FALSE;
+	sm->authStart = TRUE;
+}
+
+
+SM_STATE(AUTH_PAE, ABORTING)
+{
+	if (sm->auth_pae.state == AUTH_PAE_AUTHENTICATING) {
+		if (sm->authTimeout)
+			sm->auth_pae.authAuthTimeoutsWhileAuthenticating++;
+		if (sm->reAuthenticate)
+			sm->auth_pae.authAuthReauthsWhileAuthenticating++;
+		if (sm->auth_pae.eapStart)
+			sm->auth_pae.authAuthEapStartsWhileAuthenticating++;
+		if (sm->auth_pae.eapLogoff)
+			sm->auth_pae.authAuthEapLogoffWhileAuthenticating++;
+	}
+
+	SM_ENTRY(AUTH_PAE, ABORTING, auth_pae);
+
+	sm->authAbort = TRUE;
+	sm->currentId++;
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_AUTH)
+{
+	SM_ENTRY(AUTH_PAE, FORCE_AUTH, auth_pae);
+
+	sm->portStatus = Authorized;
+	setPortAuthorized();
+	sm->auth_pae.portMode = ForceAuthorized;
+	sm->auth_pae.eapStart = FALSE;
+	txCannedSuccess(sm->currentId);
+	sm->currentId++;
+}
+
+
+SM_STATE(AUTH_PAE, FORCE_UNAUTH)
+{
+	SM_ENTRY(AUTH_PAE, FORCE_UNAUTH, auth_pae);
+
+	sm->portStatus = Unauthorized;
+	setPortUnauthorized();
+	sm->auth_pae.portMode = ForceUnauthorized;
+	sm->auth_pae.eapStart = FALSE;
+	txCannedFail(sm->currentId);
+	sm->currentId++;
+}
+
+
+SM_STEP(AUTH_PAE)
+{
+	if ((sm->portControl == Auto &&
+	     sm->auth_pae.portMode != sm->portControl) ||
+	    sm->initialize || !sm->portEnabled)
+		SM_ENTER(AUTH_PAE, INITIALIZE);
+	else if (sm->portControl == ForceAuthorized &&
+		 sm->auth_pae.portMode != sm->portControl &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER(AUTH_PAE, FORCE_AUTH);
+	else if (sm->portControl == ForceUnauthorized &&
+		 sm->auth_pae.portMode != sm->portControl &&
+		 !(sm->initialize || !sm->portEnabled))
+		SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+	else {
+		switch (sm->auth_pae.state) {
+		case AUTH_PAE_INITIALIZE:
+			SM_ENTER(AUTH_PAE, DISCONNECTED);
+			break;
+		case AUTH_PAE_DISCONNECTED:
+			SM_ENTER(AUTH_PAE, CONNECTING);
+			break;
+		case AUTH_PAE_HELD:
+			if (sm->quietWhile == 0)
+				SM_ENTER(AUTH_PAE, CONNECTING);
+			break;
+		case AUTH_PAE_CONNECTING:
+			if (sm->auth_pae.eapLogoff ||
+			    sm->auth_pae.reAuthCount > sm->auth_pae.reAuthMax)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			else if (sm->auth_pae.rxInitialRsp &&
+				 sm->auth_pae.reAuthCount <=
+				 sm->auth_pae.reAuthMax)
+				SM_ENTER(AUTH_PAE, AUTHENTICATING);
+			else if ((sm->txWhen == 0 || sm->auth_pae.eapStart ||
+				  sm->reAuthenticate) &&
+				 sm->auth_pae.reAuthCount <=
+				 sm->auth_pae.reAuthMax)
+				SM_ENTER(AUTH_PAE, CONNECTING);
+			break;
+		case AUTH_PAE_AUTHENTICATED:
+			if (sm->auth_pae.eapStart || sm->reAuthenticate)
+				SM_ENTER(AUTH_PAE, CONNECTING);
+			else if (sm->auth_pae.eapLogoff || !sm->portValid)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			break;
+		case AUTH_PAE_AUTHENTICATING:
+			if (sm->authSuccess && sm->portValid)
+				SM_ENTER(AUTH_PAE, AUTHENTICATED);
+			else if (sm->authFail)
+				SM_ENTER(AUTH_PAE, HELD);
+			else if (sm->reAuthenticate || sm->auth_pae.eapStart ||
+				 sm->auth_pae.eapLogoff ||
+				 sm->authTimeout)
+				SM_ENTER(AUTH_PAE, ABORTING);
+			break;
+		case AUTH_PAE_ABORTING:
+			if (sm->auth_pae.eapLogoff && !sm->authAbort)
+				SM_ENTER(AUTH_PAE, DISCONNECTED);
+			else if (!sm->auth_pae.eapLogoff && !sm->authAbort)
+				SM_ENTER(AUTH_PAE, CONNECTING);
+			break;
+		case AUTH_PAE_FORCE_AUTH:
+			if (sm->auth_pae.eapStart)
+				SM_ENTER(AUTH_PAE, FORCE_AUTH);
+			break;
+		case AUTH_PAE_FORCE_UNAUTH:
+			if (sm->auth_pae.eapStart)
+				SM_ENTER(AUTH_PAE, FORCE_UNAUTH);
+			break;
+		}
+	}
+}
+
+
+
+/* Backend Authentication state machine */
+
+SM_STATE(BE_AUTH, INITIALIZE)
+{
+	SM_ENTRY(BE_AUTH, INITIALIZE, be_auth);
+
+	abortAuth;
+	sm->authAbort = FALSE;
+}
+
+
+SM_STATE(BE_AUTH, REQUEST)
+{
+	SM_ENTRY(BE_AUTH, REQUEST, be_auth);
+
+	sm->currentId = sm->be_auth.idFromServer;
+	txReq(sm->currentId);
+	sm->be_auth.backendOtherRequestsToSupplicant++;
+	sm->aWhile = sm->be_auth.suppTimeout;
+	sm->be_auth.reqCount++;
+}
+
+
+SM_STATE(BE_AUTH, RESPONSE)
+{
+	SM_ENTRY(BE_AUTH, RESPONSE, be_auth);
+
+	sm->be_auth.aReq = sm->be_auth.aSuccess = FALSE;
+	sm->authTimeout = FALSE;
+	sm->be_auth.rxResp = sm->be_auth.aFail = FALSE;
+
+	sm->aWhile = sm->be_auth.serverTimeout;
+	sm->be_auth.reqCount = 0;
+	sendRespToServer;
+	sm->be_auth.backendResponses++;
+}
+
+
+SM_STATE(BE_AUTH, SUCCESS)
+{
+	SM_ENTRY(BE_AUTH, SUCCESS, be_auth);
+
+	sm->currentId = sm->be_auth.idFromServer;
+	txReq(sm->currentId);
+	sm->authSuccess = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, FAIL)
+{
+	SM_ENTRY(BE_AUTH, FAIL, be_auth);
+
+	sm->currentId = sm->be_auth.idFromServer;
+	txReq(sm->currentId);
+	sm->authFail = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, TIMEOUT)
+{
+	SM_ENTRY(BE_AUTH, TIMEOUT, be_auth);
+
+	if (sm->portStatus == Unauthorized)
+		txCannedFail(sm->currentId);
+	sm->authTimeout = TRUE;
+}
+
+
+SM_STATE(BE_AUTH, IDLE)
+{
+	SM_ENTRY(BE_AUTH, IDLE, be_auth);
+
+	sm->authStart = FALSE;
+	sm->be_auth.reqCount = 0;
+}
+
+
+SM_STEP(BE_AUTH)
+{
+	if (sm->portControl != Auto || sm->initialize || sm->authAbort) {
+		SM_ENTER(BE_AUTH, INITIALIZE);
+		return;
+	}
+
+	switch (sm->be_auth.state) {
+	case BE_AUTH_INITIALIZE:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_REQUEST:
+		if (sm->aWhile == 0 &&
+		    sm->be_auth.reqCount != sm->be_auth.maxReq)
+			SM_ENTER(BE_AUTH, REQUEST);
+		else if (sm->be_auth.rxResp)
+			SM_ENTER(BE_AUTH, RESPONSE);
+		else if (sm->aWhile == 0 &&
+			 sm->be_auth.reqCount >= sm->be_auth.maxReq)
+			SM_ENTER(BE_AUTH, TIMEOUT);
+		break;
+	case BE_AUTH_RESPONSE:
+		if (sm->be_auth.aReq) {
+			sm->be_auth.backendAccessChallenges++;
+			SM_ENTER(BE_AUTH, REQUEST);
+		} else if (sm->aWhile == 0)
+			SM_ENTER(BE_AUTH, TIMEOUT);
+		else if (sm->be_auth.aFail) {
+			sm->be_auth.backendAuthFails++;
+			SM_ENTER(BE_AUTH, FAIL);
+		} else if (sm->be_auth.aSuccess) {
+			sm->be_auth.backendAuthSuccesses++;
+			SM_ENTER(BE_AUTH, SUCCESS);
+		}
+		break;
+	case BE_AUTH_SUCCESS:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_FAIL:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_TIMEOUT:
+		SM_ENTER(BE_AUTH, IDLE);
+		break;
+	case BE_AUTH_IDLE:
+		if (sm->authStart)
+			SM_ENTER(BE_AUTH, RESPONSE);
+		break;
+	}
+}
+
+
+
+/* Reauthentication Timer state machine */
+
+SM_STATE(REAUTH_TIMER, INITIALIZE)
+{
+	SM_ENTRY(REAUTH_TIMER, INITIALIZE, reauth_timer);
+ 
+	sm->reAuthWhen = sm->reauth_timer.reAuthPeriod;
+}
+
+
+SM_STATE(REAUTH_TIMER, REAUTHENTICATE)
+{
+	SM_ENTRY(REAUTH_TIMER, REAUTHENTICATE, reauth_timer);
+	sm->reAuthenticate = TRUE;
+}
+
+
+SM_STEP(REAUTH_TIMER)
+{
+	if (sm->portControl != Auto || sm->initialize ||
+	    sm->portStatus == Unauthorized ||
+	    !sm->reauth_timer.reAuthEnabled) {
+		SM_ENTER(REAUTH_TIMER, INITIALIZE);
+		return;
+	}
+
+	switch (sm->reauth_timer.state) {
+	case REAUTH_TIMER_INITIALIZE:
+		if ((sm->reAuthWhen == 0)  )
+			SM_ENTER(REAUTH_TIMER, REAUTHENTICATE);
+		break;
+	case REAUTH_TIMER_REAUTHENTICATE:
+		SM_ENTER(REAUTH_TIMER, INITIALIZE);
+		break;
+	}
+}
+
+/* Authenticator Key Transmit state machine */
+SM_STATE(AUTH_KEY_TX, NO_KEY_TRANSMIT)
+{
+	DBGPRINT(RT_DEBUG_INFO,"AUTH_KEY_TX, NO_KEY_TRANSMIT\n");
+	SM_ENTRY(AUTH_KEY_TX, NO_KEY_TRANSMIT, auth_key_tx);
+}
+
+SM_STATE(AUTH_KEY_TX, KEY_TRANSMIT)
+{
+	DBGPRINT(RT_DEBUG_INFO,"(AUTH_KEY_TX, KEY_TRANSMIT)\n");
+	SM_ENTRY(AUTH_KEY_TX, KEY_TRANSMIT, auth_key_tx);
+
+	txKey(sm->currentId);
+	sm->keyAvailable = FALSE;
+}
+
+SM_STEP(AUTH_KEY_TX)
+{
+	if (sm->initialize || sm->portControl != Auto) {
+		SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+		return;
+	}
+
+	switch (sm->auth_key_tx.state) {
+	case AUTH_KEY_TX_NO_KEY_TRANSMIT:
+		/* NOTE! IEEE 802.1aa/D4 does has this requirement as
+		 * keyTxEnabled && keyAvailable && authSuccess. However, this
+		 * seems to be conflicting with BE_AUTH sm, since authSuccess
+		 * is now set only if keyTxEnabled is true and there are no
+		 * keys to be sent.. I think the purpose is to sent the keys
+		 * first and report authSuccess only after this and adding OR
+		 * be_auth.aSuccess does this. */
+		if (sm->keyTxEnabled && sm->keyAvailable &&
+		    (sm->authSuccess /* || sm->be_auth.aSuccess */))
+			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+		break;
+	case AUTH_KEY_TX_KEY_TRANSMIT:
+		if (!sm->keyTxEnabled || sm->authFail ||
+		    sm->auth_pae.eapLogoff)
+			SM_ENTER(AUTH_KEY_TX, NO_KEY_TRANSMIT);
+		else if (sm->keyAvailable)
+			SM_ENTER(AUTH_KEY_TX, KEY_TRANSMIT);
+		break;
+	}
+}
+
+struct eapol_state_machine *
+eapol_sm_alloc(rtapd *rtapd, struct sta_info *sta)
+{
+	struct eapol_state_machine *sm;
+	sm = (struct eapol_state_machine *) malloc(sizeof(*sm));
+	if (sm == NULL) {
+		DBGPRINT(RT_DEBUG_ERROR,"IEEE 802.1X port state allocation failed\n");
+		return NULL;
+	}
+	memset(sm, 0, sizeof(*sm));
+
+	sm->rtapd = rtapd;
+	sm->sta = sta;
+
+	/* Set default values for state machine constants */
+	sm->auth_pae.state = AUTH_PAE_INITIALIZE;
+	sm->auth_pae.quietPeriod = AUTH_PAE_DEFAULT_quietPeriod;
+	sm->auth_pae.initialEAPMsg = AUTH_PAE_DEFAULT_initialEAPMsg;
+	sm->auth_pae.reAuthMax = AUTH_PAE_DEFAULT_reAuthMax;
+	sm->auth_pae.txPeriod = AUTH_PAE_DEFAULT_txPeriod;
+
+	sm->be_auth.state = BE_AUTH_INITIALIZE;
+	sm->be_auth.suppTimeout = BE_AUTH_DEFAULT_suppTimeout;
+	sm->be_auth.serverTimeout = BE_AUTH_DEFAULT_serverTimeout;
+	sm->be_auth.maxReq = BE_AUTH_DEFAULT_maxReq;
+
+	sm->reauth_timer.state = REAUTH_TIMER_INITIALIZE;
+
+	sm->reauth_timer.reAuthEnabled = REAUTH_TIMER_DEFAULT_reAuthEnabled;
+	if (rtapd->conf->session_timeout_set == 1)
+	{
+		sm->reauth_timer.reAuthPeriod = rtapd->conf->session_timeout_interval;
+		sm->reauth_timer.reAuthEnabled = TRUE;
+		DBGPRINT(RT_DEBUG_TRACE,"Set This Session Timeout Interval  %d Seconds. \n",sm->reauth_timer.reAuthPeriod );
+	}
+	else 
+	{
+		/* didn't set reauth , or  set to not reauth */
+		sm->reauth_timer.reAuthPeriod = REAUTH_TIMER_DEFAULT_reAuthPeriod;
+	}
+
+	sm->portEnabled = FALSE;
+	sm->portControl = Auto;
+	sm->currentId = 1;
+	/* IEEE 802.1aa/D4 */
+	sm->keyAvailable = FALSE;
+	sm->keyTxEnabled =TRUE ;
+	sm->portValid = TRUE; /* TODO: should this be FALSE sometimes? */
+
+	eapol_sm_initialize(sm);
+
+	return sm;
+}
+
+
+void eapol_sm_free(struct eapol_state_machine *sm)
+{
+	if (sm == NULL)
+		return;
+
+	eloop_cancel_timeout(eapol_port_timers_tick, sm->rtapd, sm);
+
+	free(sm);
+}
+
+
+void eapol_sm_step(struct eapol_state_machine *sm)
+{
+	int prev_auth_pae, prev_be_auth, prev_reauth_timer, prev_auth_key_tx;
+
+	/* FIX: could re-run eapol_sm_step from registered timeout (after
+	 * 0 sec) to make sure that other possible timeouts/events are
+	 * processed */
+
+	do {
+		prev_auth_pae = sm->auth_pae.state;
+		prev_be_auth = sm->be_auth.state;
+		prev_reauth_timer = sm->reauth_timer.state;
+		prev_auth_key_tx = sm->auth_key_tx.state;
+
+		SM_STEP_RUN(AUTH_PAE);
+		SM_STEP_RUN(BE_AUTH);
+		SM_STEP_RUN(REAUTH_TIMER);
+		SM_STEP_RUN(AUTH_KEY_TX);
+	} while (prev_auth_pae != sm->auth_pae.state ||
+		 prev_be_auth != sm->be_auth.state ||
+		 prev_reauth_timer != sm->reauth_timer.state ||
+		 prev_auth_key_tx != sm->auth_key_tx.state);
+}
+
+
+void eapol_sm_initialize(struct eapol_state_machine *sm)
+{
+	/* Initialize the state machines by asserting initialize and then
+	 * deasserting it after one step */
+	sm->initialize = TRUE;
+	eapol_sm_step(sm);
+	sm->initialize = FALSE;
+	eapol_sm_step(sm);
+
+	/* Start one second tick for port timers state machine */
+	eloop_cancel_timeout(eapol_port_timers_tick, sm->rtapd, sm);
+	eloop_register_timeout(1, 0, eapol_port_timers_tick, sm->rtapd, sm);
+}
+
Index: /src/router/rt2860apd/eapol_sm.h
===================================================================
--- /src/router/rt2860apd/eapol_sm.h	(revision 10789)
+++ /src/router/rt2860apd/eapol_sm.h	(revision 10789)
@@ -0,0 +1,146 @@
+#ifndef EAPOL_SM_H
+#define EAPOL_SM_H
+
+/* IEEE Std 802.1X-2001, 8.5 */
+
+typedef enum { ForceUnauthorized, ForceAuthorized, Auto } PortTypes;
+typedef enum { Unauthorized, Authorized } PortState;
+typedef enum { EAPRequestIdentity } EAPMsgType;
+typedef unsigned int Counter;
+
+
+/* Authenticator PAE state machine */
+struct eapol_auth_pae_sm {
+	/* variables */
+	Boolean eapLogoff;
+	Boolean eapStart;
+	PortTypes portMode;
+	unsigned int reAuthCount;
+	Boolean rxInitialRsp;
+
+	/* constants */
+	unsigned int quietPeriod; /* default 60; 0..65535 */
+#define AUTH_PAE_DEFAULT_quietPeriod 60
+	EAPMsgType initialEAPMsg; /* IEEE 802.1aa/D4 */
+#define AUTH_PAE_DEFAULT_initialEAPMsg EAPRequestIdentity
+	unsigned int reAuthMax; /* default 2 */
+#define AUTH_PAE_DEFAULT_reAuthMax 2
+	unsigned int txPeriod; /* default 30; 1..65535 */
+#define AUTH_PAE_DEFAULT_txPeriod 30
+
+	/* counters */
+	Counter authEntersConnecting;
+	Counter authEapLogoffsWhileConnecting;
+	Counter authEntersAuthenticating;
+	Counter authAuthSuccessesWhileAuthenticating;
+	Counter authAuthTimeoutsWhileAuthenticating;
+	Counter authAuthFailWhileAuthenticating;
+	Counter authAuthReauthsWhileAuthenticating;
+	Counter authAuthEapStartsWhileAuthenticating;
+	Counter authAuthEapLogoffWhileAuthenticating;
+	Counter authAuthReauthsWhileAuthenticated;
+	Counter authAuthEapStartsWhileAuthenticated;
+	Counter authAuthEapLogoffWhileAuthenticated;
+
+	enum { AUTH_PAE_INITIALIZE, AUTH_PAE_DISCONNECTED, AUTH_PAE_CONNECTING,
+	       AUTH_PAE_AUTHENTICATING, AUTH_PAE_AUTHENTICATED,
+	       AUTH_PAE_ABORTING, AUTH_PAE_HELD, AUTH_PAE_FORCE_AUTH,
+	       AUTH_PAE_FORCE_UNAUTH } state;
+};
+
+
+/* Backend Authentication state machine */
+struct eapol_backend_auth_sm {
+	/* variables */
+	unsigned int reqCount;
+	Boolean rxResp;
+	Boolean aSuccess;
+	Boolean aFail;
+	Boolean aReq;
+	u8 idFromServer;
+
+	/* constants */
+	unsigned int suppTimeout; /* default 30; 1..X */
+#define BE_AUTH_DEFAULT_suppTimeout 30
+	unsigned int serverTimeout; /* default 30; 1..X */
+#define BE_AUTH_DEFAULT_serverTimeout 30
+	unsigned int maxReq; /* default 2; 1..10 */
+#define BE_AUTH_DEFAULT_maxReq 2
+
+	/* counters */
+	Counter backendResponses;
+	Counter backendAccessChallenges;
+	Counter backendOtherRequestsToSupplicant;
+	Counter backendNonNakResponsesFromSupplicant;
+	Counter backendAuthSuccesses;
+	Counter backendAuthFails;
+
+	enum { BE_AUTH_REQUEST, BE_AUTH_RESPONSE, BE_AUTH_SUCCESS,
+	       BE_AUTH_FAIL, BE_AUTH_TIMEOUT, BE_AUTH_IDLE, BE_AUTH_INITIALIZE
+	} state;
+};
+
+
+/* Reauthentication Timer state machine */
+struct eapol_reauth_timer_sm {
+	/* constants */
+	unsigned int reAuthPeriod; /* default 3600 s */
+	Boolean reAuthEnabled;
+
+	enum { REAUTH_TIMER_INITIALIZE, REAUTH_TIMER_REAUTHENTICATE } state;
+};
+
+
+/* Authenticator Key Transmit state machine */
+struct eapol_auth_key_tx {
+	enum { AUTH_KEY_TX_NO_KEY_TRANSMIT, AUTH_KEY_TX_KEY_TRANSMIT } state;
+};
+
+
+struct eapol_state_machine {
+	/* timers */
+	int aWhile;
+	int quietWhile;
+	int reAuthWhen;
+	int txWhen;
+
+	/* global variables */
+	Boolean authAbort;
+	Boolean authFail;
+	Boolean authStart;
+	Boolean authTimeout;
+	Boolean authSuccess;
+	u8 currentId;
+	Boolean initialize;
+	Boolean keyAvailable; /* 802.1aa; was in Auth Key Transmit sm in .1x */
+	Boolean keyTxEnabled; /* 802.1aa; was in Auth Key Transmit sm in .1x
+			       * stace machines do not change this */
+	PortTypes portControl;
+	Boolean portEnabled;
+	PortState portStatus;
+	Boolean portValid; /* 802.1aa */
+	Boolean reAuthenticate;
+
+
+	/* Port Timers state machine */
+	/* 'Boolean tick' implicitly handled as registered timeout */
+
+	struct eapol_auth_pae_sm auth_pae;
+	struct eapol_backend_auth_sm be_auth;
+	struct eapol_reauth_timer_sm reauth_timer;
+	struct eapol_auth_key_tx auth_key_tx;
+
+	/* Somewhat nasty pointers to global hostapd and STA data to avoid
+	 * passing these to every function */
+	rtapd *rtapd;
+	struct sta_info *sta;
+};
+
+
+struct eapol_state_machine *eapol_sm_alloc(rtapd *rtapd,
+					   struct sta_info *sta);
+void eapol_sm_free(struct eapol_state_machine *sm);
+void eapol_sm_step(struct eapol_state_machine *sm);
+void eapol_sm_initialize(struct eapol_state_machine *sm);
+
+#endif /* EAPOL_SM_H */
Index: /src/router/rt2860apd/eloop.c
===================================================================
--- /src/router/rt2860apd/eloop.c	(revision 10789)
+++ /src/router/rt2860apd/eloop.c	(revision 10789)
@@ -0,0 +1,297 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	eloop.c
+
+	Revision History:
+	Who         When          What
+	--------    ----------    ----------------------------------------------
+	Jan, Lee    Dec --2003    modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include <signal.h>
+
+#include "eloop.h"
+
+
+struct eloop_sock {
+	int sock;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(int sock, void *eloop_ctx, void *sock_ctx);
+};
+
+struct eloop_timeout {
+	struct timeval time;
+	void *eloop_data;
+	void *user_data;
+	void (*handler)(void *eloop_ctx, void *sock_ctx);
+	struct eloop_timeout *next;
+};
+
+struct eloop_signal {
+	int sig;
+	void *user_data;
+	void (*handler)(int sig, void *eloop_ctx, void *signal_ctx);
+};
+
+struct eloop_data {
+	void *user_data;
+
+	int max_sock, reader_count;
+	struct eloop_sock *readers;
+
+	struct eloop_timeout *timeout;
+
+	int signal_count;
+	struct eloop_signal *signals;
+
+	int terminate;
+    int reload;
+};
+
+static struct eloop_data eloop;
+
+
+void eloop_init(void *user_data)
+{
+	memset(&eloop, 0, sizeof(eloop));
+	eloop.user_data = user_data;
+}
+
+
+int eloop_register_read_sock(int sock, void (*handler)(int sock, void *eloop_ctx, void *sock_ctx),
+                             void *eloop_data, void *user_data)
+{
+	struct eloop_sock *tmp;
+
+	tmp = (struct eloop_sock *)	realloc(eloop.readers, (eloop.reader_count + 1) * sizeof(struct eloop_sock));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.reader_count].sock = sock;
+	tmp[eloop.reader_count].eloop_data = eloop_data;
+	tmp[eloop.reader_count].user_data = user_data;
+	tmp[eloop.reader_count].handler = handler;
+	eloop.reader_count++;
+	eloop.readers = tmp;
+
+	if (sock > eloop.max_sock)
+		eloop.max_sock = sock;
+
+	return 0;
+}
+
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *tmp, *prev;
+
+	timeout = (struct eloop_timeout *) malloc(sizeof(*timeout));
+	if (timeout == NULL)
+		return -1;
+
+	gettimeofday(&timeout->time, NULL);
+	timeout->time.tv_sec += secs;
+	timeout->time.tv_usec += usecs;
+
+	while (timeout->time.tv_usec >= 1000000)
+    {
+		timeout->time.tv_sec++;
+		timeout->time.tv_usec -= 1000000;
+	}
+	timeout->eloop_data = eloop_data;
+	timeout->user_data = user_data;
+	timeout->handler = handler;
+	timeout->next = NULL;
+
+	if (eloop.timeout == NULL) {
+		eloop.timeout = timeout;
+		return 0;
+	}
+
+	prev = NULL;
+	tmp = eloop.timeout;
+	while (tmp != NULL)
+    {
+		if (timercmp(&timeout->time, &tmp->time, <))
+			break;
+		prev = tmp;
+		tmp = tmp->next;
+	}
+
+	if (prev == NULL)
+    {
+		timeout->next = eloop.timeout;
+		eloop.timeout = timeout;
+	}
+    else
+    {
+		timeout->next = prev->next;
+		prev->next = timeout;
+	}
+
+	return 0;
+}
+
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+			 void *eloop_data, void *user_data)
+{
+	struct eloop_timeout *timeout, *prev, *next;
+	int removed = 0;
+
+	prev = NULL;
+	timeout = eloop.timeout;
+	while (timeout != NULL)
+    {
+		next = timeout->next;
+
+		if (timeout->handler == handler && (timeout->eloop_data == eloop_data || eloop_data == ELOOP_ALL_CTX) 
+            && (timeout->user_data == user_data || user_data == ELOOP_ALL_CTX))
+        {
+			if (prev == NULL)
+				eloop.timeout = next;
+			else
+				prev->next = next;
+			free(timeout);
+			removed++;
+		} else
+			prev = timeout;
+
+		timeout = next;
+	}
+
+	return removed;
+}
+
+static void eloop_handle_signal(int sig)
+{
+	int i;
+	for (i = 0; i < eloop.signal_count; i++)
+    {
+		if (eloop.signals[i].sig == sig)
+        {
+			eloop.signals[i].handler(eloop.signals[i].sig, eloop.user_data, eloop.signals[i].user_data);
+			break;
+		}
+	}
+}
+
+int eloop_register_signal(int sig, void (*handler)(int sig, void *eloop_ctx, void *signal_ctx), void *user_data)
+{
+	struct eloop_signal *tmp;
+
+	tmp = (struct eloop_signal *) realloc(eloop.signals, (eloop.signal_count + 1) *	sizeof(struct eloop_signal));
+	if (tmp == NULL)
+		return -1;
+
+	tmp[eloop.signal_count].sig = sig;
+	tmp[eloop.signal_count].user_data = user_data;
+	tmp[eloop.signal_count].handler = handler;
+	eloop.signal_count++;
+	eloop.signals = tmp;
+	signal(sig, eloop_handle_signal);
+
+	return 0;
+}
+
+void eloop_run(void)
+{
+	fd_set rfds;
+	int i, res;
+	struct timeval tv, now;
+
+	while (!eloop.terminate && (eloop.timeout || eloop.reader_count > 0))
+    {
+		if (eloop.timeout)
+        {
+            gettimeofday(&now, NULL);
+			if (timercmp(&now, &eloop.timeout->time, >=))
+				tv.tv_sec = tv.tv_usec = 0;
+			else
+				timersub(&eloop.timeout->time, &now, &tv);
+		}
+
+		FD_ZERO(&rfds);
+		for (i = 0; i < eloop.reader_count; i++)
+			FD_SET(eloop.readers[i].sock, &rfds);
+		res = select(eloop.max_sock + 1, &rfds, NULL, NULL,
+			     eloop.timeout ? &tv : NULL);
+		if (res < 0 && errno != EINTR)
+        {
+			perror("select");
+			return ;
+		}
+
+		/* check if some registered timeouts have occurred */
+		if (eloop.timeout)
+        {
+			struct eloop_timeout *tmp;
+
+			gettimeofday(&now, NULL);
+			if (timercmp(&now, &eloop.timeout->time, >=))
+            {
+				tmp = eloop.timeout;
+				eloop.timeout = eloop.timeout->next;
+				tmp->handler(tmp->eloop_data, tmp->user_data);
+				free(tmp);
+			}
+
+		}  
+        
+		if (res <= 0)
+			continue;
+
+		for (i = 0; i < eloop.reader_count; i++)
+        {
+			if (FD_ISSET(eloop.readers[i].sock, &rfds))
+            {
+				eloop.readers[i].handler(eloop.readers[i].sock,	eloop.readers[i].eloop_data, eloop.readers[i].user_data);
+			}
+		}
+	}
+}
+
+void eloop_terminate(void)
+{
+	eloop.terminate = 1;
+}
+
+void eloop_reload(void)
+{
+	eloop.reload = 1;
+}
+
+void eloop_destroy(void)
+{
+	struct eloop_timeout *timeout, *prev;
+
+	timeout = eloop.timeout;
+	while (timeout != NULL)
+    {
+		prev = timeout;
+		timeout = timeout->next;
+		free(prev);
+	}
+	free(eloop.readers);
+	free(eloop.signals);
+}
+
+int eloop_terminated(void)
+{
+	return eloop.terminate;
+}
Index: /src/router/rt2860apd/eloop.h
===================================================================
--- /src/router/rt2860apd/eloop.h	(revision 10789)
+++ /src/router/rt2860apd/eloop.h	(revision 10789)
@@ -0,0 +1,53 @@
+#ifndef ELOOP_H
+#define ELOOP_H
+
+/* Magic number for eloop_cancel_timeout() */
+#define ELOOP_ALL_CTX (void *) -1
+
+/* Initialize global event loop data - must be called before any other eloop_*
+ * function. user_data is a pointer to global data structure and will be passed
+ * as eloop_ctx to signal handlers. */
+void eloop_init(void *user_data);
+
+/* Register handler for read event */
+int eloop_register_read_sock(int sock,
+			     void (*handler)(int sock, void *eloop_ctx,
+					     void *sock_ctx),
+			     void *eloop_data, void *user_data);
+
+/* Register timeout */
+int eloop_register_timeout(unsigned int secs, unsigned int usecs,
+			   void (*handler)(void *eloop_ctx, void *timeout_ctx),
+			   void *eloop_data, void *user_data);
+
+/* Cancel timeouts matching <handler,eloop_data,user_data>.
+ * ELOOP_ALL_CTX can be used as a wildcard for cancelling all timeouts
+ * regardless of eloop_data/user_data. */
+int eloop_cancel_timeout(void (*handler)(void *eloop_ctx, void *sock_ctx),
+			 void *eloop_data, void *user_data);
+
+/* Register handler for signal.
+ * Note: signals are 'global' events and there is no local eloop_data pointer
+ * like with other handlers. The (global) pointer given to eloop_init() will be
+ * used as eloop_ctx for signal handlers. */
+int eloop_register_signal(int sock,
+			  void (*handler)(int sig, void *eloop_ctx,
+					  void *signal_ctx),
+			  void *user_data);
+
+/* Start event loop and continue running as long as there are any registered
+ * event handlers. */
+void eloop_run(void);
+
+/* Terminate event loop even if there are registered events. */
+void eloop_terminate(void);
+void eloop_reload(void);
+
+/* Free any reserved resources. After calling eloop_destoy(), other eloop_*
+ * functions must not be called before re-running eloop_init(). */
+void eloop_destroy(void);
+
+/* Check whether event loop has been terminated. */
+int eloop_terminated(void);
+
+#endif /* ELOOP_H */
Index: /src/router/rt2860apd/ieee802_1x.c
===================================================================
--- /src/router/rt2860apd/ieee802_1x.c	(revision 10789)
+++ /src/router/rt2860apd/ieee802_1x.c	(revision 10789)
@@ -0,0 +1,926 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	ieee802_1x.c
+
+	Revision History:
+	Who 		When		  What
+	--------	----------	  ----------------------------------------------
+	Jan, Lee	Dec --2003	  modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+
+#include <linux/if.h>			/* for IFNAMSIZ and co... */
+#include <linux/wireless.h>
+
+#include "rt2860apd.h"
+#include "ieee802_1x.h"
+#include "radius.h"
+#include "radius_client.h"
+#include "eapol_sm.h"
+#include "md5.h"
+#include "eloop.h"
+#include "sta_info.h"
+
+static void ieee802_1x_send(rtapd *rtapd, struct sta_info *sta, u8 type, u8 *data, size_t datalen)
+{
+	char *buf;
+	struct ieee8023_hdr *hdr3;
+	struct ieee802_1x_hdr *xhdr;
+	size_t len;
+	u8 *pos;
+		   
+	len = sizeof(*hdr3) + 2+ sizeof(*xhdr) +datalen;
+	buf = (char *) malloc(len);
+	if (buf == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"malloc() failed for ieee802_1x_send(len=%d)\n", len);
+		return;
+	}
+	DBGPRINT(RT_DEBUG_TRACE,"Send to Sta(%s%d) with Identifier %d\n", rtapd->prefix_wlan_name, sta->ApIdx,*(data+1));
+	memset(buf, 0, len);
+	hdr3 = (struct ieee8023_hdr *) buf;
+	memcpy(hdr3->dAddr, sta->addr, ETH_ALEN);
+	memcpy(hdr3->sAddr, rtapd->own_addr[sta->ApIdx], ETH_ALEN);
+
+	if (sta->ethertype == ETH_P_PRE_AUTH)
+		(hdr3->eth_type) = htons(ETH_P_PRE_AUTH);
+	else
+		(hdr3->eth_type) = htons(ETH_P_PAE);
+
+	pos = (u8 *) (hdr3 + 1);
+	xhdr = (struct ieee802_1x_hdr *) pos;
+	if (sta->ethertype == ETH_P_PRE_AUTH)
+		xhdr->version = EAPOL_VERSION_2;
+	else
+		xhdr->version = EAPOL_VERSION;
+	xhdr->type = type;
+	xhdr->length = htons(datalen);
+
+	if (datalen > 0 && data != NULL)
+		memcpy(pos + LENGTH_8021X_HDR, data, datalen);
+
+	//If (ethertype==ETH_P_PRE_AUTH), this means the packet is to or from ehternet socket(WPA2, pre-auth)
+	if (sta->ethertype == ETH_P_PRE_AUTH)
+	{
+		if (send(rtapd->eth_sock, buf, len, 0) < 0)
+			perror("send[WPA2 pre-auth]");
+		DBGPRINT(RT_DEBUG_INFO,"ieee802_1x_send::WPA2, pre-auth, len=%d\n", len);
+	}
+	else
+	{
+        if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_RADIUS_DATA, buf, len, rtapd->prefix_wlan_name, sta->ApIdx, 0))
+        DBGPRINT(RT_DEBUG_ERROR,"ioctl failed for ieee802_1x_send(len=%d)\n", len);
+	}
+
+	free(buf);
+}
+
+void ieee802_1x_set_sta_authorized(rtapd *rtapd, struct sta_info *sta, int authorized)
+{
+	switch(authorized)
+	{
+		case 0:
+			DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized FAILED \n");
+//			  Ap_free_sta(rtapd, sta);
+			break;
+
+		case 1:
+			DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_Set_Sta_Authorized SUCCESSED  \n"); 		   
+			
+			// This connection completed without transmitting EAPoL-Key
+			// Notify driver to set-up pairwise key based on its shared key
+			if( sta->eapol_sm->authSuccess && sta->eapol_key_sign_len == 0 && sta->eapol_key_crypt_len == 0 )
+			{
+				UCHAR	MacAddr[MAC_ADDR_LEN];
+				
+				memcpy(MacAddr, sta->addr, MAC_ADDR_LEN);
+				if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_STATIC_WEP_COPY, (char *)&MacAddr, sizeof(MacAddr), rtapd->prefix_wlan_name, sta->ApIdx, 0))
+				{				   
+                	DBGPRINT(RT_DEBUG_ERROR,"Failed to RTPRIV_IOCTL_STATIC_WEP_COPY\n");
+                	return;
+				}   
+	    	}
+			break;	  
+	}
+}
+
+void ieee802_1x_request_identity(rtapd *rtapd, struct sta_info *sta, u8 id)
+{
+	u8 *buf;
+	struct eap_hdr *eap;
+	int tlen;
+	u8 *pos;
+
+	ieee802_1x_new_auth_session(rtapd, sta);
+
+	tlen = sizeof(*eap) + 1 ;
+
+	buf = (u8 *) malloc(tlen);
+	if (buf == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "Could not allocate memory for identity request\n");
+		return;
+	}
+
+	memset(buf, 0, tlen);
+
+	eap = (struct eap_hdr *) buf;
+	eap->code = EAP_CODE_REQUEST;
+	eap->identifier = id;
+	eap->length = htons(tlen);
+	pos = (u8 *) (eap + 1);
+	*pos++ = EAP_TYPE_IDENTITY;
+
+	DBGPRINT(RT_DEBUG_INFO, "IEEE802_1X_Request_Identity %d bytes: \n",tlen);
+	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, buf, tlen);
+	free(buf);
+}
+
+void ieee802_1x_tx_canned_eap(rtapd *rtapd, struct sta_info *sta, u8 id, int success)
+{
+	struct eap_hdr eap;
+
+	memset(&eap, 0, sizeof(eap));
+
+	eap.code = success ? EAP_CODE_SUCCESS : EAP_CODE_FAILURE;
+	eap.identifier = id;
+	eap.length = htons(sizeof(eap));
+	DBGPRINT(RT_DEBUG_TRACE,"ieee802_1x_tx_canned_eap : Send to Sta with Identifier %d\n",id);
+
+	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET, (u8 *) &eap, sizeof(eap));
+}
+
+void ieee802_1x_tx_req(rtapd *rtapd, struct sta_info *sta, u8 id)
+{
+	struct eap_hdr *eap;
+
+	if (sta->last_eap_radius == NULL)
+	{
+		DBGPRINT(RT_DEBUG_WARN, "TxReq called for station " MACSTR ", but there "
+			   "is no EAP request from the authentication server\n", MAC2STR(sta->addr));
+		return;
+	}
+
+	eap = (struct eap_hdr *) sta->last_eap_radius;
+	if (eap->identifier != id)
+	{
+		DBGPRINT(RT_DEBUG_WARN,"IEEE 802.1X: TxReq(%d) - changing id from %d\n", id, eap->identifier);
+		eap->identifier = id;
+	}
+
+	ieee802_1x_send(rtapd, sta, IEEE802_1X_TYPE_EAP_PACKET,	sta->last_eap_radius, sta->last_eap_radius_len);
+}
+
+static void ieee802_1x_tx_key_one(rtapd *hapd, struct sta_info *sta,
+				  int index, int broadcast,
+				  u8 *key_data, size_t key_len)
+{
+	u8 *buf, *ekey;
+	struct ieee802_1x_hdr *hdr;
+	struct ieee802_1x_eapol_key *key;
+	struct timeval now;
+	size_t len, ekey_len;
+	u32 ntp_hi, ntp_lo, sec, usec;
+
+	len = sizeof(*key) + key_len;
+	buf = malloc(sizeof(*hdr) + len);
+	if (buf == NULL)
+		return;
+
+	memset(buf, 0, sizeof(*hdr) + len);
+	hdr = (struct ieee802_1x_hdr *) buf;
+	key = (struct ieee802_1x_eapol_key *) (hdr + 1);
+	key->type = EAPOL_KEY_TYPE_RC4;
+	key->key_length = htons(key_len);
+
+	/* Set the NTP timestamp as the replay counter */
+	gettimeofday(&now, NULL);
+	sec = now.tv_sec;
+	usec = now.tv_usec;
+
+#define JAN_1970 0x83aa7e80UL /* seconds from 1900 to 1970 */
+	ntp_hi = htonl(sec + JAN_1970);
+	/* approximation of 2^32/1000000 * usec */
+	ntp_lo = htonl(4295 * usec - (usec >> 5) - (usec >> 9));
+
+	memcpy(&key->replay_counter[0], &ntp_hi, sizeof(u32));
+	memcpy(&key->replay_counter[4], &ntp_lo, sizeof(u32));
+	if (hostapd_get_rand(key->key_iv, sizeof(key->key_iv)))
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "Could not get random numbers\n");
+		free(buf);
+		return;
+	}
+
+	key->key_index = index | (broadcast ? 0 : BIT(7));
+//	if (hapd->conf->eapol_key_index_workaround) {
+		/* According to some information, WinXP Supplicant seems to
+		 * interrept bit7 as an indication whether the key is to be
+		 * activated, so make it possible to enable workaround that
+		 * sets this bit for all keys. */
+//		key->key_index |= BIT(7);
+//	}
+	DBGPRINT(RT_DEBUG_TRACE, "key_index= %d key_length= %d \n",index, key_len);
+
+	/* Key is encrypted using "Key-IV + sta->eapol_key_crypt" as the
+	 * RC4-key */
+	memcpy((u8 *) (key + 1), key_data, key_len);
+	ekey_len = sizeof(key->key_iv) + sta->eapol_key_crypt_len;
+	ekey = malloc(ekey_len);
+	if (ekey == NULL)
+	{
+		DBGPRINT(RT_DEBUG_TRACE,"Could not encrypt key\n");
+		free(buf);
+		return;
+	}
+	memcpy(ekey, key->key_iv, sizeof(key->key_iv));
+	memcpy(ekey + sizeof(key->key_iv), sta->eapol_key_crypt, sta->eapol_key_crypt_len);
+	rc4((u8 *) (key + 1), key_len, ekey, ekey_len);
+	free(ekey);
+
+	/* This header is needed here for HMAC-MD5, but it will be regenerated in ieee802_1x_send() */
+	hdr->version = EAPOL_VERSION;
+	hdr->type = IEEE802_1X_TYPE_EAPOL_KEY;
+	hdr->length = htons(len);
+	hmac_md5(sta->eapol_key_sign, sta->eapol_key_sign_len, buf, sizeof(*hdr) + len, key->key_signature);
+
+	ieee802_1x_send(hapd, sta, IEEE802_1X_TYPE_EAPOL_KEY, (u8 *) key, len);
+	free(buf);
+}
+
+void ieee802_1x_tx_key(rtapd *rtapd, struct sta_info *sta, u8 id)
+{
+	NDIS_802_11_KEY 	WepKey, *pWepKey;
+       char individual_wep_key[WEP8021X_KEY_LEN];
+	
+	if (!sta->eapol_key_sign || !sta->eapol_key_crypt)
+		return;
+
+	memset(&WepKey, 0, sizeof(NDIS_802_11_KEY));
+	pWepKey = &WepKey;
+
+	// prepare EAPoL-key for broadcast key and send to STA 
+	ieee802_1x_tx_key_one(rtapd, sta, rtapd->conf->DefaultKeyID[sta->ApIdx], 1, (u8*)rtapd->conf->IEEE8021X_ikey[sta->ApIdx], rtapd->conf->individual_wep_key_len[sta->ApIdx]);
+	
+	// use IOCTL cmd to add WEP key
+	WepKey.KeyIndex =  0x80000000 | (rtapd->conf->DefaultKeyID[sta->ApIdx]);
+	WepKey.KeyLength = rtapd->conf->individual_wep_key_len[sta->ApIdx];
+	memcpy(WepKey.KeyMaterial, rtapd->conf->IEEE8021X_ikey[sta->ApIdx], rtapd->conf->individual_wep_key_len[sta->ApIdx]);
+	memcpy(WepKey.addr, sta->addr, 6);
+
+	// WPA2(pre-auth)
+	if (sta->ethertype== ETH_P_PRE_AUTH)
+	{
+		if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_PMKID_CACHE, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, 0, 0))
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
+			return;
+		}
+	}
+	else
+	{
+		if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_WPA_KEY, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, sta->ApIdx, 0))
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
+			return;
+		}
+	}
+       
+    // Generate random unicast key and send to STA
+    hostapd_get_rand((u8*)individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);
+    ieee802_1x_tx_key_one(rtapd, sta, rtapd->conf->individual_wep_key_idx[sta->ApIdx], 0, (u8*)individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);
+
+	// use IOCTL cmd to add WEP key
+	WepKey.KeyIndex =  rtapd->conf->individual_wep_key_idx[sta->ApIdx];
+	WepKey.KeyLength = rtapd->conf->individual_wep_key_len[sta->ApIdx];
+	memcpy(WepKey.KeyMaterial, individual_wep_key, rtapd->conf->individual_wep_key_len[sta->ApIdx]);
+	memcpy(WepKey.addr, sta->addr, 6);
+
+	// WPA2(pre-auth)
+	if (sta->ethertype == ETH_P_PRE_AUTH)
+	{
+		if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_PMKID_CACHE, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, 0, 0))
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
+			return;
+		}
+	}
+	else
+	{
+		if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_WPA_KEY, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, sta->ApIdx, 0))
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_tx_key:RTPRIV_IOCTL_ADD_WPA_KEY\n");
+			return;
+		}
+	}
+}
+
+static void ieee802_1x_encapsulate_radius(rtapd *rtapd, struct sta_info *sta, u8 *eap, size_t len)
+{
+	struct radius_msg *msg;
+	u8 buf[128];
+	int	res;
+
+	sta->radius_identifier = Radius_client_get_id(rtapd);
+	msg = Radius_msg_new(RADIUS_CODE_ACCESS_REQUEST, sta->radius_identifier);
+	if (msg == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "Could not create net RADIUS packet\n");
+		return;
+	}
+
+	Radius_msg_make_authenticator(msg, (u8 *) sta, sizeof(sta));
+
+	if (sta->identity && !Radius_msg_add_attr(msg, RADIUS_ATTR_USER_NAME, sta->identity, sta->identity_len))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add User-Name\n");
+		goto fail;
+	}
+	   // apd->conf->own_ip_addr is filled according to configuration file
+	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_NAS_IP_ADDRESS, (u8 *) &rtapd->conf->own_ip_addr, 4))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-IP-Address\n");
+		goto fail;
+	}
+
+	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT, sta->aid))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port\n");
+		goto fail;
+	}
+	
+	snprintf((char *)&buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(rtapd->own_addr[sta->ApIdx]));
+	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLED_STATION_ID, buf, strlen((char *)&buf)))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add Called-Station-Id\n");
+		goto fail;
+	}
+
+	snprintf((char *)&buf, sizeof(buf), RADIUS_802_1X_ADDR_FORMAT, MAC2STR(sta->addr));
+	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CALLING_STATION_ID, buf, strlen((char *)&buf)))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add Calling-Station-Id\n");
+		goto fail;
+	}
+
+	/* TODO: should probably check MTU from driver config; 2304 is max for
+	 * IEEE 802.11, but use 1400 to avoid problems with too large packets
+	 */
+	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_FRAMED_MTU, 1400))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add Framed-MTU\n");
+		goto fail;
+	}
+
+	if (!Radius_msg_add_attr_int32(msg, RADIUS_ATTR_NAS_PORT_TYPE, RADIUS_NAS_PORT_TYPE_IEEE_802_11))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add NAS-Port-Type\n");
+		goto fail;
+	}
+/*
+	snprintf(buf, sizeof(buf), "CONNECT 11Mbps 802.11b");
+	if (!Radius_msg_add_attr(msg, RADIUS_ATTR_CONNECT_INFO, buf, strlen(buf)))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add Connect-Info\n");
+		goto fail;
+	}
+*/
+	if (eap && !Radius_msg_add_eap(msg, eap, len))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not add EAP-Message\n");
+		goto fail;
+	}
+
+	/* State attribute must be copied if and only if this packet is
+	 * Access-Request reply to the previous Access-Challenge */
+	if (sta->last_recv_radius && sta->last_recv_radius->hdr->code == RADIUS_CODE_ACCESS_CHALLENGE)
+	{
+		int res = Radius_msg_copy_attr(msg, sta->last_recv_radius, RADIUS_ATTR_STATE);
+		if (res < 0)
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"Could not copy State attribute from previous Access-Challenge\n");
+			goto fail;
+		}
+	}
+
+	res = Radius_client_send(rtapd, msg, RADIUS_AUTH, sta->ApIdx);
+	DBGPRINT(RT_DEBUG_TRACE, "Finish Radius_client_send..(%d)\n", res);
+
+	return;
+
+fail:
+	Radius_msg_free(msg);
+	free(msg);
+}
+
+static void handle_eap_response(struct sta_info *sta, struct eap_hdr *eap, u8 *data, size_t len)
+{
+	u8 type;
+
+	assert(sta->eapol_sm != NULL);
+
+	if (eap->identifier != sta->eapol_sm->currentId)
+	{
+		DBGPRINT(RT_DEBUG_INFO,"EAP Identifier of the Response-Identity from " MACSTR
+			   " does not match (was %d, expected %d)\n",
+			   MAC2STR(sta->addr), eap->identifier,
+			   sta->eapol_sm->currentId);
+		// didn't check identifier..  reasonable ?
+		return;
+	}
+
+	if (len < 1)
+	{
+		DBGPRINT(RT_DEBUG_WARN,"too short response data\n");
+		return;
+	}
+
+	if (sta->last_eap_supp != NULL)
+		free(sta->last_eap_supp);
+	       sta->last_eap_supp_len = sizeof(*eap) + len;
+	       sta->last_eap_supp = (u8 *) malloc(sta->last_eap_supp_len);
+	if (sta->last_eap_supp == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not alloc memory for last EAP Response\n");
+		return;
+	}
+
+	memcpy(sta->last_eap_supp, eap, sizeof(*eap));
+	memcpy(sta->last_eap_supp + sizeof(*eap), data, len);
+
+	type = data[0];
+	data++;
+	len--;
+
+	/* TODO: IEEE 802.1aa/D4: should use auth_pae.initialEAPMsg to check
+	 * which EAP packet is accepted as response; currently, hostapd only
+	 * supports EAP Response-Identity, so this can be hardcoded */
+	if (type == EAP_TYPE_IDENTITY)
+	{
+		char *buf, *pos;
+		int i;
+
+		buf = malloc(4 * len + 1);
+		if (buf)
+		{
+			pos = buf;
+			for (i = 0; i < len; i++)
+			{
+				if (data[i] >= 32 && data[i] < 127)
+					*pos++ = data[i];
+				else
+				{
+					snprintf(pos, 5, "{%02x}", data[i]);
+					pos += 4;
+				}
+			}
+			*pos = '\0';
+			free(buf);
+		}
+
+		sta->eapol_sm->auth_pae.rxInitialRsp = TRUE;
+
+		/* Save station identity for future RADIUS packets */
+		if (sta->identity)
+			free(sta->identity);
+		sta->identity = (u8 *) malloc(len);
+		if (sta->identity)
+		{
+			memcpy(sta->identity, data, len);
+			sta->identity_len = len;
+		}
+	}
+	else
+	{
+		if (type != EAP_TYPE_NAK)
+			sta->eapol_sm->be_auth.backendNonNakResponsesFromSupplicant++;
+		sta->eapol_sm->be_auth.rxResp = TRUE;
+	}
+}
+
+/* Process incoming EAP packet from Supplicant */
+static void handle_eap(struct sta_info *sta, u8 *buf, size_t len)
+{
+	struct eap_hdr *eap;
+	u16 eap_len;
+
+	if (len < sizeof(*eap))
+	{
+		DBGPRINT(RT_DEBUG_ERROR," too short EAP packet\n");
+		return;
+	}
+
+	eap = (struct eap_hdr *) buf;
+
+	eap_len = ntohs(eap->length);
+	DBGPRINT(RT_DEBUG_INFO," Receive EAP: code=%d identifier=%d length=%d from Supplicant ra%d\n",
+			  eap->code, eap->identifier, eap_len,sta->ApIdx);
+	if (eap_len < sizeof(*eap))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Invalid EAP length\n");
+		return;
+	}
+	else if (eap_len > len)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Too short frame to contain this EAP packet\n");
+		return;
+	}
+	else if (eap_len < len)
+	{
+		DBGPRINT(RT_DEBUG_WARN,"Ignoring %d extra bytes after EAP packet\n", len - eap_len);
+	}
+
+	eap_len -= LENGTH_8021X_HDR;
+
+	switch (eap->code)
+	{
+		case EAP_CODE_REQUEST:
+			return;
+
+		case EAP_CODE_RESPONSE:
+			handle_eap_response( sta, eap, (u8 *) (eap + 1), eap_len);
+			break;
+
+		case EAP_CODE_SUCCESS:
+			return;
+
+		case EAP_CODE_FAILURE:
+			return;
+
+		default:
+			return;
+	}
+}
+
+/* called from handle_read(). Process the EAPOL frames from the Supplicant */
+void ieee802_1x_receive(rtapd *rtapd, u8 *sa, u8 *apidx, u8 *buf, size_t len, u16 ethertype)
+{
+	struct sta_info *sta;
+	struct ieee802_1x_hdr *hdr;
+	char SNAP_802_1H[] = {0xaa, 0xaa, 0x03, 0x00, 0x00, 0x00};
+	UCHAR 	RalinkIe[9] = {221, 7, 0x00, 0x0c, 0x43, 0x00, 0x00, 0x00, 0x00}; 
+	u16 datalen;
+	int bStop = 0;
+
+	DBGPRINT(RT_DEBUG_TRACE,"IEEE802_1X_RECEIVE : from Supplicant\n");
+	
+	if (len == sizeof(RalinkIe) && RTMPCompareMemory(buf, RalinkIe, sizeof(RalinkIe)) == 0)
+		bStop = 1;
+	
+	sta = Ap_get_sta(rtapd, sa, apidx, ethertype, bStop);
+	if (!sta)
+	{
+		return;
+	}
+	if (RTMPCompareMemory(buf, SNAP_802_1H, 6) == 0)
+		buf += LENGTH_802_1_H;
+	hdr = (struct ieee802_1x_hdr *) buf;
+	datalen = ntohs(hdr->length);
+	
+	if (len - sizeof(*hdr) < datalen)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Frame too short for this IEEE 802.1X packet\n");
+		return;
+	}
+
+	if (len - sizeof(*hdr) > datalen)
+	{
+	}
+
+	if (!sta->eapol_sm)
+	{
+		sta->eapol_sm = eapol_sm_alloc(rtapd, sta);
+		if (!sta->eapol_sm)
+			return;
+	}
+
+	if (((ethertype == ETH_P_PAE) && (hdr->version != EAPOL_VERSION)) || ((ethertype == ETH_P_PRE_AUTH) && (hdr->version != EAPOL_VERSION_2)))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Key descripter does not match with WPA rule\n");
+		return;
+	}
+
+	switch (hdr->type)
+	{
+		case IEEE802_1X_TYPE_EAP_PACKET:
+			DBGPRINT(RT_DEBUG_TRACE,"Handle EAP_PACKET from %s%d\n", rtapd->prefix_wlan_name, sta->ApIdx);
+			handle_eap(sta, (buf + LENGTH_8021X_HDR), datalen);
+			break;
+
+		case IEEE802_1X_TYPE_EAPOL_START:
+			DBGPRINT(RT_DEBUG_TRACE,"Handle EAPOL_START from %s%d\n", rtapd->prefix_wlan_name, sta->ApIdx);
+			sta->eapol_sm->auth_pae.eapStart = TRUE;
+			eapol_sm_step(sta->eapol_sm);
+			break;
+
+		case IEEE802_1X_TYPE_EAPOL_LOGOFF:
+			sta->eapol_sm->auth_pae.eapLogoff = TRUE;
+			eapol_sm_step(sta->eapol_sm);
+			break;
+
+		case IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT:
+			/* TODO: */
+			DBGPRINT(RT_DEBUG_TRACE,"Handle EAPOL_ALERT from %s%d\n", rtapd->prefix_wlan_name, sta->ApIdx);
+			break;
+
+		default:
+			DBGPRINT(RT_DEBUG_TRACE,"Handle Unknown EAP message(Type:%d) from %s%d\n",hdr->type, rtapd->prefix_wlan_name, sta->ApIdx);
+			break;
+	}
+
+	eapol_sm_step(sta->eapol_sm);
+}
+
+void ieee802_1x_new_station(rtapd *rtapd, struct sta_info *sta)
+{
+	if (sta->eapol_sm)
+	{
+		sta->eapol_sm->portEnabled = TRUE;
+		eapol_sm_step(sta->eapol_sm);
+		return;
+	}
+
+	sta->eapol_sm = eapol_sm_alloc(rtapd, sta);
+	if (sta->eapol_sm)
+		sta->eapol_sm->portEnabled = TRUE;
+}
+
+void ieee802_1x_free_station(struct sta_info *sta)
+{
+	if (sta->last_recv_radius)
+	{
+		Radius_msg_free(sta->last_recv_radius);
+		free(sta->last_recv_radius);
+		sta->last_recv_radius = NULL;
+	}
+
+	free(sta->last_eap_supp);
+	sta->last_eap_supp = NULL;
+
+	free(sta->last_eap_radius);
+	sta->last_eap_radius = NULL;
+
+	free(sta->identity);
+	sta->identity = NULL;
+
+	free(sta->eapol_key_sign);
+	sta->eapol_key_sign = NULL;
+
+	free(sta->eapol_key_crypt);
+	sta->eapol_key_crypt = NULL;
+
+	eapol_sm_free(sta->eapol_sm);
+	sta->eapol_sm = NULL;
+}
+
+static void ieee802_1x_decapsulate_radius(struct sta_info *sta)
+{
+	u8 *eap;
+	size_t len;
+	struct eap_hdr *hdr;
+	int eap_type = -1;
+	struct radius_msg *msg;
+
+	if (sta->last_recv_radius == NULL)
+		return;
+
+	msg = sta->last_recv_radius;
+	eap = Radius_msg_get_eap(msg, &len);
+	if (eap == NULL)
+	{
+		/* draft-aboba-radius-rfc2869bis-20.txt, Chap. 2.6.3:
+		 * RADIUS server SHOULD NOT send Access-Reject/no EAP-Message
+		 * attribute */
+		free(sta->last_eap_radius);
+		sta->last_eap_radius = NULL;
+		sta->last_eap_radius_len = 0;
+		return;
+	}
+
+	if (len < sizeof(*hdr))
+	{
+		free(eap);
+		return;
+	}
+
+	if (len > sizeof(*hdr))
+		eap_type = eap[sizeof(*hdr)];
+
+	hdr = (struct eap_hdr *) eap;
+
+	sta->eapol_sm->be_auth.idFromServer = hdr->identifier;
+
+	if (sta->last_eap_radius)
+		free(sta->last_eap_radius);
+	sta->last_eap_radius = eap;
+	sta->last_eap_radius_len = len;
+}
+
+static void ieee802_1x_get_keys(rtapd *rtapd, struct sta_info *sta,
+				struct radius_msg *msg, struct radius_msg *req,
+				u8 *shared_secret, size_t shared_secret_len)
+{
+	struct radius_ms_mppe_keys *keys;
+	NDIS_802_11_KEY 	WepKey;
+	
+	memset(&WepKey, 0,sizeof(NDIS_802_11_KEY));
+	keys = Radius_msg_get_ms_keys(msg, req, shared_secret, shared_secret_len);
+	
+	if(keys && keys->recv_len != 0)
+	{
+		DBGPRINT(RT_DEBUG_INFO, "IEEE802_1x_Get_Keys, PMK_len = %d\n",keys->recv_len );
+		DBGPRINT(RT_DEBUG_INFO, "PMK = %x %x %x %x %x %x %x ...%x \n",\
+			keys->recv[0],keys->recv[1],keys->recv[2],keys->recv[3],\
+			keys->recv[4],keys->recv[5],keys->recv[6],keys->recv[15]);
+		DBGPRINT(RT_DEBUG_INFO, "PMK[16] = %x %x %x %x %x %x %x %x \n",\
+			keys->recv[16],keys->recv[17],keys->recv[18],keys->recv[19],\
+			keys->recv[20],keys->recv[21],keys->recv[22],keys->recv[23]);
+
+		WepKey.KeyLength = keys->recv_len;
+		memcpy(WepKey.KeyMaterial, keys->recv, (keys->recv_len== 32?32:1));
+		memcpy(WepKey.addr, sta->addr, 6);
+
+		// WPA2(pre-auth)
+		if (sta->ethertype == ETH_P_PRE_AUTH)
+		{
+			if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_PMKID_CACHE, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, 0, 0))
+			{
+				DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_get_keys:RTPRIV_IOCTL_ADD_PMKID_CACHE\n");
+				return;
+			}
+		}
+		else
+		{
+			if (RT_ioctl(rtapd->ioctl_sock, RTPRIV_IOCTL_ADD_WPA_KEY, (char *)&WepKey, sizeof(NDIS_802_11_KEY), rtapd->prefix_wlan_name, sta->ApIdx, 0))
+			{
+				DBGPRINT(RT_DEBUG_ERROR,"ieee802_1x_get_keys:RTPRIV_IOCTL_ADD_WPA_KEY\n");
+				return;
+			}
+		}
+
+	
+		if (keys->send && keys->recv)
+		{
+			free(sta->eapol_key_sign);
+			free(sta->eapol_key_crypt);
+			sta->eapol_key_sign = keys->send;
+			sta->eapol_key_sign_len = keys->send_len;
+			sta->eapol_key_crypt = keys->recv;
+			sta->eapol_key_crypt_len = keys->recv_len;
+			sta->eapol_sm->keyAvailable = TRUE;
+		}
+		else
+		{
+			free(keys->send);
+			free(keys->recv);
+		}
+		free(keys);
+	}
+}
+
+/* Process the RADIUS frames from Authentication Server */
+static RadiusRxResult
+ieee802_1x_receive_auth(rtapd *rtapd, struct radius_msg *msg, struct radius_msg *req,
+			u8 *shared_secret, size_t shared_secret_len, void *data)
+{
+	struct sta_info *sta;
+	u32 session_timeout = 88, termination_action;
+	int session_timeout_set, free_flag = 0;
+
+	DBGPRINT(RT_DEBUG_TRACE,"Receive IEEE802_1X Response Packet From Radius Server. \n");
+
+	sta = Ap_get_sta_radius_identifier(rtapd, msg->hdr->identifier);
+	if (sta == NULL)
+	{
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	/* RFC 2869, Ch. 5.13: valid Message-Authenticator attribute MUST be
+	 * present when packet contains an EAP-Message attribute */
+	if (msg->hdr->code == RADIUS_CODE_ACCESS_REJECT && Radius_msg_get_attr(msg,
+		RADIUS_ATTR_MESSAGE_AUTHENTICATOR, NULL, 0) < 0 &&
+		Radius_msg_get_attr(msg, RADIUS_ATTR_EAP_MESSAGE, NULL, 0) < 0)
+	{
+	}
+	else if (Radius_msg_verify(msg, shared_secret, shared_secret_len, req))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Incoming RADIUS packet did not have correct Message-Authenticator - dropped\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	if (msg->hdr->code != RADIUS_CODE_ACCESS_ACCEPT &&
+		msg->hdr->code != RADIUS_CODE_ACCESS_REJECT &&
+		msg->hdr->code != RADIUS_CODE_ACCESS_CHALLENGE)
+	{
+		DBGPRINT(RT_DEBUG_WARN,"Unknown RADIUS message code\n");
+		return RADIUS_RX_UNKNOWN;
+	}
+
+	sta->radius_identifier = -1;
+
+	if (sta->last_recv_radius)
+	{
+		Radius_msg_free(sta->last_recv_radius);
+		free(sta->last_recv_radius);
+	}
+
+	sta->last_recv_radius = msg;
+
+	session_timeout_set = !Radius_msg_get_attr_int32(msg, RADIUS_ATTR_SESSION_TIMEOUT, &session_timeout);
+	if (Radius_msg_get_attr_int32(msg, RADIUS_ATTR_TERMINATION_ACTION, &termination_action))
+		termination_action = RADIUS_TERMINATION_ACTION_DEFAULT;
+
+	switch (msg->hdr->code)
+	{
+		case RADIUS_CODE_ACCESS_ACCEPT:
+			/* draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
+			if (session_timeout_set && termination_action == RADIUS_TERMINATION_ACTION_RADIUS_REQUEST)
+			{
+				sta->eapol_sm->reauth_timer.reAuthPeriod =	session_timeout;
+			}
+			else if (session_timeout_set && (rtapd->conf->session_timeout_set == 1))   // 1 1 
+			{
+				Ap_sta_session_timeout(rtapd, sta, ((session_timeout<rtapd->conf->session_timeout_interval) ? session_timeout : rtapd->conf->session_timeout_interval));
+			}
+			else if (session_timeout_set )   // 1 0 
+			{
+				Ap_sta_session_timeout(rtapd, sta, session_timeout);
+			}
+			else if (rtapd->conf->session_timeout_set == 1)   // 0 1
+			{
+				Ap_sta_session_timeout(rtapd, sta, rtapd->conf->session_timeout_interval);
+			}
+			else  // 0 0
+				free_flag = 1;
+			sta->eapol_sm->be_auth.aSuccess = TRUE;
+			ieee802_1x_get_keys(rtapd, sta, msg, req, shared_secret, shared_secret_len);
+			break;
+
+		case RADIUS_CODE_ACCESS_REJECT:
+			DBGPRINT(RT_DEBUG_WARN, "AS send RADIUS_CODE_ACCESS_REJECT\n");
+			sta->eapol_sm->be_auth.aFail = TRUE;
+			break;
+
+		case RADIUS_CODE_ACCESS_CHALLENGE:
+			if (session_timeout_set)
+			{
+				/* RFC 2869, Ch. 2.3.2
+				 * draft-congdon-radius-8021x-22.txt, Ch. 3.17 */
+				sta->eapol_sm->be_auth.suppTimeout = session_timeout;
+			}
+			sta->eapol_sm->be_auth.aReq = TRUE;
+			break;
+	}
+
+	ieee802_1x_decapsulate_radius(sta);
+	eapol_sm_step(sta->eapol_sm);
+
+
+	if (free_flag == 1)
+		Ap_free_sta(rtapd, sta);
+	return RADIUS_RX_QUEUED;
+}
+
+
+/* Handler for EAPOL Backend Authentication state machine sendRespToServer.
+ * Forward the EAP Response from Supplicant to Authentication Server. */
+void ieee802_1x_send_resp_to_server(rtapd *rtapd, struct sta_info *sta)
+{
+	ieee802_1x_encapsulate_radius(rtapd, sta, sta->last_eap_supp, sta->last_eap_supp_len);
+}
+
+int ieee802_1x_init(rtapd *rtapd)
+{
+	if (Radius_client_register(rtapd, RADIUS_AUTH, ieee802_1x_receive_auth, NULL))
+		return -1;
+
+	return 0;
+}
+
+void ieee802_1x_new_auth_session(rtapd *rtapd, struct sta_info *sta)
+{
+	if (!sta->last_recv_radius)
+		return;
+
+	Radius_msg_free(sta->last_recv_radius);
+	free(sta->last_recv_radius);
+	sta->last_recv_radius = NULL;
+}
Index: /src/router/rt2860apd/ieee802_1x.h
===================================================================
--- /src/router/rt2860apd/ieee802_1x.h	(revision 10789)
+++ /src/router/rt2860apd/ieee802_1x.h	(revision 10789)
@@ -0,0 +1,140 @@
+#ifndef IEEE802_1X_H
+#define IEEE802_1X_H
+
+#include "rtmp_type.h"
+
+/* IEEE Std 802.1X-2001, 7.2 */
+struct ieee802_1x_hdr {
+	u8 version;
+	u8 type;
+	u16 length;
+	/* followed by length octets of data */
+} __attribute__ ((packed));
+
+#define LENGTH_8021X_HDR        4
+#define MAC_ADDR_LEN			6
+
+#define EAPOL_VERSION		1
+#define EAPOL_VERSION_2		2    //for WPA2(pre-auth)
+
+#define LENGTH_802_1_H			8
+
+enum { IEEE802_1X_TYPE_EAP_PACKET = 0,
+       IEEE802_1X_TYPE_EAPOL_START = 1,
+       IEEE802_1X_TYPE_EAPOL_LOGOFF = 2,
+       IEEE802_1X_TYPE_EAPOL_KEY = 3,
+       IEEE802_1X_TYPE_EAPOL_ENCAPSULATED_ASF_ALERT = 4
+};
+
+struct ieee802_1x_eapol_key {
+	u8 type;
+	u16 key_length;
+	u8 replay_counter[8]; /* does not repeat within the life of the keying
+			       * material used to encrypt the Key field;
+			       * 64-bit NTP timestamp MAY be used here */
+	u8 key_iv[16]; /* cryptographically random number */
+	u8 key_index; /* key flag in the most significant bit:
+		       * 0 = broadcast (default key),
+		       * 1 = unicast (key mapping key); key index is in the
+		       * 7 least significant bits */
+	u8 key_signature[16]; /* HMAC-MD5 message integrity check computed with
+			       * MS-MPPE-Send-Key as the key */
+
+	/* followed by key: if packet body length = 44 + key length, then the
+	 * key field (of key_length bytes) contains the key in encrypted form;
+	 * if packet body length = 44, key field is absent and key_length
+	 * represents the number of least significant octets from
+	 * MS-MPPE-Send-Key attribute to be used as the keying material;
+	 * RC4 key used in encryption = Key-IV + MS-MPPE-Recv-Key */
+} __attribute__ ((packed));
+
+enum { EAPOL_KEY_TYPE_RC4 = 1 };
+
+
+/* RFC 2284 - PPP Extensible Authentication Protocol (EAP) */
+
+struct eap_hdr {
+	u8 code;
+	u8 identifier;
+	u16 length; /* including code and identifier */
+	/* followed by length-2 octets of data */
+} __attribute__ ((packed));
+
+#define LENGTH_EAP_HDR        4
+
+enum { EAP_CODE_REQUEST = 1, EAP_CODE_RESPONSE = 2, EAP_CODE_SUCCESS = 3,
+       EAP_CODE_FAILURE = 4 };
+
+/* EAP Request and Response data begins with one octet Type. Success and
+ * Failure do not have additional data. */
+
+/* RFC 2284, 3.0 */
+enum { EAP_TYPE_IDENTITY = 1,
+       EAP_TYPE_NOTIFICATION = 2,
+       EAP_TYPE_NAK = 3 /* Response only */,
+       EAP_TYPE_MD5_CHALLENGE = 4,
+       EAP_TYPE_ONE_TIME_PASSWORD = 5 /* RFC 1938 */,
+       EAP_TYPE_GENERIC_TOKEN_CARD = 6,
+       EAP_TYPE_TLS = 13 /* RFC 2716 */,
+       EAP_TYPE_TTLS = 21 /* draft-ietf-pppext-eap-ttls-02.txt */,
+       EAP_TYPE_PEAP = 25 /* draft-josefsson-pppext-eap-tls-eap-06.txt */,
+};
+
+// Key mapping keys require a BSSID
+typedef struct _NDIS_802_11_KEY
+{
+    u32           Length;             // Length of this structure
+    u8            addr[6];
+    u32           KeyIndex;           
+    u32           KeyLength;          // length of key in bytes
+    u8            KeyMaterial[64];     // variable length depending on above field
+} NDIS_802_11_KEY, *PNDIS_802_11_KEY;
+
+// The definition MUST synchronize with driver(in oid.h)
+#define MAX_RADIUS_SRV_NUM			2	  // 802.1x failover number
+
+typedef struct PACKED _RADIUS_SRV_INFO {
+	unsigned int		radius_ip;
+	unsigned int		radius_port;
+	unsigned char		radius_key[64];
+	unsigned char		radius_keylen;
+} RADIUS_SRV_INFO, *PRADIUS_SRV_INFO;
+
+typedef struct PACKED _RADIUS_KEY_INFO
+{
+	unsigned char		radius_srv_num;			
+	RADIUS_SRV_INFO		radius_srv_info[MAX_RADIUS_SRV_NUM];	
+	unsigned char		ieee8021xWEP;		 // dynamic WEP
+    unsigned char       key_index;           
+    unsigned char       key_length;          // length of key in bytes
+    unsigned char       key_material[13];    
+} RADIUS_KEY_INFO, *PRADIUS_KEY_INFO;
+
+// It's used by 802.1x daemon to require relative configuration
+typedef struct PACKED _RADIUS_CONF
+{
+    unsigned int       	Length;             // Length of this structure    
+    unsigned char		mbss_num;			// indicate multiple BSS number 
+	unsigned int		own_ip_addr;	
+	unsigned int		retry_interval;
+	unsigned int		session_timeout_interval;
+	unsigned char		EAPifname[IFNAMSIZ];
+	unsigned char		EAPifname_len;
+	unsigned char 		PreAuthifname[IFNAMSIZ];
+	unsigned char		PreAuthifname_len;
+	RADIUS_KEY_INFO		RadiusInfo[MAX_MBSSID_NUM];
+} RADIUS_CONF, *PRADIUS_CONF;
+
+void ieee802_1x_new_station(rtapd *apd, struct sta_info *sta);
+void ieee802_1x_free_station(struct sta_info *sta);
+
+void ieee802_1x_request_identity(rtapd *apd, struct sta_info *sta, u8 id);
+void ieee802_1x_tx_canned_eap(rtapd *apd, struct sta_info *sta, u8 id, int success);
+void ieee802_1x_tx_req(rtapd *apd, struct sta_info *sta, u8 id);
+void ieee802_1x_tx_key(rtapd *hapd, struct sta_info *sta, u8 id);
+void ieee802_1x_send_resp_to_server(rtapd *apd, struct sta_info *sta);
+void ieee802_1x_set_sta_authorized(rtapd *rtapd, struct sta_info *sta, int authorized);
+int ieee802_1x_init(rtapd *apd);
+void ieee802_1x_new_auth_session(rtapd *apd, struct sta_info *sta);
+
+#endif /* IEEE802_1X_H */
Index: /src/router/rt2860apd/md5.c
===================================================================
--- /src/router/rt2860apd/md5.c	(revision 10789)
+++ /src/router/rt2860apd/md5.c	(revision 10789)
@@ -0,0 +1,508 @@
+/*
+
+ ***************************************************************************
+ * Ralink Tech Inc.
+ * 4F, No. 2 Technology	5th	Rd.
+ * Science-based Industrial	Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002-2004, Ralink Technology, Inc.
+ *
+ * All rights reserved.	Ralink's source	code is	an unpublished work	and	the
+ * use of a	copyright notice does not imply	otherwise. This	source code
+ * contains	confidential trade secret material of Ralink Tech. Any attemp
+ * or participation	in deciphering,	decoding, reverse engineering or in	any
+ * way altering	the	source code	is stricitly prohibited, unless	the	prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************
+
+	Module Name:
+	md5.c
+
+	Abstract:
+
+	Revision History:
+	Who			When			What
+	--------	----------		----------------------------------------------
+	jan		10-28-03		Initial
+	Rita    	11-23-04		Modify MD5 and SHA-1
+	Edward Tsai	03-11-05		Integrate hostapd_get_rand and rc4 frunctions from MD5 code of HUT Mobile IP
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include <endian.h>
+
+#include "common.h"
+#include "rtmp_type.h"
+#include "md5.h"
+
+int hostapd_get_rand(u8 *buf, size_t len)
+{
+	FILE *f;
+	size_t rc;
+
+	f = fopen("/dev/urandom", "r");
+	if (f == NULL) {
+		printf("Could not open /dev/urandom.\n");
+		return -1;
+	}
+
+	rc = fread(buf, 1, len, f);
+	fclose(f);
+
+	return rc != len ? -1 : 0;
+}
+
+/**
+ * md5_mac:
+ * @key: pointer to	the	key	used for MAC generation
+ * @key_len: length	of the key in bytes
+ * @data: pointer to the data area for which the MAC is	generated
+ * @data_len: length of	the	data in	bytes
+ * @mac: pointer to	the	buffer holding space for the MAC; the buffer should
+ * have	space for 128-bit (16 bytes) MD5 hash value
+ *
+ * md5_mac() determines	the	message	authentication code	by using secure	hash
+ * MD5(key | data |	key).
+ */
+void md5_mac(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac)
+{
+	MD5_CTX	context;
+
+	MD5Init(&context);
+	MD5Update(&context,	key, key_len);
+	MD5Update(&context,	data, data_len);
+	MD5Update(&context,	key, key_len);
+	MD5Final(mac, &context);
+}
+
+
+/**
+ * hmac_md5:
+ * @key: pointer to	the	key	used for MAC generation
+ * @key_len: length	of the key in bytes
+ * @data: pointer to the data area for which the MAC is	generated
+ * @data_len: length of	the	data in	bytes
+ * @mac: pointer to	the	buffer holding space for the MAC; the buffer should
+ * have	space for 128-bit (16 bytes) MD5 hash value
+ *
+ * hmac_md5() determines the message authentication	code using HMAC-MD5.
+ * This	implementation is based	on the sample code presented in	RFC	2104.
+ */
+void hmac_md5(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac)
+{
+	MD5_CTX	context;
+	UCHAR k_ipad[65]; /* inner	padding	- key XORd with	ipad */
+	UCHAR k_opad[65]; /* outer	padding	- key XORd with	opad */
+	UCHAR tk[16];
+	int	i;
+
+	//assert(key != NULL && data != NULL && mac != NULL);
+
+	/* if key is longer	than 64	bytes reset	it to key =	MD5(key) */
+	if (key_len	> 64) {
+		MD5_CTX	ttcontext;
+
+		MD5Init(&ttcontext);
+		MD5Update(&ttcontext, key, key_len);
+		MD5Final(tk, &ttcontext);
+		//key=(PUCHAR)ttcontext.buf;
+		key	= tk;
+		key_len	= 16;
+	}
+
+	/* the HMAC_MD5	transform looks	like:
+	 *
+	 * MD5(K XOR opad, MD5(K XOR ipad, text))
+	 *
+	 * where K is an n byte	key
+	 * ipad	is the byte	0x36 repeated 64 times
+	 * opad	is the byte	0x5c repeated 64 times
+	 * and text	is the data	being protected	*/
+
+	/* start out by	storing	key	in pads	*/
+	NdisZeroMemory(k_ipad, sizeof(k_ipad));
+	NdisZeroMemory(k_opad,	sizeof(k_opad));
+	//assert(key_len < sizeof(k_ipad));
+	NdisMoveMemory(k_ipad, key,	key_len);
+	NdisMoveMemory(k_opad, key,	key_len);
+
+	/* XOR key with	ipad and opad values */
+	for	(i = 0;	i <	64;	i++) {
+		k_ipad[i] ^= 0x36;
+		k_opad[i] ^= 0x5c;
+	}
+
+	/* perform inner MD5 */
+	MD5Init(&context);					 /*	init context for 1st pass */
+	MD5Update(&context,	k_ipad,	64);	 /*	start with inner pad */
+	MD5Update(&context,	data, data_len); /*	then text of datagram */
+	MD5Final(mac, &context);			 /*	finish up 1st pass */
+
+	/* perform outer MD5 */
+	MD5Init(&context);					 /*	init context for 2nd pass */
+	MD5Update(&context,	k_opad,	64);	 /*	start with outer pad */
+	MD5Update(&context,	mac, 16);		 /*	then results of	1st	hash */
+	MD5Final(mac, &context);			 /*	finish up 2nd pass */
+}
+
+#if __BYTE_ORDER == __BIG_ENDIAN
+void byteReverse(unsigned char *buf, unsigned longs);
+void byteReverse(unsigned char *buf, unsigned longs)
+{
+	unsigned char tmp;
+	
+    do {
+	   tmp = buf[3];
+	   buf[3] = buf[0];
+	   buf[0] = tmp;
+	   tmp = buf[2];
+	   buf[2] = buf[1];
+	   buf[1] = tmp;
+	   buf += 4;
+    } while (--longs);
+}
+#else
+#define byteReverse(buf, len)	// Nothing
+#endif
+
+/* ==========================  MD5 implementation =========================== */
+// four base functions for MD5
+#define MD5_F1(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define MD5_F2(x, y, z) (((x) & (z)) | ((y) & (~z)))
+#define MD5_F3(x, y, z) ((x) ^ (y) ^ (z))
+#define MD5_F4(x, y, z) ((y) ^ ((x) | (~z)))
+#define CYCLIC_LEFT_SHIFT(w, s) (((w) << (s)) | ((w) >> (32-(s))))
+
+#define	MD5Step(f, w, x, y,	z, data, t, s)	\
+	( w	+= f(x,	y, z) +	data + t,  w = (CYCLIC_LEFT_SHIFT(w, s)) & 0xffffffff, w +=	x )
+
+
+/*
+ *  Function Description:
+ *      Initiate MD5 Context satisfied in RFC 1321
+ *
+ *  Arguments:
+ *      pCtx        Pointer	to MD5 context
+ *
+ *  Return Value:
+ *      None	    
+ */
+VOID MD5Init(MD5_CTX *pCtx)
+{
+    pCtx->Buf[0]=0x67452301;
+    pCtx->Buf[1]=0xefcdab89;
+    pCtx->Buf[2]=0x98badcfe;
+    pCtx->Buf[3]=0x10325476;
+
+    pCtx->LenInBitCount[0]=0;
+    pCtx->LenInBitCount[1]=0;
+}
+
+
+/*
+ *  Function Description:
+ *      Update MD5 Context, allow of an arrary of octets as the next portion 
+ *      of the message
+ *      
+ *  Arguments:
+ *      pCtx		Pointer	to MD5 context
+ * 	    pData       Pointer to input data
+ *      LenInBytes  The length of input data (unit: byte)
+ *
+ *  Return Value:
+ *      None
+ *
+ *  Note:
+ *      Called after MD5Init or MD5Update(itself)   
+ */
+VOID MD5Update(MD5_CTX *pCtx, UCHAR *pData, ULONG LenInBytes)
+{
+    
+    ULONG TfTimes;
+    ULONG temp;
+	unsigned int i;
+    
+    temp = pCtx->LenInBitCount[0];
+
+    pCtx->LenInBitCount[0] = (ULONG) (pCtx->LenInBitCount[0] + (LenInBytes << 3));
+ 
+    if (pCtx->LenInBitCount[0] < temp)
+        pCtx->LenInBitCount[1]++;   //carry in
+
+    pCtx->LenInBitCount[1] += LenInBytes >> 29;
+
+    // mod 64 bytes
+    temp = (temp >> 3) & 0x3f;  
+    
+    // process lacks of 64-byte data 
+    if (temp) 
+    {
+        UCHAR *pAds = (UCHAR *) pCtx->Input + temp;
+
+        if ((temp+LenInBytes) < 64)
+        {
+            NdisMoveMemory(pAds, (UCHAR *)pData, LenInBytes);   
+            return;
+        }
+        
+        NdisMoveMemory(pAds, (UCHAR *)pData, 64-temp);               
+        byteReverse(pCtx->Input, 16);
+        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
+
+        pData += 64-temp;
+        LenInBytes -= 64-temp; 
+    } // end of if (temp)
+    
+     
+    TfTimes = (LenInBytes >> 6);
+
+    for (i=TfTimes; i>0; i--)
+    {
+        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, 64);
+        byteReverse(pCtx->Input, 16);
+        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
+        pData += 64;
+        LenInBytes -= 64;
+    } // end of for
+
+    // buffering lacks of 64-byte data
+    if(LenInBytes)
+        NdisMoveMemory(pCtx->Input, (UCHAR *)pData, LenInBytes);   
+   
+}
+
+
+/*
+ *  Function Description:
+ *      Append padding bits and length of original message in the tail 
+ *      The message digest has to be completed in the end  
+ *  
+ *  Arguments:
+ *      Digest		Output of Digest-Message for MD5
+ *  	pCtx        Pointer	to MD5 context
+ * 	
+ *  Return Value:
+ *      None
+ *  
+ *  Note:
+ *      Called after MD5Update
+ */
+VOID MD5Final(UCHAR Digest[16], MD5_CTX *pCtx)
+{
+    UCHAR Remainder;
+    UCHAR PadLenInBytes;
+    UCHAR *pAppend=0;
+    unsigned int i;
+    
+    Remainder = (UCHAR)((pCtx->LenInBitCount[0] >> 3) & 0x3f);
+
+    PadLenInBytes = (Remainder < 56) ? (56-Remainder) : (120-Remainder);
+    
+    pAppend = (UCHAR *)pCtx->Input + Remainder;
+
+    // padding bits without crossing block(64-byte based) boundary
+    if (Remainder < 56)
+    {
+        *pAppend = 0x80;
+        PadLenInBytes --;
+        
+        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, PadLenInBytes); 
+		
+		// add data-length field, from low to high
+       	for (i=0; i<4; i++)
+        {
+        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff);
+        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff);
+      	}
+      	
+        byteReverse(pCtx->Input, 16);
+        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
+    } // end of if
+    
+    // padding bits with crossing block(64-byte based) boundary
+    else
+    {
+        // the first block ===
+        *pAppend = 0x80;
+        PadLenInBytes --;
+       
+        NdisZeroMemory((UCHAR *)pCtx->Input + Remainder+1, (64-Remainder-1)); 
+        PadLenInBytes -= (64 - Remainder - 1);
+        
+        byteReverse(pCtx->Input, 16);
+        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
+        
+
+        // the second block ===
+        NdisZeroMemory((UCHAR *)pCtx->Input, PadLenInBytes); 
+
+        // add data-length field
+        for (i=0; i<4; i++)
+        {
+        	pCtx->Input[56+i] = (UCHAR)((pCtx->LenInBitCount[0] >> (i << 3)) & 0xff);
+        	pCtx->Input[60+i] = (UCHAR)((pCtx->LenInBitCount[1] >> (i << 3)) & 0xff);
+      	}
+
+        byteReverse(pCtx->Input, 16);
+        MD5Transform(pCtx->Buf, (ULONG *)pCtx->Input);
+    } // end of else
+
+
+    NdisMoveMemory((UCHAR *)Digest, (ULONG *)pCtx->Buf, 16); // output
+    byteReverse((UCHAR *)Digest, 4);
+    NdisZeroMemory(pCtx, sizeof(pCtx)); // memory free 
+}
+
+
+/*
+ *  Function Description:
+ *      The central algorithm of MD5, consists of four rounds and sixteen 
+ *  	steps per round
+ * 
+ *  Arguments:
+ *      Buf     Buffers of four states (output: 16 bytes)		
+ * 	    Mes     Input data (input: 64 bytes) 
+ *  
+ *  Return Value:
+ *      None
+ *  	
+ *  Note:
+ *      Called by MD5Update or MD5Final
+ */
+VOID MD5Transform(ULONG Buf[4], ULONG Mes[16])
+{  
+    ULONG Reg[4], Temp; 
+	unsigned int i;
+    
+    static UCHAR LShiftVal[16] = 
+    { 	
+        7, 12, 17, 22, 	
+		5, 9 , 14, 20, 
+		4, 11, 16, 23, 
+ 		6, 10, 15, 21,
+ 	};
+
+	
+	// [equal to 4294967296*abs(sin(index))]
+    static ULONG MD5Table[64] = 
+	{ 
+		0xd76aa478,	0xe8c7b756,	0x242070db,	0xc1bdceee,	
+		0xf57c0faf,	0x4787c62a,	0xa8304613, 0xfd469501,	
+		0x698098d8,	0x8b44f7af,	0xffff5bb1,	0x895cd7be,
+    	0x6b901122,	0xfd987193,	0xa679438e,	0x49b40821,
+    	
+    	0xf61e2562,	0xc040b340,	0x265e5a51,	0xe9b6c7aa,
+    	0xd62f105d,	0x02441453,	0xd8a1e681,	0xe7d3fbc8,
+    	0x21e1cde6,	0xc33707d6,	0xf4d50d87,	0x455a14ed,
+    	0xa9e3e905,	0xfcefa3f8,	0x676f02d9,	0x8d2a4c8a,
+    	           
+    	0xfffa3942,	0x8771f681,	0x6d9d6122,	0xfde5380c,
+    	0xa4beea44,	0x4bdecfa9,	0xf6bb4b60,	0xbebfbc70,
+    	0x289b7ec6,	0xeaa127fa,	0xd4ef3085,	0x04881d05,
+    	0xd9d4d039,	0xe6db99e5,	0x1fa27cf8,	0xc4ac5665,
+    	           
+    	0xf4292244,	0x432aff97,	0xab9423a7,	0xfc93a039,
+   		0x655b59c3,	0x8f0ccc92,	0xffeff47d,	0x85845dd1,
+    	0x6fa87e4f,	0xfe2ce6e0,	0xa3014314,	0x4e0811a1,
+    	0xf7537e82,	0xbd3af235,	0x2ad7d2bb,	0xeb86d391
+	};
+ 
+				
+    for (i=0; i<4; i++)
+        Reg[i]=Buf[i];
+			
+				
+    // 64 steps in MD5 algorithm
+    for (i=0; i<16; i++)                    
+    {
+        MD5Step(MD5_F1, Reg[0], Reg[1], Reg[2], Reg[3], Mes[i],               
+                MD5Table[i], LShiftVal[i & 0x3]);
+
+        // one-word right shift
+        Temp   = Reg[3]; 
+        Reg[3] = Reg[2];
+        Reg[2] = Reg[1];
+        Reg[1] = Reg[0];
+        Reg[0] = Temp;            
+    }
+    for (i=16; i<32; i++)                    
+    {
+        MD5Step(MD5_F2, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(5*(i & 0xf)+1) & 0xf], 
+                MD5Table[i], LShiftVal[(0x1 << 2)+(i & 0x3)]);    
+
+        // one-word right shift
+        Temp   = Reg[3]; 
+        Reg[3] = Reg[2];
+        Reg[2] = Reg[1];
+        Reg[1] = Reg[0];
+        Reg[0] = Temp;           
+    }
+    for (i=32; i<48; i++)                    
+    {
+        MD5Step(MD5_F3, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(3*(i & 0xf)+5) & 0xf], 
+                MD5Table[i], LShiftVal[(0x1 << 3)+(i & 0x3)]);        
+
+        // one-word right shift
+        Temp   = Reg[3]; 
+        Reg[3] = Reg[2];
+        Reg[2] = Reg[1];
+        Reg[1] = Reg[0];
+        Reg[0] = Temp;          
+    }
+    for (i=48; i<64; i++)                    
+    {
+        MD5Step(MD5_F4, Reg[0], Reg[1], Reg[2], Reg[3], Mes[(7*(i & 0xf)) & 0xf], 
+                MD5Table[i], LShiftVal[(0x3 << 2)+(i & 0x3)]);   
+
+        // one-word right shift
+        Temp   = Reg[3]; 
+        Reg[3] = Reg[2];
+        Reg[2] = Reg[1];
+        Reg[1] = Reg[0];
+        Reg[0] = Temp;           
+    }
+    
+      
+    // (temporary)output
+    for (i=0; i<4; i++)
+        Buf[i] += Reg[i];
+
+}
+
+
+
+#define S_SWAP(a,b) do { u8 t = S[a]; S[a] = S[b]; S[b] = t; } while(0)
+
+void rc4(u8 *buf, size_t len, u8 *key, size_t key_len)
+{
+	u8 S[256];
+	u32 i, j, k;
+	u8 kpos, *pos;
+
+	/* Setup RC4 state */
+	for (i = 0; i < 256; i++)
+		S[i] = i;
+	j = 0;
+	kpos = 0;
+	for (i = 0; i < 256; i++) {
+		j = (j + S[i] + key[kpos]) & 0xff;
+		kpos++;
+		if (kpos >= key_len)
+			kpos = 0;
+		S_SWAP(i, j);
+	}
+
+	/* Apply RC4 to data */
+	pos = buf;
+	i = j = 0;
+	for (k = 0; k < len; k++) {
+		i = (i + 1) & 0xff;
+		j = (j + S[i]) & 0xff;
+		S_SWAP(i, j);
+		*pos++ ^= S[(S[i] + S[j]) & 0xff];
+	}
+}
+
Index: /src/router/rt2860apd/md5.h
===================================================================
--- /src/router/rt2860apd/md5.h	(revision 10789)
+++ /src/router/rt2860apd/md5.h	(revision 10789)
@@ -0,0 +1,65 @@
+#ifndef	__MD5_H__
+#define	__MD5_H__
+
+#ifndef ULONG
+#define	INT		int
+#define	UINT		u32
+#define ULONG		u32
+#define USHORT		u16
+#define UCHAR		u8
+
+#define BOOLEAN		u8
+#define LONGLONG	s64
+#define ULONGLONG	u64
+#define VOID		void
+#define	LONG		int
+#endif	// ULONG
+
+#define	NdisZeroMemory(buff, buff_size)		\
+{						\
+	memset(buff, 0, buff_size);		\
+}
+
+#define	NdisMoveMemory(buff, key, buff_size)	\
+{						\
+	memcpy(buff, key, buff_size);		\
+}
+
+#ifdef ASSERT
+#undef ASSERT
+#endif
+
+#define	ASSERT(x)                                                                       \
+{                                                                                       \
+    if (!(x))                                                                           \
+    {                                                                                   \
+        printk(KERN_WARNING __FILE__ ":%d assert " #x "failed\n", __LINE__);            \
+    }                                                                                   \
+}
+
+#define MD5_MAC_LEN 16
+
+typedef struct _MD5_CTX {
+	ULONG   Buf[4];             // buffers of four states
+	ULONG   LenInBitCount[2];   // length counter for input message, 0 up to 64 bits
+	UCHAR   Input[64];          // input message
+}   MD5_CTX;
+
+int	hostapd_get_rand(u8 *buf, size_t len);
+void	MD5Init(MD5_CTX *pCtx);
+void	MD5Update(MD5_CTX *pCtx, UCHAR *pData, ULONG LenInBytes);
+
+void	MD5Final(UCHAR Digest[16], MD5_CTX *pCtx);
+void	MD5Transform(ULONG Buf[4], ULONG Mes[16]);
+
+void	md5_mac(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac);
+void	hmac_md5(UCHAR *key, ULONG key_len, UCHAR *data, ULONG data_len, UCHAR *mac);
+
+#endif // __MD5_H__
+
+#ifndef RC4_H
+#define RC4_H
+
+void rc4(u8 *buf, size_t len, u8 *key, size_t key_len);
+
+#endif /* RC4_H */
Index: /src/router/rt2860apd/radius.c
===================================================================
--- /src/router/rt2860apd/radius.c	(revision 10789)
+++ /src/router/rt2860apd/radius.c	(revision 10789)
@@ -0,0 +1,710 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	radius.c
+
+	Revision History:
+	Who         When          What
+	--------    ----------    ----------------------------------------------
+	Jan, Lee    Dec --2003    modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <signal.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "common.h"
+#include "radius.h"
+#include "md5.h"
+#include "rt2860apd.h"
+
+struct radius_msg *Radius_msg_new(u8 code, u8 identifier)
+{
+	struct radius_msg *msg;
+
+	msg = (struct radius_msg *) malloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	if (Radius_msg_initialize(msg, RADIUS_DEFAULT_MSG_SIZE))
+	{
+		free(msg);
+		return NULL;
+	}
+
+	Radius_msg_set_hdr(msg, code, identifier);
+
+	return msg;
+}
+
+int Radius_msg_initialize(struct radius_msg *msg, size_t init_len)
+{
+	if (msg == NULL || init_len < sizeof(struct radius_hdr))
+		return -1;
+
+	memset(msg, 0, sizeof(*msg));
+	msg->buf = (unsigned char *) malloc(init_len);
+	if (msg->buf == NULL)
+		return -1;
+	memset(msg->buf, 0, init_len);
+
+	msg->buf_size = init_len;
+	msg->hdr = (struct radius_hdr *) msg->buf;
+	msg->buf_used = sizeof(*msg->hdr);
+
+	msg->attrs = (struct radius_attr_hdr **)
+		malloc(RADIUS_DEFAULT_ATTR_COUNT * sizeof(*msg->attrs));
+	if (msg->attrs == NULL)
+	{
+		free(msg->buf);
+		msg->buf = NULL;
+		msg->hdr = NULL;
+		return -1;
+	}
+
+	msg->attr_size = RADIUS_DEFAULT_ATTR_COUNT;
+	msg->attr_used = 0;
+
+	return 0;
+}
+
+void Radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier)
+{
+	msg->hdr->code = code;
+	msg->hdr->identifier = identifier;
+}
+
+void Radius_msg_free(struct radius_msg *msg)
+{
+	if (msg->buf != NULL)
+	{
+		free(msg->buf);
+		msg->buf = NULL;
+		msg->hdr = NULL;
+	}
+	msg->buf_size = msg->buf_used = 0;
+
+	if (msg->attrs != NULL)
+	{
+		free(msg->attrs);
+		msg->attrs = NULL;
+	}
+	msg->attr_size = msg->attr_used = 0;
+}
+
+
+struct radius_attr_type {
+	u8 type;
+	char *name;
+	enum { RADIUS_ATTR_UNDIST, RADIUS_ATTR_TEXT, RADIUS_ATTR_IP,
+	       RADIUS_ATTR_HEXDUMP, RADIUS_ATTR_INT32 } data_type;
+};
+
+void Radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len)
+{
+	if (secret)
+	{
+		u8 auth[MD5_MAC_LEN];
+		struct radius_attr_hdr *attr;
+
+		memset(auth, 0, MD5_MAC_LEN);
+		attr = Radius_msg_add_attr(msg, RADIUS_ATTR_MESSAGE_AUTHENTICATOR, auth, MD5_MAC_LEN);
+		msg->hdr->length = htons(msg->buf_used);
+		hmac_md5(secret, secret_len, msg->buf, msg->buf_used, (u8 *) (attr + 1));
+	}
+	else
+		msg->hdr->length = htons(msg->buf_used);
+
+	if (msg->buf_used > 0xffff)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"WARNING: too long RADIUS messages (%d)\n", msg->buf_used);
+	}
+}
+
+static int Radius_msg_add_attr_to_array(struct radius_msg *msg, struct radius_attr_hdr *attr)
+{
+	if (msg->attr_used >= msg->attr_size)
+	{
+		struct radius_attr_hdr **nattrs;
+		int nlen = msg->attr_size * 2;
+
+		nattrs = (struct radius_attr_hdr **) realloc(msg->attrs, nlen * sizeof(*msg->attrs));
+
+		if (nattrs == NULL)
+			return -1;
+
+		msg->attrs = nattrs;
+		msg->attr_size = nlen;
+	}
+
+	msg->attrs[msg->attr_used++] = attr;
+
+	return 0;
+}
+
+struct radius_attr_hdr *Radius_msg_add_attr(struct radius_msg *msg, u8 type, u8 *data, size_t data_len)
+{
+	size_t buf_needed;
+	struct radius_attr_hdr *attr;
+
+	if (data_len > RADIUS_MAX_ATTR_LEN)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"radius_msg_add_attr: too long attribute (%d bytes)\n", data_len);
+		return NULL;
+	}
+
+	buf_needed = msg->buf_used + sizeof(*attr) + data_len;
+
+	if (msg->buf_size < buf_needed)
+	{
+		/* allocate more space for message buffer */
+		unsigned char *nbuf;
+		int nlen = msg->buf_size;
+		int diff, i;
+
+		while (nlen < buf_needed)
+			nlen *= 2;
+		nbuf = (unsigned char *) realloc(msg->buf, nlen);
+		if (nbuf == NULL)
+			return NULL;
+		diff = nbuf - msg->buf;
+		msg->buf = nbuf;
+		msg->hdr = (struct radius_hdr *) msg->buf;
+		
+		/* adjust attr pointers to match with the new buffer */
+		for (i = 0; i < msg->attr_used; i++)
+			msg->attrs[i] = (struct radius_attr_hdr *) (((u8 *) msg->attrs[i]) + diff);
+		memset(msg->buf + msg->buf_size, 0, nlen - msg->buf_size);
+		msg->buf_size = nlen;
+	}
+
+	attr = (struct radius_attr_hdr *) (msg->buf + msg->buf_used);
+	attr->type = type;
+	attr->length = sizeof(*attr) + data_len;
+	if (data_len > 0)
+		memcpy(attr + 1, data, data_len);
+
+	msg->buf_used += sizeof(*attr) + data_len;
+
+	if (Radius_msg_add_attr_to_array(msg, attr))
+		return NULL;
+
+	return attr;
+}
+
+struct radius_msg *Radius_msg_parse(const u8 *data, size_t len)
+{
+	struct radius_msg *msg;
+	struct radius_hdr *hdr;
+	struct radius_attr_hdr *attr;
+	size_t msg_len;
+	unsigned char *pos, *end;
+
+	if (data == NULL || len < sizeof(*hdr))
+		return NULL;
+
+	hdr = (struct radius_hdr *) data;
+
+	msg_len = ntohs(hdr->length);
+	if (msg_len < sizeof(*hdr) || msg_len > len)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Invalid RADIUS message length\n");
+		return NULL;
+	}
+
+	if (msg_len < len)
+	{
+		DBGPRINT(RT_DEBUG_INFO,"Ignored %d extra bytes after RADIUS message\n", len - msg_len);
+	}
+
+	msg = (struct radius_msg *) malloc(sizeof(*msg));
+	if (msg == NULL)
+		return NULL;
+
+	if (Radius_msg_initialize(msg, msg_len))
+	{
+		free(msg);
+		return NULL;
+	}
+
+	memcpy(msg->buf, data, msg_len);
+	msg->buf_size = msg->buf_used = msg_len;
+
+	/* parse attributes */
+	pos = (unsigned char *) (msg->hdr + 1);
+	end = msg->buf + msg->buf_used;
+	while (pos < end)
+	{
+		if (end - pos < sizeof(*attr))
+			goto fail;
+
+		attr = (struct radius_attr_hdr *) pos;
+
+		if (pos + attr->length > end || attr->length < sizeof(*attr))
+			goto fail;
+
+		/* TODO: check that attr->length is suitable for attr->type */
+
+		if (Radius_msg_add_attr_to_array(msg, attr))
+			goto fail;
+
+		pos += attr->length;
+	}
+
+	return msg;
+
+ fail:
+	Radius_msg_free(msg);
+	free(msg);
+	return NULL;
+}
+
+int Radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len)
+{
+	u8 *pos = data;
+	size_t left = data_len;
+
+	while (left > 0)
+	{
+		int len;
+		if (left > RADIUS_MAX_ATTR_LEN)
+			len = RADIUS_MAX_ATTR_LEN;
+		else
+			len = left;
+
+		if (!Radius_msg_add_attr(msg, RADIUS_ATTR_EAP_MESSAGE, pos, len))
+			return 0;
+
+		pos += len;
+		left -= len;
+	}
+
+	return 1;
+}
+
+u8 *Radius_msg_get_eap(struct radius_msg *msg, size_t *eap_len)
+{
+	u8 *eap, *pos;
+	size_t len;
+	int i;
+
+	if (msg == NULL)
+		return NULL;
+
+	len = 0;
+	for (i = 0; i < msg->attr_used; i++)
+	{
+		if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE)
+			len += msg->attrs[i]->length - sizeof(struct radius_attr_hdr);
+	}
+
+	if (len == 0)
+		return NULL;
+
+	eap = (u8 *) malloc(len);
+	if (eap == NULL)
+		return NULL;
+
+	pos = eap;
+	for (i = 0; i < msg->attr_used; i++)
+	{
+		if (msg->attrs[i]->type == RADIUS_ATTR_EAP_MESSAGE)
+		{
+			struct radius_attr_hdr *attr = msg->attrs[i];
+			int flen = attr->length - sizeof(*attr);
+			memcpy(pos, attr + 1, flen);
+			pos += flen;
+		}
+	}
+
+	if (eap_len)
+		*eap_len = len;
+
+	return eap;
+}
+
+int Radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len, struct radius_msg *sent_msg)
+{
+	u8 auth[MD5_MAC_LEN], orig[MD5_MAC_LEN];
+	u8 orig_authenticator[16];
+	struct radius_attr_hdr *attr = NULL;
+	int i;
+	MD5_CTX context;
+	u8 hash[MD5_MAC_LEN];
+
+	if (sent_msg == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"No matching Access-Request message found\n");
+		return 1;
+	}
+
+	for (i = 0; i < msg->attr_used; i++)
+	{
+		if (msg->attrs[i]->type == RADIUS_ATTR_MESSAGE_AUTHENTICATOR)
+		{
+			if (attr != 0)
+			{
+				DBGPRINT(RT_DEBUG_ERROR,"Multiple Message-Authenticator attributes in RADIUS message\n");
+				return 1;
+			}
+			attr = msg->attrs[i];
+		}
+	}
+
+	if (attr == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"No Message-Authenticator attribute found\n");
+		return 1;
+	}
+
+	memcpy(orig, attr + 1, MD5_MAC_LEN);
+	memset(attr + 1, 0, MD5_MAC_LEN);
+	memcpy(orig_authenticator, msg->hdr->authenticator, sizeof(orig_authenticator));
+	memcpy(msg->hdr->authenticator, sent_msg->hdr->authenticator, sizeof(msg->hdr->authenticator));
+	hmac_md5(secret, secret_len, msg->buf, msg->buf_used, auth);
+	memcpy(attr + 1, orig, MD5_MAC_LEN);
+	memcpy(msg->hdr->authenticator, orig_authenticator, sizeof(orig_authenticator));
+
+	if (memcmp(orig, auth, MD5_MAC_LEN) != 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Invalid Message-Authenticator!\n");
+		return 1;
+	}
+
+	/* ResponseAuth = MD5(Code+ID+Length+RequestAuth+Attributes+Secret) */
+	MD5Init(&context);
+	MD5Update(&context, (u8 *) msg->hdr, 1 + 1 + 2);
+	MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
+	MD5Update(&context, (u8 *) (msg->hdr + 1), msg->buf_used - sizeof(*msg->hdr));
+	MD5Update(&context, secret, secret_len);
+	MD5Final(hash, &context);
+	if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Response Authenticator invalid!\n");
+		return 1;
+	}
+	return 0;
+
+}
+
+int Radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
+			   size_t secret_len, struct radius_msg *sent_msg)
+{
+	MD5_CTX context;
+	u8 hash[MD5_MAC_LEN];
+
+	MD5Init(&context);
+	MD5Update(&context, msg->buf, 4);
+	MD5Update(&context, sent_msg->hdr->authenticator, MD5_MAC_LEN);
+	if (msg->buf_used > sizeof(struct radius_hdr))
+		MD5Update(&context, msg->buf + sizeof(struct radius_hdr), msg->buf_used - sizeof(struct radius_hdr));
+	MD5Update(&context, secret, secret_len);
+	MD5Final(hash, &context);
+	if (memcmp(hash, msg->hdr->authenticator, MD5_MAC_LEN) != 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Response Authenticator invalid!\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+int Radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type)
+{
+	struct radius_attr_hdr *attr = NULL;
+	int i;
+
+	for (i = 0; i < src->attr_used; i++)
+	{
+		if (src->attrs[i]->type == type)
+		{
+			attr = src->attrs[i];
+			break;
+		}
+	}
+
+	if (attr == NULL)
+		return 0;
+
+	if (!Radius_msg_add_attr(dst, type, (u8 *) (attr + 1), attr->length - sizeof(*attr)))
+		return -1;
+
+	return 1;
+}
+
+/* Create Request Authenticator. The value should be unique over the lifetime
+ * of the shared secret between authenticator and authentication server.
+ * Use one-way MD5 hash calculated from current timestamp and some data given
+ * by the caller. */
+void Radius_msg_make_authenticator(struct radius_msg *msg, u8 *data, size_t len)
+{
+	struct timeval tv;
+	MD5_CTX context;
+	long int l;
+
+	gettimeofday(&tv, NULL);
+	l = random();
+	MD5Init(&context);
+	MD5Update(&context, (u8 *) &tv, sizeof(tv));
+	MD5Update(&context, data, len);
+	MD5Update(&context, (u8 *) &l, sizeof(l));
+	MD5Final(msg->hdr->authenticator, &context);
+}
+
+/* Get Microsoft Vendor-specific RADIUS Attribute from a parsed RADIUS message.
+ * Returns the Attribute payload and sets alen to indicate the length of the
+ * payload if a vendor attribute with ms_type is found, otherwise returns NULL.
+ * The returned payload is allocated with malloc() and caller must free it.
+ */
+static u8 *Radius_msg_get_ms_attr(struct radius_msg *msg, u8 ms_type, size_t *alen)
+{
+	u8 *data, *pos;
+	int i;
+	size_t len;
+
+	if (msg == NULL)
+		return NULL;
+
+	for (i = 0; i < msg->attr_used; i++)
+	{
+		struct radius_attr_hdr *attr = msg->attrs[i];
+		int left;
+		u32 vendor_id;
+		struct radius_attr_vendor_microsoft *ms;
+
+		if (attr->type != RADIUS_ATTR_VENDOR_SPECIFIC)
+			continue;
+
+		left = attr->length - sizeof(*attr);
+		if (left < 4)
+			continue;
+
+		pos = (u8 *) (attr + 1);
+
+		memcpy(&vendor_id, pos, 4);
+		pos += 4;
+		left -= 4;
+
+		if (ntohl(vendor_id) != RADIUS_VENDOR_ID_MICROSOFT)
+			continue;
+
+		while (left >= sizeof(*ms))
+		{
+			ms = (struct radius_attr_vendor_microsoft *) pos;
+			if (ms->vendor_length > left)
+			{
+				left = 0;
+				continue;
+			}
+			if (ms->vendor_type != ms_type)
+			{
+				pos += ms->vendor_length;
+				left -= ms->vendor_length;
+				continue;
+			}
+
+			len = ms->vendor_length - sizeof(*ms);
+			data = (u8 *) malloc(len);
+			if (data == NULL)
+				return NULL;
+			memcpy(data, pos + sizeof(*ms), len);
+			if (alen)
+				*alen = len;
+			return data;
+		}
+	}
+
+	return NULL;
+}
+
+static u8 * decrypt_ms_key(u8 *key, size_t len, struct radius_msg *sent_msg,
+			   u8 *secret, size_t secret_len, size_t *reslen)
+{
+	u8 *pos, *plain, *ppos, *res;
+	size_t left, plen;
+	u8 hash[MD5_MAC_LEN];
+	MD5_CTX context;
+	int i, first = 1;
+
+	/* key: 16-bit salt followed by encrypted key info */
+
+	if (len < 2 + 16)
+		return NULL;
+
+	pos = key + 2;
+	left = len - 2;
+	if (left % 16)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Invalid ms key len\n");
+		return NULL;
+	}
+
+	plen = left;
+	ppos = plain = malloc(plen);
+	if (plain == NULL)
+		return NULL;
+
+	while (left > 0)
+	{
+		/* b(1) = MD5(Secret + Request-Authenticator + Salt)
+		 * b(i) = MD5(Secret + c(i - 1)) for i > 1 */
+
+		MD5Init(&context);
+		MD5Update(&context, secret, secret_len);
+		if (first)
+		{
+			MD5Update(&context, sent_msg->hdr->authenticator,
+				  MD5_MAC_LEN);
+			MD5Update(&context, key, 2); /* Salt */
+			first = 0;
+		} else
+			MD5Update(&context, pos - MD5_MAC_LEN, MD5_MAC_LEN);
+		MD5Final(hash, &context);
+
+		for (i = 0; i < MD5_MAC_LEN; i++)
+			*ppos++ = *pos++ ^ hash[i];
+		left -= MD5_MAC_LEN;
+	}
+
+	if (plain[0] > plen - 1)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Failed to decrypt MPPE key\n");
+		free(plain);
+		return NULL;
+	}
+
+	res = malloc(plain[0]);
+	if (res == NULL)
+	{
+		free(plain);
+		return NULL;
+	}
+	memcpy(res, plain + 1, plain[0]);
+	if (reslen)
+		*reslen = plain[0];
+	free(plain);
+	return res;
+}
+
+struct radius_ms_mppe_keys *
+Radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+		       u8 *secret, size_t secret_len)
+{
+	u8 *key;
+	size_t keylen;
+	struct radius_ms_mppe_keys *keys;
+
+	if (msg == NULL || sent_msg == NULL)
+		return NULL;
+
+	keys = (struct radius_ms_mppe_keys *) malloc(sizeof(*keys));
+	if (keys == NULL)
+		return NULL;
+
+	memset(keys, 0, sizeof(*keys));
+
+	key = Radius_msg_get_ms_attr(msg, RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY, &keylen);
+	if (key)
+	{
+		keys->send = decrypt_ms_key(key, keylen, sent_msg, secret, secret_len, &keys->send_len);
+		free(key);
+	}
+    DBGPRINT(RT_DEBUG_INFO," secret_len = %d, secret= %s\n",secret_len,secret);
+	key = Radius_msg_get_ms_attr(msg, RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY, &keylen);
+	if (key)
+	{
+		keys->recv = decrypt_ms_key(key, keylen, sent_msg, secret, secret_len, &keys->recv_len);
+		free(key);
+	}
+
+	return keys;
+}
+
+/* Add User-Password attribute to a RADIUS message and encrypt it as specified
+ * in RFC 2865, Chap. 5.2 */
+struct radius_attr_hdr *
+Radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  u8 *data, size_t data_len, u8 *secret, size_t secret_len)
+{
+	u8 buf[128];
+	int padlen, i, pos;
+	MD5_CTX context;
+	size_t buf_len;
+	u8 hash[16];
+
+	if (data_len > 128)
+		return NULL;
+
+	memcpy(buf, data, data_len);
+	buf_len = data_len;
+
+	padlen = data_len % 16;
+	if (padlen)
+	{
+		padlen = 16 - padlen;
+		memset(buf + data_len, 0, padlen);
+		buf_len += padlen;
+	}
+
+	MD5Init(&context);
+	MD5Update(&context, secret, secret_len);
+	MD5Update(&context, msg->hdr->authenticator, 16);
+	MD5Final(hash, &context);
+
+	for (i = 0; i < 16; i++)
+		buf[i] ^= hash[i];
+	pos = 16;
+
+	while (pos < buf_len)
+	{
+		MD5Init(&context);
+		MD5Update(&context, secret, secret_len);
+		MD5Update(&context, &buf[pos - 16], 16);
+		MD5Final(hash, &context);
+
+		for (i = 0; i < 16; i++)
+			buf[pos + i] ^= hash[i];
+
+		pos += 16;
+	}
+
+	return Radius_msg_add_attr(msg, RADIUS_ATTR_USER_PASSWORD, buf, buf_len);
+}
+
+int Radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len)
+{
+	int i;
+	struct radius_attr_hdr *attr = NULL;
+	size_t dlen;
+
+	for (i = 0; i < msg->attr_used; i++)
+	{
+		if (msg->attrs[i]->type == type)
+		{
+			attr = msg->attrs[i];
+			break;
+		}
+	}
+
+	if (!attr)
+		return -1;
+
+	dlen = attr->length - sizeof(*attr);
+	if (buf)
+		memcpy(buf, (attr + 1), dlen > len ? len : dlen);
+	return dlen;
+}
+
Index: /src/router/rt2860apd/radius.h
===================================================================
--- /src/router/rt2860apd/radius.h	(revision 10789)
+++ /src/router/rt2860apd/radius.h	(revision 10789)
@@ -0,0 +1,162 @@
+#ifndef RADIUS_H
+#define RADIUS_H
+
+/* RFC 2865 - RADIUS */
+
+struct radius_hdr {
+	u8 code;
+	u8 identifier;
+	u16 length; /* including this header */
+	u8 authenticator[16];
+	/* followed by length-20 octets of attributes */
+} __attribute__ ((packed));
+
+enum { RADIUS_CODE_ACCESS_REQUEST = 1,
+       RADIUS_CODE_ACCESS_ACCEPT = 2,
+       RADIUS_CODE_ACCESS_REJECT = 3,
+       RADIUS_CODE_ACCOUNTING_REQUEST = 4,
+       RADIUS_CODE_ACCOUNTING_RESPONSE = 5,
+       RADIUS_CODE_ACCESS_CHALLENGE = 11,
+       RADIUS_CODE_STATUS_SERVER = 12,
+       RADIUS_CODE_STATUS_CLIENT = 13,
+       RADIUS_CODE_RESERVED = 255
+};
+
+struct radius_attr_hdr {
+	u8 type;
+	u8 length; /* including this header */
+	/* followed by length-2 octets of attribute value */
+} __attribute__ ((packed));
+
+#define RADIUS_MAX_ATTR_LEN (255 - sizeof(struct radius_attr_hdr))
+
+enum { RADIUS_ATTR_USER_NAME = 1,
+       RADIUS_ATTR_USER_PASSWORD = 2,
+       RADIUS_ATTR_NAS_IP_ADDRESS = 4,
+       RADIUS_ATTR_NAS_PORT = 5,
+       RADIUS_ATTR_FRAMED_MTU = 12,
+       RADIUS_ATTR_STATE = 24,
+       RADIUS_ATTR_VENDOR_SPECIFIC = 26,
+       RADIUS_ATTR_SESSION_TIMEOUT = 27,
+       RADIUS_ATTR_IDLE_TIMEOUT = 28,
+       RADIUS_ATTR_TERMINATION_ACTION = 29,
+       RADIUS_ATTR_CALLED_STATION_ID = 30,
+       RADIUS_ATTR_CALLING_STATION_ID = 31,
+       RADIUS_ATTR_NAS_IDENTIFIER = 32,
+       RADIUS_ATTR_ACCT_STATUS_TYPE = 40,
+       RADIUS_ATTR_ACCT_DELAY_TIME = 41,
+       RADIUS_ATTR_ACCT_INPUT_OCTETS = 42,
+       RADIUS_ATTR_ACCT_OUTPUT_OCTETS = 43,
+       RADIUS_ATTR_ACCT_SESSION_ID = 44,
+       RADIUS_ATTR_ACCT_AUTHENTIC = 45,
+       RADIUS_ATTR_ACCT_SESSION_TIME = 46,
+       RADIUS_ATTR_ACCT_INPUT_PACKETS = 47,
+       RADIUS_ATTR_ACCT_OUTPUT_PACKETS = 48,
+       RADIUS_ATTR_ACCT_TERMINATE_CAUSE = 49,
+       RADIUS_ATTR_ACCT_MULTI_SESSION_ID = 50,
+       RADIUS_ATTR_ACCT_LINK_COUNT = 51,
+       RADIUS_ATTR_NAS_PORT_TYPE = 61,
+       RADIUS_ATTR_CONNECT_INFO = 77,
+       RADIUS_ATTR_EAP_MESSAGE = 79,
+       RADIUS_ATTR_MESSAGE_AUTHENTICATOR = 80
+};
+
+
+/* Termination-Action */
+#define RADIUS_TERMINATION_ACTION_DEFAULT 0
+#define RADIUS_TERMINATION_ACTION_RADIUS_REQUEST 1
+
+/* NAS-Port-Type */
+#define RADIUS_NAS_PORT_TYPE_IEEE_802_11 19
+
+
+/* RFC 2548 - Microsoft Vendor-specific RADIUS Attributes */
+#define RADIUS_VENDOR_ID_MICROSOFT 311
+
+struct radius_attr_vendor_microsoft {
+	u8 vendor_type;
+	u8 vendor_length;
+} __attribute__ ((packed));
+
+enum { RADIUS_VENDOR_ATTR_MS_MPPE_SEND_KEY = 16,
+       RADIUS_VENDOR_ATTR_MS_MPPE_RECV_KEY = 17
+};
+
+struct radius_ms_mppe_keys {
+	u8 *send;
+	size_t send_len;
+	u8 *recv;
+	size_t recv_len;
+};
+
+
+/* RADIUS message structure for new and parsed messages */
+struct radius_msg {
+	unsigned char *buf;
+	size_t buf_size; /* total size allocated for buf */
+	size_t buf_used; /* bytes used in buf */
+
+	struct radius_hdr *hdr;
+
+	struct radius_attr_hdr **attrs; /* array of pointers to attributes */
+	size_t attr_size; /* total size of the attribute pointer array */
+	size_t attr_used; /* total number of attributes in the array */
+};
+
+
+/* Default size to be allocated for new RADIUS messages */
+#define RADIUS_DEFAULT_MSG_SIZE 1024
+
+/* Default size to be allocated for attribute array */
+#define RADIUS_DEFAULT_ATTR_COUNT 16
+
+
+/* MAC address ASCII format for IEEE 802.1X use
+ * (draft-congdon-radius-8021x-20.txt) */
+#define RADIUS_802_1X_ADDR_FORMAT "%02X-%02X-%02X-%02X-%02X-%02X"
+/* MAC address ASCII format for non-802.1X use */
+#define RADIUS_ADDR_FORMAT "%02x%02x%02x%02x%02x%02x"
+
+struct radius_msg *Radius_msg_new(u8 code, u8 identifier);
+int Radius_msg_initialize(struct radius_msg *msg, size_t init_len);
+void Radius_msg_set_hdr(struct radius_msg *msg, u8 code, u8 identifier);
+void Radius_msg_free(struct radius_msg *msg);
+void Radius_msg_finish(struct radius_msg *msg, u8 *secret, size_t secret_len);
+struct radius_attr_hdr *Radius_msg_add_attr(struct radius_msg *msg, u8 type,
+					    u8 *data, size_t data_len);
+struct radius_msg *Radius_msg_parse(const u8 *data, size_t len);
+int Radius_msg_add_eap(struct radius_msg *msg, u8 *data, size_t data_len);
+u8 *Radius_msg_get_eap(struct radius_msg *msg, size_t *len);
+int Radius_msg_verify(struct radius_msg *msg, u8 *secret, size_t secret_len,
+		      struct radius_msg *sent_msg);
+int Radius_msg_verify_acct(struct radius_msg *msg, u8 *secret,
+			   size_t secret_len, struct radius_msg *sent_msg);
+int Radius_msg_copy_attr(struct radius_msg *dst, struct radius_msg *src, u8 type);
+void Radius_msg_make_authenticator(struct radius_msg *msg, u8 *data, size_t len);
+struct radius_ms_mppe_keys *
+Radius_msg_get_ms_keys(struct radius_msg *msg, struct radius_msg *sent_msg,
+		       u8 *secret, size_t secret_len);
+struct radius_attr_hdr *
+Radius_msg_add_attr_user_password(struct radius_msg *msg,
+				  u8 *data, size_t data_len, u8 *secret, size_t secret_len);
+int Radius_msg_get_attr(struct radius_msg *msg, u8 type, u8 *buf, size_t len);
+
+static inline int Radius_msg_add_attr_int32(struct radius_msg *msg, u8 type, u32 value)
+{
+	u32 val = htonl(value);
+	return Radius_msg_add_attr(msg, type, (u8 *) &val, 4) != NULL;
+}
+
+static inline int Radius_msg_get_attr_int32(struct radius_msg *msg, u8 type, u32 *value)
+{
+	u32 val;
+	int res;
+	res = Radius_msg_get_attr(msg, type, (u8 *) &val, 4);
+	if (res != 4)
+		return -1;
+
+	*value = ntohl(val);
+	return 0;
+}
+
+#endif /* RADIUS_H */
Index: /src/router/rt2860apd/radius_client.c
===================================================================
--- /src/router/rt2860apd/radius_client.c	(revision 10789)
+++ /src/router/rt2860apd/radius_client.c	(revision 10789)
@@ -0,0 +1,652 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	radius_client.c
+
+	Revision History:
+	Who 		When		  What
+	--------	----------	  ----------------------------------------------
+	Jan, Lee	Dec --2003	  modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+#include "rt2860apd.h"
+#include "radius.h"
+#include "radius_client.h"
+#include "eloop.h"
+
+/* Defaults for RADIUS retransmit values (exponential backoff) */
+#define RADIUS_CLIENT_FIRST_WAIT 1 /* seconds */
+#define RADIUS_CLIENT_MAX_WAIT 120 /* seconds */
+#define RADIUS_CLIENT_MAX_RETRIES 10 /* maximum number of retransmit attempts
+					  * before entry is removed from retransmit list */
+#define RADIUS_CLIENT_MAX_ENTRIES 30 /* maximum number of entries in retransmit
+					  * list (oldest will be removed, if this limit is exceeded) */
+#define RADIUS_CLIENT_NUM_FAILOVER 4 /* try to change RADIUS server after this
+					  * many failed retry attempts */
+
+static int
+Radius_change_server(rtapd *rtapd, struct hostapd_radius_server *nserv,
+			 struct hostapd_radius_server *oserv, int sock, int auth);
+
+static void Radius_client_msg_free(struct radius_msg_list *req)
+{
+	Radius_msg_free(req->msg);
+	free(req->msg);
+	free(req);
+}
+
+int Radius_client_register(rtapd *apd, RadiusType msg_type,
+			   RadiusRxResult (*handler)(rtapd *apd, struct radius_msg *msg, struct radius_msg *req,
+							 u8 *shared_secret, size_t shared_secret_len, void *data), void *data)
+{
+	struct radius_rx_handler **handlers, *newh;
+	size_t *num;
+
+	handlers = &apd->radius->auth_handlers;
+	num = &apd->radius->num_auth_handlers;
+
+	newh = (struct radius_rx_handler *)
+		realloc(*handlers, (*num + 1) * sizeof(struct radius_rx_handler));
+	if (newh == NULL)
+		return -1;
+
+	newh[*num].handler = handler;
+	newh[*num].data = data;
+	(*num)++;
+	*handlers = newh;
+
+	return 0;
+}
+
+static int Radius_client_retransmit(rtapd *rtapd, struct radius_msg_list *entry, time_t now)
+{
+	int s;
+
+#if MULTIPLE_RADIUS
+	s = rtapd->radius->mbss_auth_serv_sock[entry->ApIdx];
+#else
+	s = rtapd->radius->auth_serv_sock;
+#endif
+	/* retransmit; remove entry if too many attempts */
+	entry->attempts++;
+
+	if (send(s, entry->msg->buf, entry->msg->buf_used, 0) < 0)
+		perror("send[RADIUS]");
+
+	entry->next_try = now + entry->next_wait;
+	entry->next_wait *= 2;
+	if (entry->next_wait > RADIUS_CLIENT_MAX_WAIT)
+		entry->next_wait = RADIUS_CLIENT_MAX_WAIT;
+	if (entry->attempts >= RADIUS_CLIENT_MAX_RETRIES)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Removing un-ACKed RADIUS message due to too many failed retransmit attempts\n");
+		return 1;
+	}
+
+	return 0;
+}
+
+static void Radius_client_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	rtapd *rtapd = eloop_ctx;
+	time_t now, first;
+	struct radius_msg_list *entry, *prev, *tmp;
+#if MULTIPLE_RADIUS
+	int	i;
+	int mbss_auth_failover[MAX_MBSSID_NUM];
+#else
+	int auth_failover = 0;
+#endif
+
+#if MULTIPLE_RADIUS
+	for (i = 0; i < MAX_MBSSID_NUM; i++)
+		mbss_auth_failover[i] = 0;
+#endif
+
+	entry = rtapd->radius->msgs;
+	if (!entry)
+		return;
+
+	time(&now);
+	first = 0;
+
+	prev = NULL;
+	while (entry)
+	{
+		if (now >= entry->next_try && Radius_client_retransmit(rtapd, entry, now))
+		{
+			if (prev)
+				prev->next = entry->next;
+			else
+				rtapd->radius->msgs = entry->next;
+
+			tmp = entry;
+			entry = entry->next;
+			Radius_client_msg_free(tmp);
+			rtapd->radius->num_msgs--;
+			continue;
+		}
+
+		if (entry->attempts > RADIUS_CLIENT_NUM_FAILOVER)
+		{
+			if (entry->msg_type == RADIUS_AUTH)
+			{
+#if MULTIPLE_RADIUS
+				mbss_auth_failover[entry->ApIdx]++;
+#else
+				auth_failover++;
+#endif
+				DBGPRINT(RT_DEBUG_WARN, "Radius_client_timer : Failed retry attempts(%d) \n", RADIUS_CLIENT_NUM_FAILOVER);
+			}	
+		}
+
+		if (first == 0 || entry->next_try < first)
+			first = entry->next_try;
+
+		prev = entry;
+		entry = entry->next;
+	}
+
+	if (rtapd->radius->msgs)
+	{
+		if (first < now)
+			first = now;
+		eloop_register_timeout(first - now, 0, Radius_client_timer, rtapd, NULL);
+	}
+#if MULTIPLE_RADIUS
+	for (i = 0; i < rtapd->conf->SsidNum; i++)
+	{	
+		if (mbss_auth_failover[i] && rtapd->conf->mbss_num_auth_servers[i] > 1)
+		{
+			struct hostapd_radius_server *next, *old;
+			old = rtapd->conf->mbss_auth_server[i];
+
+			next = old + 1;
+			if (next > &(rtapd->conf->mbss_auth_servers[i][rtapd->conf->mbss_num_auth_servers[i]- 1]))
+				next = rtapd->conf->mbss_auth_servers[i];
+			rtapd->conf->mbss_auth_server[i] = next;
+			Radius_change_server(rtapd, next, old, rtapd->radius->mbss_auth_serv_sock[i], 1);
+			DBGPRINT(RT_DEBUG_WARN, "Radius_client_timer : ready to change RADIUS server for %s%d\n", rtapd->prefix_wlan_name, i);
+		}	
+	}
+#else
+	if (auth_failover && rtapd->conf->num_auth_servers > 1)
+	{
+		struct hostapd_radius_server *next, *old;
+		old = rtapd->conf->auth_server;
+
+		next = old + 1;
+		if (next > &(rtapd->conf->auth_servers[rtapd->conf->num_auth_servers - 1]))
+			next = rtapd->conf->auth_servers;
+		rtapd->conf->auth_server = next;
+		Radius_change_server(rtapd, next, old, rtapd->radius->auth_serv_sock, 1);
+		DBGPRINT(RT_DEBUG_WARN, "==> Radius_client_timer : ready to change RADIUS server \n");	
+	}
+#endif			
+}
+
+static void Radius_client_list_add(rtapd *rtapd, struct radius_msg *msg,
+				   RadiusType msg_type, u8 *shared_secret, size_t shared_secret_len, u8 ApIdx)
+{
+	struct radius_msg_list *entry, *prev;
+
+	if (eloop_terminated())
+	{
+		/* No point in adding entries to retransmit queue since event
+		 * loop has already been terminated. */
+		DBGPRINT(RT_DEBUG_TRACE,"eloop_terminate \n");
+		Radius_msg_free(msg);
+		free(msg);
+		return;
+	}
+
+	entry = malloc(sizeof(*entry));
+	if (entry == NULL)
+	{
+		DBGPRINT(RT_DEBUG_TRACE,"Failed to add RADIUS packet into retransmit list\n");
+		Radius_msg_free(msg);
+		free(msg);
+		return;
+	}
+
+	memset(entry, 0, sizeof(*entry));
+	entry->msg = msg;
+	entry->msg_type = msg_type;
+	entry->shared_secret = shared_secret;
+	entry->shared_secret_len = shared_secret_len;
+	entry->ApIdx = ApIdx;
+	time(&entry->first_try);
+	entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+	entry->attempts = 1;
+	entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+
+	if (!rtapd->radius->msgs)
+	{		
+		eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, Radius_client_timer, rtapd, NULL);
+	}
+
+	entry->next = rtapd->radius->msgs;
+	rtapd->radius->msgs = entry;
+
+	if (rtapd->radius->num_msgs >= RADIUS_CLIENT_MAX_ENTRIES)
+	{
+		DBGPRINT(RT_DEBUG_TRACE,"Removing the oldest un-ACKed RADIUS packet due to retransmit list limits.\n");
+		prev = NULL;
+		while (entry->next)
+		{
+			prev = entry;
+			entry = entry->next;
+		}
+		if (prev)
+		{
+			prev->next = NULL;
+			Radius_client_msg_free(entry);
+		}
+	} else
+		rtapd->radius->num_msgs++;
+}
+
+int Radius_client_send(rtapd *rtapd, struct radius_msg *msg, RadiusType msg_type, u8 ApIdx)
+{
+	u8 *shared_secret;
+	size_t shared_secret_len;
+	char *name;
+	int s, res = 0;
+
+#if MULTIPLE_RADIUS
+	shared_secret = rtapd->conf->mbss_auth_server[ApIdx]->shared_secret;
+	shared_secret_len = rtapd->conf->mbss_auth_server[ApIdx]->shared_secret_len;
+	s = rtapd->radius->mbss_auth_serv_sock[ApIdx];
+	DBGPRINT(RT_DEBUG_TRACE, "Send packet to server (%s)\n",
+						inet_ntoa(rtapd->conf->mbss_auth_server[ApIdx]->addr));
+#else
+	shared_secret = rtapd->conf->auth_server->shared_secret;
+	shared_secret_len = rtapd->conf->auth_server->shared_secret_len;
+	s = rtapd->radius->auth_serv_sock;
+#endif	
+	Radius_msg_finish(msg, shared_secret, shared_secret_len);
+	name = "authentication";
+
+	res = send(s, msg->buf, msg->buf_used, 0);
+	if (res < 0)
+		perror("send[RADIUS]");
+
+	Radius_client_list_add(rtapd, msg, msg_type, shared_secret, shared_secret_len, ApIdx);
+
+	return res;
+}
+
+static void Radius_client_receive(int sock, void *eloop_ctx, void *sock_ctx)
+{
+	rtapd *rtapd = eloop_ctx;
+	RadiusType msg_type = (RadiusType) sock_ctx;
+	int len, i,len_80211hdr=24;
+	unsigned char buf[3000];
+	struct radius_msg *msg;
+	struct radius_rx_handler *handlers;
+	size_t num_handlers;
+	struct radius_msg_list *req, *prev_req;
+
+	DBGPRINT(RT_DEBUG_TRACE, "RADIUS_CLIENT_RECEIVE : msg_type= %d \n", msg_type);
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0)
+	{
+		perror("recv[RADIUS]");
+		return;
+	}
+	if (len == sizeof(buf))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Possibly too long UDP frame for our buffer - dropping it\n");
+		return;
+	}
+	
+	if(buf[0]!=0xff)
+	{
+		int i;
+		DBGPRINT(RT_DEBUG_INFO,"  r_dump %d bytes:",len);
+		for (i = 0; i < len_80211hdr; i++)
+			DBGPRINT(RT_DEBUG_INFO," %02x", buf[i]);
+		DBGPRINT(RT_DEBUG_INFO,"\n");
+	}
+
+	msg = Radius_msg_parse(buf, len);
+	if (msg == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Parsing incoming RADIUS frame failed\n");
+		return;
+	}
+
+	handlers = rtapd->radius->auth_handlers;
+	num_handlers = rtapd->radius->num_auth_handlers;
+
+	prev_req = NULL;
+	req = rtapd->radius->msgs;
+	while (req)
+	{
+		/* TODO: also match by src addr:port of the packet when using
+		 * alternative RADIUS servers (?) */
+		if (req->msg_type == msg_type && req->msg->hdr->identifier == msg->hdr->identifier)
+			break;
+
+		prev_req = req;
+		req = req->next;
+	}
+
+	if (req == NULL)
+	{
+		goto fail;
+	}
+
+	/* Remove ACKed RADIUS packet from retransmit list */
+	if (prev_req)
+		prev_req->next = req->next;
+	else
+		rtapd->radius->msgs = req->next;
+	rtapd->radius->num_msgs--;
+
+	for (i = 0; i < num_handlers; i++)
+	{
+		RadiusRxResult res;
+		res = handlers[i].handler(rtapd, msg, req->msg, req->shared_secret, req->shared_secret_len, handlers[i].data);
+		switch (res) 
+		{
+			case RADIUS_RX_PROCESSED:
+			Radius_msg_free(msg);
+			free(msg);
+			/* continue */
+			case RADIUS_RX_QUEUED:
+			Radius_client_msg_free(req);
+			return;
+			case RADIUS_RX_UNKNOWN:
+			/* continue with next handler */
+			break;
+		}
+	}
+
+	DBGPRINT(RT_DEBUG_ERROR,"No RADIUS RX handler found (type=%d code=%d id=%d) - dropping "
+		   "packet\n", msg_type, msg->hdr->code, msg->hdr->identifier);
+	Radius_client_msg_free(req);
+
+ fail:
+	Radius_msg_free(msg);
+	free(msg);
+}
+
+u8 Radius_client_get_id(rtapd *rtapd)
+{
+	struct radius_msg_list *entry, *prev, *remove;
+	u8 id = rtapd->radius->next_radius_identifier++;
+
+	/* remove entries with matching id from retransmit list to avoid
+	 * using new reply from the RADIUS server with an old request */
+	entry = rtapd->radius->msgs;
+	prev = NULL;
+	while (entry)
+	{
+		if (entry->msg->hdr->identifier == id)
+		{
+			if (prev)
+				prev->next = entry->next;
+			else
+				rtapd->radius->msgs = entry->next;
+			remove = entry;
+		} else
+			remove = NULL;
+		prev = entry;
+		entry = entry->next;
+
+		if (remove)
+			Radius_client_msg_free(remove);
+	}
+
+	return id;
+}
+
+void Radius_client_flush(rtapd *rtapd)
+{
+	struct radius_msg_list *entry, *prev;
+
+	if (!rtapd->radius)
+		return;
+
+	eloop_cancel_timeout(Radius_client_timer, rtapd, NULL);
+
+	entry = rtapd->radius->msgs;
+	rtapd->radius->msgs = NULL;
+	rtapd->radius->num_msgs = 0;
+	while (entry)
+	{
+		prev = entry;
+		entry = entry->next;
+		Radius_client_msg_free(prev);
+	}
+}
+
+static int
+Radius_change_server(rtapd *rtapd, struct hostapd_radius_server *nserv,
+			 struct hostapd_radius_server *oserv, int sock, int auth)
+{
+	struct sockaddr_in serv;
+	if (!oserv || nserv->shared_secret_len != oserv->shared_secret_len ||
+		memcmp(nserv->shared_secret, oserv->shared_secret, nserv->shared_secret_len) != 0)
+	{
+		/* Pending RADIUS packets used different shared
+		 * secret, so they would need to be modified. Could
+		 * update all message authenticators and
+		 * User-Passwords, etc. and retry with new server. For
+		 * now, just drop all pending packets. */
+		Radius_client_flush(rtapd);
+	} 
+	else
+	{
+		/* Reset retry counters for the new server */
+		struct radius_msg_list *entry;
+		entry = rtapd->radius->msgs;
+		while (entry)
+		{
+			entry->next_try = entry->first_try + RADIUS_CLIENT_FIRST_WAIT;
+			entry->attempts = 0;
+			entry->next_wait = RADIUS_CLIENT_FIRST_WAIT * 2;
+			entry = entry->next;
+		}
+		if (rtapd->radius->msgs)
+		{
+			eloop_cancel_timeout(Radius_client_timer, rtapd, NULL);
+			eloop_register_timeout(RADIUS_CLIENT_FIRST_WAIT, 0, Radius_client_timer, rtapd, NULL);
+		}
+	}
+	// bind before connect to assign local port
+/*Comment by rory
+	memset(&serv, 0, sizeof(serv));
+	port = 2048;
+	serv.sin_family = AF_INET;
+	//serv.sin_addr.s_addr = inet_addr("192.168.1.138");
+	serv.sin_addr.s_addr = rtapd->conf->own_ip_addr.s_addr;
+	serv.sin_port = htons(port);
+	if (bind(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0)
+	{
+		perror("bind");
+		return -1;
+	}*/
+	memset(&serv, 0, sizeof(serv));
+	serv.sin_family = AF_INET;
+	serv.sin_addr.s_addr = nserv->addr.s_addr;
+	serv.sin_port = htons(nserv->port);
+	if (connect(sock, (struct sockaddr *) &serv, sizeof(serv)) < 0)
+	{
+		perror("connect[radius]");
+		return -1;
+	}
+	DBGPRINT(RT_DEBUG_TRACE, "Radius_change_server :: Connect to Radius Server(%s)\n", inet_ntoa(nserv->addr));
+	return 0;
+}
+
+static void Radius_retry_primary_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	rtapd *rtapd = eloop_ctx;
+	struct hostapd_radius_server *oserv;
+
+	DBGPRINT(RT_DEBUG_TRACE, "RUN Radius_retry_primary_timer.....\n");
+#if MULTIPLE_RADIUS
+	int	i;
+
+	for (i = 0; i < rtapd->conf->SsidNum; i++)
+	{
+		if (rtapd->radius->mbss_auth_serv_sock[i] >= 0 && rtapd->conf->mbss_auth_servers[i] &&
+			rtapd->conf->mbss_auth_server[i] != rtapd->conf->mbss_auth_servers[i])
+		{
+			oserv = rtapd->conf->mbss_auth_server[i];
+			rtapd->conf->mbss_auth_server[i] = rtapd->conf->mbss_auth_servers[i];
+			Radius_change_server(rtapd, rtapd->conf->mbss_auth_server[i], oserv, rtapd->radius->mbss_auth_serv_sock[i], 1);
+		}
+	}
+#else
+	if (rtapd->radius->auth_serv_sock >= 0 && rtapd->conf->auth_servers &&
+		rtapd->conf->auth_server != rtapd->conf->auth_servers)
+	{
+		oserv = rtapd->conf->auth_server;
+		rtapd->conf->auth_server = rtapd->conf->auth_servers;
+		Radius_change_server(rtapd, rtapd->conf->auth_server, oserv, rtapd->radius->auth_serv_sock, 1);
+	}
+#endif
+
+	if (rtapd->conf->radius_retry_primary_interval)
+		eloop_register_timeout(rtapd->conf->radius_retry_primary_interval, 0, Radius_retry_primary_timer, rtapd, NULL);
+}
+
+#if MULTIPLE_RADIUS
+static int Radius_client_init_auth(rtapd *rtapd, int apidx)
+{		
+	if (rtapd->conf->mbss_auth_server[apidx]->addr.s_addr == 0)
+	{
+		DBGPRINT(RT_DEBUG_WARN, "Radius_client_init_auth: can't create auth RADIUS socket for %s%d (it's invalid IP)\n", rtapd->prefix_wlan_name, apidx);
+		return -1;
+	}
+
+	rtapd->radius->mbss_auth_serv_sock[apidx] = socket(PF_INET, SOCK_DGRAM, 0);
+	if (rtapd->radius->mbss_auth_serv_sock[apidx] < 0)
+	{
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		return -1;
+	}
+
+	if (Radius_change_server(rtapd, rtapd->conf->mbss_auth_server[apidx], NULL, rtapd->radius->mbss_auth_serv_sock[apidx], 1))
+		return -1;
+
+	if (eloop_register_read_sock(rtapd->radius->mbss_auth_serv_sock[apidx], Radius_client_receive, rtapd, (void *) RADIUS_AUTH))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket for authentication server - iface-%d\n", apidx);
+		return -1;
+	}
+	return 0;
+}
+#else
+static int Radius_client_init_auth(rtapd *rtapd)
+{
+	rtapd->radius->auth_serv_sock = socket(PF_INET, SOCK_DGRAM, 0);
+	if (rtapd->radius->auth_serv_sock < 0)
+	{
+		perror("socket[PF_INET,SOCK_DGRAM]");
+		return -1;
+	}
+
+	Radius_change_server(rtapd, rtapd->conf->auth_server, NULL, rtapd->radius->auth_serv_sock, 1);
+
+	if (eloop_register_read_sock(rtapd->radius->auth_serv_sock, Radius_client_receive, rtapd, (void *) RADIUS_AUTH))
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket for authentication server\n");
+		return -1;
+	}
+	return 0;
+}
+#endif
+
+
+int Radius_client_init(rtapd *rtapd)
+{
+#if MULTIPLE_RADIUS
+	int	i, ready_sock_count = 0, bReInit = 1;
+#endif
+
+	if (rtapd->radius == NULL)
+	{		 
+		rtapd->radius = malloc(sizeof(struct radius_client_data));
+		if (rtapd->radius == NULL)
+			return -1;
+		
+		memset(rtapd->radius, 0, sizeof(struct radius_client_data));
+
+#if MULTIPLE_RADIUS
+		for (i = 0; i < MAX_MBSSID_NUM; i++)
+			rtapd->radius->mbss_auth_serv_sock[i] = -1;
+
+		bReInit= 0;
+#else
+		rtapd->radius->auth_serv_sock = -1;
+#endif
+	}
+	
+#if MULTIPLE_RADIUS	
+	// Create socket for auth RADIUS
+	for (i = 0; i < rtapd->conf->SsidNum; i++)
+	{
+		if (rtapd->radius->mbss_auth_serv_sock[i] < 0)
+		{
+			if (rtapd->conf->mbss_auth_server[i] && (!Radius_client_init_auth(rtapd, i)))
+					ready_sock_count++;		
+		}
+		else
+			ready_sock_count++;
+	}
+	
+	if (ready_sock_count == 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "Radius_client_init : no any auth RADIUS socket ready \n");
+		return -1;
+	}
+	else
+		DBGPRINT(RT_DEBUG_TRACE, "Radius_client_init : ready_sock_count %d \n", ready_sock_count);
+
+	if (rtapd->conf->radius_retry_primary_interval && !bReInit && ready_sock_count > 0)
+		eloop_register_timeout(rtapd->conf->radius_retry_primary_interval, 0, Radius_retry_primary_timer, rtapd, NULL);
+#else
+	if( rtapd->radius->auth_serv_sock < 0)
+	{
+		if (rtapd->conf->auth_server && Radius_client_init_auth(rtapd))
+			return -1;
+		if (rtapd->conf->radius_retry_primary_interval)
+			eloop_register_timeout(rtapd->conf->radius_retry_primary_interval, 0, Radius_retry_primary_timer, rtapd, NULL);
+	}
+#endif	
+	return 0;
+}
+
+void Radius_client_deinit(rtapd *rtapd)
+{
+	if (!rtapd->radius)
+		return;
+
+	eloop_cancel_timeout(Radius_retry_primary_timer, rtapd, NULL);
+
+	Radius_client_flush(rtapd);
+	free(rtapd->radius->auth_handlers);
+	free(rtapd->radius);
+	rtapd->radius = NULL;
+}
+
Index: /src/router/rt2860apd/radius_client.h
===================================================================
--- /src/router/rt2860apd/radius_client.h	(revision 10789)
+++ /src/router/rt2860apd/radius_client.h	(revision 10789)
@@ -0,0 +1,66 @@
+#ifndef RADIUS_CLIENT_H
+#define RADIUS_CLIENT_H
+
+typedef enum {
+	RADIUS_AUTH
+} RadiusType;
+
+/* RADIUS message retransmit list */
+struct radius_msg_list {
+	struct radius_msg *msg;
+	RadiusType msg_type;
+	time_t first_try;
+	time_t next_try;
+	int attempts;
+	int next_wait;
+
+	u8 *shared_secret;
+	size_t shared_secret_len;
+
+	u8	ApIdx;	// Multiple SSID interface
+	/* TODO: server config with failover to backup server(s) */
+
+	struct radius_msg_list *next;
+};
+
+
+typedef enum {
+	RADIUS_RX_PROCESSED,
+	RADIUS_RX_QUEUED,
+	RADIUS_RX_UNKNOWN
+} RadiusRxResult;
+
+struct radius_rx_handler {
+	RadiusRxResult (*handler)(rtapd *apd, struct radius_msg *msg, struct radius_msg *req,
+				  u8 *shared_secret, size_t shared_secret_len, void *data);
+	void *data;
+};
+
+struct radius_client_data {
+
+#if MULTIPLE_RADIUS
+	int mbss_auth_serv_sock[MAX_MBSSID_NUM]; /* socket for authentication RADIUS messages */
+#else
+	int auth_serv_sock; /* socket for authentication RADIUS messages */
+#endif
+
+	struct radius_rx_handler *auth_handlers;
+	size_t num_auth_handlers;
+
+	struct radius_msg_list *msgs;
+	size_t num_msgs;
+
+	u8 next_radius_identifier;
+
+};
+
+int Radius_client_register(rtapd *apd, RadiusType msg_type,
+			   RadiusRxResult (*handler) (rtapd *apd,  struct radius_msg *msg, struct radius_msg *req,
+			    u8 *shared_secret, size_t shared_secret_len, void *data),  void *data);
+int Radius_client_send(rtapd *rtapd, struct radius_msg *msg, RadiusType msg_type, u8 ApIdx);
+u8 Radius_client_get_id(rtapd *rtapd);
+void Radius_client_flush(rtapd *rtapd);
+int Radius_client_init(rtapd *rtapd);
+void Radius_client_deinit(rtapd *rtapd);
+
+#endif /* RADIUS_CLIENT_H */
Index: /src/router/rt2860apd/rt2860apd.c
===================================================================
--- /src/router/rt2860apd/rt2860apd.c	(revision 10789)
+++ /src/router/rt2860apd/rt2860apd.c	(revision 10789)
@@ -0,0 +1,693 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	rt2860apd.c
+
+	Revision History:
+	Who         When          What
+	--------    ----------    ----------------------------------------------
+	Jan, Lee    Dec --2003    modified
+
+*/
+
+#include <net/if_arp.h>
+#include <netpacket/packet.h>
+#include <sys/ioctl.h>
+#include <netinet/in.h>
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <netinet/in.h>
+#include <string.h>
+#include <signal.h>
+#include <time.h>
+#include <syslog.h>
+#include <stdarg.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <linux/if.h>			/* for IFNAMSIZ and co... */
+#include <linux/wireless.h>
+
+#include "rt2860apd.h"
+#include "eloop.h"
+#include "ieee802_1x.h"
+#include "eapol_sm.h"
+#include "ap.h"
+#include "sta_info.h"
+#include "radius_client.h"
+#include "config.h"
+
+#define RT2860AP_SYSTEM_PATH	"/tmp/RT2860.dat"
+
+
+struct hapd_interfaces {
+	int count;
+	rtapd **rtapd;
+};
+
+u32    RTDebugLevel = RT_DEBUG_ERROR;
+
+/*
+	========================================================================
+	
+	Routine Description:
+		Compare two memory block
+
+	Arguments:
+		Adapter						Pointer to our adapter
+
+	Return Value:
+		0:			memory is equal
+		1:			pSrc1 memory is larger
+		2:			pSrc2 memory is larger
+
+	Note:
+		
+	========================================================================
+*/
+u16	RTMPCompareMemory(void *pSrc1,void *pSrc2, u16 Length)
+{
+	char *pMem1;
+	char *pMem2;
+	u16	Index = 0;
+
+	pMem1 = (char*) pSrc1;
+	pMem2 = (char*) pSrc2;
+
+	for (Index = 0; Index < Length; Index++)
+	{
+		if (pMem1[Index] > pMem2[Index])
+			return (1);
+		else if (pMem1[Index] < pMem2[Index])
+			return (2);
+	}
+
+	// Equal
+	return (0);
+}
+
+int RT_ioctl(int sid, int param, char  *data, int data_len, char *prefix_name, unsigned char apidx, int flags)
+{
+    //char			name[12];
+    int				ret = 1;
+    struct iwreq	wrq;
+
+    //sprintf(name, "ra%d", apidx);
+    //name[3] = '\0';
+
+    //strcpy(wrq.ifr_name, name);
+	sprintf(wrq.ifr_name, "%s%d", prefix_name, apidx);
+
+    wrq.u.data.flags = flags;
+	wrq.u.data.length = data_len;
+    wrq.u.data.pointer = (caddr_t) data;
+
+    ret = ioctl(sid, param, &wrq);	
+    
+    return ret;
+}
+
+static void Handle_read(int sock, void *eloop_ctx, void *sock_ctx)
+{                              
+	rtapd *rtapd = eloop_ctx;
+	int len;
+	unsigned char buf[3000];
+	u8 *sa, *da, *pos, *pos_vlan, apidx=0, isVlanTag=0;
+	u16 ethertype,i;
+    priv_rec *rec;
+    size_t left;
+
+	len = recv(sock, buf, sizeof(buf), 0);
+	if (len < 0)
+    {
+		perror("recv");
+        Handle_term(15,eloop_ctx,sock_ctx);
+        return;
+	}
+
+	rec = (priv_rec*)buf;
+    left = len -sizeof(*rec)+1;
+	if (left <= 0)
+	{
+		DBGPRINT(RT_DEBUG_ERROR," too short recv\n");
+		return;
+	}
+						
+    sa = rec->saddr;
+	da = rec->daddr;
+	ethertype = rec->ethtype[0] << 8;
+	ethertype |= rec->ethtype[1];
+			
+#ifdef ETH_P_VLAN
+	if(ethertype == ETH_P_VLAN)
+    {
+    	pos_vlan = rec->xframe;
+
+        if(left >= 4)
+        {
+			ethertype = *(pos_vlan+2) << 8;
+			ethertype |= *(pos_vlan+3);
+		}
+			
+		if((ethertype == ETH_P_PRE_AUTH) || (ethertype == ETH_P_PAE))
+		{
+			isVlanTag = 1;
+			DBGPRINT(RT_DEBUG_TRACE,"Recv vlan tag for 802.1x. (%02x %02x)\n", *(pos_vlan), *(pos_vlan+1));		
+		}
+    }
+#endif
+	
+	if ((ethertype == ETH_P_PRE_AUTH) || (ethertype == ETH_P_PAE))	
+    {
+        // search this packet is coming from which interface
+		for (i = 0; i < rtapd->conf->SsidNum; i++)
+		{		    
+			if (memcmp(da, rtapd->own_addr[i], 6) == 0)
+		    {
+		        apidx = i;		        
+		        break;
+		    }
+		}
+		if(i >= rtapd->conf->SsidNum)
+		{
+	        DBGPRINT(RT_DEBUG_WARN,"sock not found (sock=%d) in %sX!!!\n", sock, rtapd->prefix_wlan_name);
+		    return;
+		}
+
+		if (ethertype == ETH_P_PRE_AUTH)
+		{
+			DBGPRINT(RT_DEBUG_TRACE, "Receive WPA2 pre-auth packet for %s%d\n", rtapd->prefix_wlan_name, apidx);
+		}
+		else
+		{
+			DBGPRINT(RT_DEBUG_TRACE, "Receive EAP packet for %s%d\n", rtapd->prefix_wlan_name, apidx);
+		}
+    }
+	else
+	{
+		DBGPRINT(RT_DEBUG_ERROR, "Receive unexpected ethertype 0x%04X!!!\n", ethertype);
+		return;
+	}
+
+    pos = rec->xframe;
+    
+    //strip 4 bytes for valn tag
+    if(isVlanTag)
+    {
+    	pos += 4;
+    	left -= 4;
+	}
+	if (len < 52 )
+    {
+		DBGPRINT(RT_DEBUG_INFO,"Handle_read :: handle_short_frame: (len=%d, left=%d)\n", len,left);
+        for(i = 0; i < left; i++)
+		DBGPRINT(RT_DEBUG_INFO," %x", *(pos+i));
+		DBGPRINT(RT_DEBUG_INFO,"\n");
+	}
+    
+    ieee802_1x_receive(rtapd, sa, &apidx, pos, left, ethertype);
+}
+
+int Apd_init_sockets(rtapd *rtapd)
+{
+    struct ifreq ifr;
+	struct sockaddr_ll addr;
+    int i;
+
+	// 1. init ethernet interface socket for pre-auth
+	rtapd->eth_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PRE_AUTH));
+    if (rtapd->eth_sock < 0)
+    {
+        perror("socket[PF_PACKET,SOCK_RAW](eth_sock)");
+		return -1;
+    }
+
+    if (eloop_register_read_sock(rtapd->eth_sock, Handle_read, rtapd, NULL))
+    {
+        DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket(eth_sock)\n");
+		return -1;
+    }
+	
+    memset(&ifr, 0, sizeof(ifr));
+    memcpy(ifr.ifr_name, rtapd->conf->PreAuthifname, strlen(rtapd->conf->PreAuthifname));
+    DBGPRINT(RT_DEBUG_TRACE,"Register pre-auth interface as (%s)\n", ifr.ifr_name);
+
+    if (ioctl(rtapd->eth_sock, SIOCGIFINDEX, &ifr) != 0)
+    {
+        perror("ioctl(SIOCGIFHWADDR)(eth_sock)");
+        return -1;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+	addr.sll_family = AF_PACKET;
+	addr.sll_ifindex = ifr.ifr_ifindex;
+	if (bind(rtapd->eth_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+    {
+		perror("bind");
+		return -1;
+	}
+    DBGPRINT(RT_DEBUG_TRACE,"Opening pre-auth raw packet socket with %s(socknum=%d,ifindex=%d)\n", ifr.ifr_name, rtapd->eth_sock, addr.sll_ifindex);
+
+	// 2. init wireless interface socket for EAP negotiation      		
+    rtapd->wlan_sock = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_PAE));
+        
+    if (rtapd->wlan_sock < 0)
+        {
+            perror("socket[PF_PACKET,SOCK_RAW]");
+    		return -1;
+        }
+
+    if (eloop_register_read_sock(rtapd->wlan_sock, Handle_read, rtapd, NULL))
+        {
+            DBGPRINT(RT_DEBUG_ERROR,"Could not register read socket\n");
+    		return -1;
+        }
+	
+        memset(&ifr, 0, sizeof(ifr));
+	strcpy(ifr.ifr_name, rtapd->conf->EAPifname);
+	DBGPRINT(RT_DEBUG_TRACE,"Register EAP interface as (%s)\n", ifr.ifr_name);
+
+    if (ioctl(rtapd->wlan_sock, SIOCGIFINDEX, &ifr) != 0)
+        {
+            perror("ioctl(SIOCGIFHWADDR)");
+            return -1;
+        }
+
+        memset(&addr, 0, sizeof(addr));
+    	addr.sll_family = AF_PACKET;
+    	addr.sll_ifindex = ifr.ifr_ifindex;
+    if (bind(rtapd->wlan_sock, (struct sockaddr *) &addr, sizeof(addr)) < 0)
+        {
+    		perror("bind");
+    		return -1;
+    	}
+    DBGPRINT(RT_DEBUG_TRACE, "Opening EAP raw packet socket with br0 (socknum=%d,ifindex=%d)\n", rtapd->wlan_sock, addr.sll_ifindex);
+    
+	// 3. Get wireless interface MAC address
+    for(i = 0; i < rtapd->conf->SsidNum; i++)
+    {
+		int s = -1;
+	
+		s = socket(AF_INET, SOCK_DGRAM, 0); 
+
+		if (s < 0)
+        {
+            perror("socket[AF_INET,SOCK_DGRAM]");
+    		return -1;
+        }
+    
+    	memset(&ifr, 0, sizeof(ifr));
+		sprintf(ifr.ifr_name, "%s%d",rtapd->prefix_wlan_name, i);
+    	//sprintf(ifr.ifr_name, "ra%d", i);
+    
+		// Get MAC address
+    	if (ioctl(s, SIOCGIFHWADDR, &ifr) != 0)
+    	{
+        	perror("ioctl(SIOCGIFHWADDR)");
+			close(s);
+        	return -1;
+    	}
+
+    	DBGPRINT(RT_DEBUG_INFO," Device %s has ifr.ifr_hwaddr.sa_family %d\n",ifr.ifr_name, ifr.ifr_hwaddr.sa_family);
+		if (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER)
+    	{
+			DBGPRINT(RT_DEBUG_ERROR,"IF-%s : Invalid HW-addr family 0x%04x\n", ifr.ifr_name, ifr.ifr_hwaddr.sa_family);
+			close(s);
+			return -1;
+		}
+
+		memcpy(rtapd->own_addr[i], ifr.ifr_hwaddr.sa_data, ETH_ALEN);
+    	DBGPRINT(RT_DEBUG_TRACE, "IF-%s MAC Address = " MACSTR "\n", ifr.ifr_name, MAC2STR(rtapd->own_addr[i]));
+
+		close(s);
+	}	
+
+
+	return 0;
+}
+
+static void Apd_cleanup(rtapd *rtapd)
+{
+
+	if (rtapd->wlan_sock >= 0)
+		close(rtapd->wlan_sock);	
+	if (rtapd->ioctl_sock >= 0)
+		close(rtapd->ioctl_sock);
+	if (rtapd->eth_sock >= 0)
+		close(rtapd->eth_sock);
+    
+	Radius_client_deinit(rtapd);
+
+	Config_free(rtapd->conf);
+	rtapd->conf = NULL;
+
+	free(rtapd->prefix_wlan_name);
+}
+
+static int Apd_setup_interface(rtapd *rtapd)
+{   
+#if MULTIPLE_RADIUS
+	int		i;
+#endif
+
+	if (Apd_init_sockets(rtapd))
+		return -1;    
+    
+	if (Radius_client_init(rtapd))
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"RADIUS client initialization failed.\n");
+		return -1;
+	}
+
+	if (ieee802_1x_init(rtapd))
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"IEEE 802.1X initialization failed.\n");
+		return -1;
+	}
+#if MULTIPLE_RADIUS
+	for (i = 0; i < rtapd->conf->SsidNum; i++)
+		DBGPRINT(RT_DEBUG_TRACE,"auth_serv_sock[%d] = %d\n", i, rtapd->radius->mbss_auth_serv_sock[i]);
+#else	
+    DBGPRINT(RT_DEBUG_TRACE,"rtapd->radius->auth_serv_sock = %d\n",rtapd->radius->auth_serv_sock);
+#endif
+
+	return 0;
+}
+
+static void usage(void)
+{
+	DBGPRINT(RT_DEBUG_OFF, "USAGE :  	rt2860apd [optional command]\n");
+	DBGPRINT(RT_DEBUG_OFF, "[optional command] : \n");
+	DBGPRINT(RT_DEBUG_OFF, "-i <card_number> : indicate which card is used\n");
+	DBGPRINT(RT_DEBUG_OFF, "-d <debug_level> : set debug level\n");
+	
+	exit(1);
+}
+
+static rtapd * Apd_init(const char *prefix_name)
+{
+	rtapd *rtapd;
+
+	rtapd = malloc(sizeof(*rtapd));
+	if (rtapd == NULL)
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for rtapd data\n");
+		goto fail;
+	}
+	memset(rtapd, 0, sizeof(*rtapd));
+
+	rtapd->prefix_wlan_name = strdup(prefix_name);
+	if (rtapd->prefix_wlan_name == NULL)
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for prefix_wlan_name\n");
+		goto fail;
+	}
+
+    // init ioctl socket
+    rtapd->ioctl_sock = socket(PF_INET, SOCK_DGRAM, 0);
+    if (rtapd->ioctl_sock < 0)
+    {
+	    DBGPRINT(RT_DEBUG_ERROR,"Could not init ioctl socket \n");	
+	    goto fail;
+    }
+   
+
+	rtapd->conf = Config_read(rtapd->ioctl_sock, rtapd->prefix_wlan_name);
+	if (rtapd->conf == NULL)
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"Could not allocate memory for rtapd->conf \n");
+		goto fail;
+	}
+
+	rtapd->wlan_sock = -1;
+	rtapd->eth_sock = -1;
+
+	return rtapd;
+
+fail:
+	if (rtapd) {		
+		if (rtapd->conf)
+			Config_free(rtapd->conf);
+
+		if (rtapd->prefix_wlan_name)
+			free(rtapd->prefix_wlan_name);
+
+		free(rtapd);
+	}
+	return NULL;
+	
+}
+
+static void Handle_usr1(int sig, void *eloop_ctx, void *signal_ctx)
+{
+	struct hapd_interfaces *rtapds = (struct hapd_interfaces *) eloop_ctx;
+	struct rtapd_config *newconf;
+	int i;
+
+	DBGPRINT(RT_DEBUG_TRACE,"Reloading configuration\n");
+	for (i = 0; i < rtapds->count; i++)
+    {
+		rtapd *rtapd = rtapds->rtapd[i];
+		newconf = Config_read(rtapd->ioctl_sock, rtapd->prefix_wlan_name);
+		if (newconf == NULL)
+        {
+			DBGPRINT(RT_DEBUG_ERROR,"Failed to read new configuration file - continuing with old.\n");
+			continue;
+		}
+
+		/* TODO: update dynamic data based on changed configuration
+		 * items (e.g., open/close sockets, remove stations added to
+		 * deny list, etc.) */
+		Radius_client_flush(rtapd);
+		Config_free(rtapd->conf);
+		rtapd->conf = newconf;
+        Apd_free_stas(rtapd);
+
+/* when reStartAP, no need to reallocate sock
+        for (i = 0; i < rtapd->conf->SsidNum; i++)
+        {
+            if (rtapd->sock[i] >= 0)
+                close(rtapd->sock[i]);
+                
+    	    rtapd->sock[i] = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL));
+    	    if (rtapd->sock[i] < 0)
+            {
+    		    perror("socket[PF_PACKET,SOCK_RAW]");
+    		    return;
+    	    }
+        }*/
+
+	    if (Radius_client_init(rtapd))
+        {
+		    DBGPRINT(RT_DEBUG_ERROR,"RADIUS client initialization failed.\n");
+		    return;
+	    }
+#if MULTIPLE_RADIUS
+		for (i = 0; i < rtapd->conf->SsidNum; i++)
+			DBGPRINT(RT_DEBUG_TRACE, "auth_serv_sock[%d] = %d\n", i, rtapd->radius->mbss_auth_serv_sock[i]);
+#else
+        DBGPRINT(RT_DEBUG_TRACE,"rtapd->radius->auth_serv_sock = %d\n",rtapd->radius->auth_serv_sock);
+#endif
+	}
+}
+
+void Handle_term(int sig, void *eloop_ctx, void *signal_ctx)
+{
+	//FILE    *f;
+	//char    buf[256], *pos;
+	//int     line = 0, i;
+    //int     filesize,cur = 0;
+    //char    *ini_buffer;             /* storage area for .INI file */
+
+	DBGPRINT(RT_DEBUG_ERROR,"Signal %d received - terminating\n", sig);
+
+#if 0
+	f = fopen(RT2860AP_SYSTEM_PATH, "r");
+	if (f == NULL)
+    {
+		DBGPRINT(RT_DEBUG_ERROR,"Could not open configuration file '%s' for reading.\n", RT2860AP_SYSTEM_PATH);
+		return;
+	}
+
+    if ((fseek(f, 0, SEEK_END))!=0)
+        return;
+    filesize=ftell(f);
+	DBGPRINT(RT_DEBUG_ERROR,"filesize %d   - terminating\n", filesize);
+
+    if ((ini_buffer=(char *)malloc(filesize + 1 ))==NULL)
+        return;   //out of memory
+    fseek(f,0,SEEK_SET);
+    fread(ini_buffer, filesize, 1, f);
+    fseek(f,0,SEEK_SET);
+    ini_buffer[filesize]='\0';
+
+	while ((fgets(buf, sizeof(buf), f)))
+    {
+		line++;
+		if (buf[0] == '#')
+			continue;
+		pos = buf;
+		while (*pos != '\0')
+        {
+			if (*pos == '\n')
+            {
+				*pos = '\0';
+				break;
+			}
+			pos++;
+		}
+		if (buf[0] == '\0')
+			continue;
+
+		pos = strchr(buf, '=');
+		if (pos == NULL)
+        {
+		    pos = strchr(buf, '[');                
+			continue;
+		}
+		*pos = '\0';
+		pos++;
+
+        if ((strcmp(buf, "pid") == 0) )
+        {
+            cur = 0;
+            while(cur < (int)filesize)
+            {  
+                if ((ini_buffer[cur]=='p') && (ini_buffer[cur+1]=='i') && (ini_buffer[cur+2]=='d'))
+                {
+                    cur += 4;
+                    for( i=4; i>=0; i--)
+                    {
+                        if (ini_buffer[cur] !='\n' )
+                        {
+                            ini_buffer[cur] =0x30;
+                        }
+                        else
+                        {
+                            break;
+                        }
+                        cur++;
+                    }   
+                    break;
+                }
+                cur++;
+            }
+		} 
+    }
+    fseek(f,0,SEEK_SET);
+    fprintf(f, "%s", ini_buffer);    
+    fclose(f);
+#endif
+
+	eloop_terminate();
+}
+
+
+int main(int argc, char *argv[])
+{
+	struct hapd_interfaces interfaces;
+       pid_t child_pid;
+	int ret = 1, i;
+	int c;
+       pid_t auth_pid;
+    char prefix_name[IFNAMSIZ+1];
+    
+	strcpy(prefix_name, "ra");
+	
+	for (;;)
+    {
+		c = getopt(argc, argv, "d:i:h");
+		if (c < 0)
+			break;
+
+		switch (c)
+        {
+			case 'd': 
+				/* 	set Debug level -
+						RT_DEBUG_OFF		0
+						RT_DEBUG_ERROR		1
+						RT_DEBUG_WARN		2
+						RT_DEBUG_TRACE		3
+						RT_DEBUG_INFO		4 
+				*/
+				printf("Set debug level as %s\n", optarg);
+				RTDebugLevel = (int)strtol(optarg, 0, 10);
+				break;
+
+			case 'i': 
+				// Assign the wireless interface when support multiple cards
+				sprintf(prefix_name, "%s%02d_", prefix_name, ((int)strtol(optarg, 0, 10) - 1));
+			    break;
+
+			case 'h':	
+		    default:
+				usage();
+			    break;
+		}
+	} 
+
+	DBGPRINT(RT_DEBUG_TRACE, "prefix_name = '%s'\n", prefix_name);
+
+
+    child_pid = fork();
+    if (child_pid == 0)
+    {           
+		auth_pid = getpid();
+		DBGPRINT(RT_DEBUG_TRACE, "Porcess ID = %d\n",auth_pid);
+        
+        openlog("rt2860apd",0,LOG_DAEMON);
+        // set number of configuration file 1
+        interfaces.count = 1;
+        interfaces.rtapd = malloc(sizeof(rtapd *));
+        if (interfaces.rtapd == NULL)
+        {
+            DBGPRINT(RT_DEBUG_ERROR,"malloc failed\n");
+            exit(1);    
+        }
+
+        eloop_init(&interfaces);
+        eloop_register_signal(SIGINT, Handle_term, NULL);
+        eloop_register_signal(SIGTERM, Handle_term, NULL);
+        eloop_register_signal(SIGUSR1, Handle_usr1, NULL);
+        eloop_register_signal(SIGHUP, Handle_usr1, NULL);
+
+        interfaces.rtapd[0] = Apd_init(prefix_name);
+        if (!interfaces.rtapd[0])
+            goto out;
+        if (Apd_setup_interface(interfaces.rtapd[0]))
+            goto out;
+        
+		// Notify driver about PID
+        RT_ioctl(interfaces.rtapd[0]->ioctl_sock, RT_PRIV_IOCTL, (char *)&auth_pid, sizeof(int), prefix_name, 0, RT_SET_APD_PID | OID_GET_SET_TOGGLE);
+        
+        eloop_run();
+
+        Apd_free_stas(interfaces.rtapd[0]);
+	    ret = 0;
+
+out:
+	    for (i = 0; i < interfaces.count; i++)
+        {
+		    if (!interfaces.rtapd[i])
+			    continue;
+
+		    Apd_cleanup(interfaces.rtapd[i]);
+		    free(interfaces.rtapd[i]);
+	    }
+
+	    free(interfaces.rtapd);
+	    eloop_destroy();
+        closelog();
+	    return ret;
+    }
+    else        
+        return 0;
+}
+
Index: /src/router/rt2860apd/rt2860apd.h
===================================================================
--- /src/router/rt2860apd/rt2860apd.h	(revision 10789)
+++ /src/router/rt2860apd/rt2860apd.h	(revision 10789)
@@ -0,0 +1,115 @@
+#ifndef RT2860APD_H
+#define RT2860APD_H
+
+#include "common.h"
+#include "ap.h"
+
+#define MAX_MBSSID_NUM              8
+#define WEP8021X_KEY_LEN            13
+
+#ifndef ETH_ALEN
+#define ETH_ALEN 6
+#endif
+#ifndef IFNAMSIZ
+#define IFNAMSIZ 16
+#endif
+#ifndef ETH_P_ALL
+#define ETH_P_ALL 0x0003
+#endif
+
+#include "config.h"
+#define NIC_DBG_STRING      (" ")
+
+#define RT_DEBUG_OFF		0
+#define RT_DEBUG_ERROR		1
+#define RT_DEBUG_WARN		2
+#define RT_DEBUG_TRACE		3
+#define RT_DEBUG_INFO		4
+
+// OID definition
+#define OID_GET_SET_TOGGLE							0x8000
+#define RT_QUERY_SIGNAL_CONTEXT						0x0402
+#define	RT_SET_APD_PID								0x0405
+#define RT_SET_DEL_MAC_ENTRY						0x0406
+#define OID_802_11_RADIUS_QUERY_SETTING				0x0540
+
+#define RT_PRIV_IOCTL								(SIOCIWFIRSTPRIV + 0x01)
+#define RTPRIV_IOCTL_ADD_PMKID_CACHE                (SIOCIWFIRSTPRIV + 0x0A)
+#define RTPRIV_IOCTL_RADIUS_DATA                    (SIOCIWFIRSTPRIV + 0x0C)
+#define RTPRIV_IOCTL_ADD_WPA_KEY                    (SIOCIWFIRSTPRIV + 0x0E)
+#define RTPRIV_IOCTL_STATIC_WEP_COPY                (SIOCIWFIRSTPRIV + 0x10)
+
+#define MAC2STR(a) (a)[0], (a)[1], (a)[2], (a)[3], (a)[4], (a)[5]
+#define MACSTR "%02x:%02x:%02x:%02x:%02x:%02x"
+#ifndef ETH_P_PAE
+#define ETH_P_PAE 0x888E /* Port Access Entity (IEEE 802.1X) */
+#endif /* ETH_P_PAE */
+
+#ifndef ETH_P_PRE_AUTH
+#define ETH_P_PRE_AUTH 0x88C7 /* Port Access Entity (WPA2 pre-auth mode) */
+#endif /* ETH_P_PRE_AUTH */
+
+#ifndef ETH_P_VLAN
+#define ETH_P_VLAN 0x8100 /* VLAN Protocol */
+#endif /* ETH_P_VLAN */
+
+#define BIT(x) (1 << (x))
+#define REAUTH_TIMER_DEFAULT_reAuthEnabled TRUE
+#define REAUTH_TIMER_DEFAULT_reAuthPeriod 3600
+
+#if DBG
+extern u32 	RTDebugLevel;	
+#define DBGPRINT(Level, fmt, args...) 					\
+{                                   \
+    if (Level <= RTDebugLevel)      \
+    {                               \
+        printf(NIC_DBG_STRING);   \
+		printf( fmt, ## args);			\
+    }                               \
+}
+#else
+#define DBGPRINT(Level, fmt, args...) 	
+#endif
+
+struct ieee8023_hdr {
+	u8 dAddr[6];
+	u8 sAddr[6];
+	u16 eth_type;
+} __attribute__ ((packed));
+
+typedef struct apd_data {
+	struct rtapd_config *conf;
+	char *prefix_wlan_name;		/* the prefix name of wireless interface */
+
+	int wlan_sock;				/* raw packet socket for wireless interface access */		
+	int eth_sock; /* raw packet socket for ethernet interface access */
+	int ioctl_sock; /* socket for ioctl() use */
+	u8 own_addr[MAX_MBSSID_NUM][6];
+
+	int num_sta; /* number of entries in sta_list */
+	struct sta_info *sta_list; /* STA info list head */
+	struct sta_info *sta_hash[STA_HASH_SIZE];
+
+	/* pointers to STA info; based on allocated AID or NULL if AID free
+	 * AID is in the range 1-2007, so sta_aid[0] corresponders to AID 1
+	 * and so on
+	 */
+	struct sta_info *sta_aid[MAX_AID_TABLE_SIZE];
+
+	struct radius_client_data *radius;
+
+} rtapd;
+
+typedef struct recv_from_ra {
+    u8 daddr[6];
+    u8 saddr[6];
+    u8 ethtype[2];
+    u8 xframe[1];    
+} __attribute__ ((packed)) priv_rec;
+
+void ieee802_1x_receive(rtapd *apd, u8 *sa, u8 *apidx, u8 *buf, size_t len, u16 ethertype);
+u16	RTMPCompareMemory(void *pSrc1,void *pSrc2, u16 Length);
+void Handle_term(int sig, void *eloop_ctx, void *signal_ctx);
+int RT_ioctl(int sid, int param, char  *data, int data_len, char *prefix_name, unsigned char apidx, int flags);
+
+#endif // RT2860APD_H
Index: /src/router/rt2860apd/rtmp_type.h
===================================================================
--- /src/router/rt2860apd/rtmp_type.h	(revision 10789)
+++ /src/router/rt2860apd/rtmp_type.h	(revision 10789)
@@ -0,0 +1,124 @@
+/*
+ ***************************************************************************
+ * Ralink Tech Inc.
+ * 4F, No. 2 Technology 5th Rd.
+ * Science-based Industrial Park
+ * Hsin-chu, Taiwan, R.O.C.
+ *
+ * (c) Copyright 2002, Ralink Technology, Inc.
+ *
+ * All rights reserved. Ralink's source code is an unpublished work and the
+ * use of a copyright notice does not imply otherwise. This source code
+ * contains confidential trade secret material of Ralink Tech. Any attemp
+ * or participation in deciphering, decoding, reverse engineering or in any
+ * way altering the source code is stricitly prohibited, unless the prior
+ * written consent of Ralink Technology, Inc. is obtained.
+ ***************************************************************************
+
+	Module Name:
+	header.h
+
+	Abstract:
+
+	Revision History:
+	Who			When			What
+	--------	----------		----------------------------------------------
+	Name		Date			Modification logs
+	Paul Lin	1-2-2004
+*/
+#ifndef	__RTMP_TYPE_H__
+#define	__RTMP_TYPE_H__
+
+// Put platform dependent declaration here
+// For example, linux type definition
+//#ifdef	Linux
+
+typedef	unsigned short		UINT16;
+typedef	unsigned long		UINT32;
+typedef unsigned long long	UINT64;
+
+//#endif  // Linux
+
+/*
+#ifdef	Win32
+
+#undef	BIG_ENDIAN			// Only little endian foe WIN32 system
+
+typedef	unsigned short		UINT16;
+typedef	unsigned long		UINT32;
+typedef unsigned __int64	UINT64;
+
+#endif  // Win32
+*/
+
+#define PACKED  __attribute__ ((packed))
+
+// Endian byte swapping codes
+#ifdef	BIG_ENDIAN
+#define SWAP16(x) \
+	((UINT16)( \
+	(((UINT16)(x) & (UINT16) 0x00ffU) << 8) | \
+	(((UINT16)(x) & (UINT16) 0xff00U) >> 8) ))
+
+#define SWAP32(x) \
+	((UINT32)( \
+	(((UINT32)(x) & (UINT32) 0x000000ffUL) << 24) | \
+	(((UINT32)(x) & (UINT32) 0x0000ff00UL) <<  8) | \
+	(((UINT32)(x) & (UINT32) 0x00ff0000UL) >>  8) | \
+	(((UINT32)(x) & (UINT32) 0xff000000UL) >> 24) ))
+
+#define SWAP64(x) \
+	((UINT64)( \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x00000000000000ffULL) << 56) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x000000000000ff00ULL) << 40) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x0000000000ff0000ULL) << 24) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x00000000ff000000ULL) <<  8) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x000000ff00000000ULL) >>  8) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x0000ff0000000000ULL) >> 24) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0x00ff000000000000ULL) >> 40) | \
+	(UINT64)(((UINT64)(x) & (UINT64) 0xff00000000000000ULL) >> 56) ))
+#else
+
+#define SWAP16(x)
+#define SWAP32(x)
+#define	SWAP64(x)
+
+#endif  // BIG_ENDIAN
+
+
+#ifdef BIG_ENDIAN
+
+#define cpu2le64(x) SWAP64((x))
+#define le2cpu64(x) SWAP64((x))
+#define cpu2le32(x) SWAP32((x))
+#define le2cpu32(x) SWAP32((x))
+#define cpu2le16(x) SWAP16((x))
+#define le2cpu16(x) SWAP16((x))
+#define cpu2be64(x) ((UINT64)(x))
+#define be2cpu64(x) ((UINT64)(x))
+#define cpu2be32(x) ((UINT32)(x))
+#define be2cpu32(x) ((UINT32)(x))
+#define cpu2be16(x) ((UINT16)(x))
+#define be2cpu16(x) ((UINT16)(x))
+
+#else	// Little_Endian
+
+#define cpu2le64(x) ((UINT64)(x))
+#define le2cpu64(x) ((UINT64)(x))
+#define cpu2le32(x) ((UINT32)(x))
+#define le2cpu32(x) ((UINT32)(x))
+#define cpu2le16(x) ((UINT16)(x))
+#define le2cpu16(x) ((UINT16)(x))
+#define cpu2be64(x) SWAP64((x))
+#define be2cpu64(x) SWAP64((x))
+#define cpu2be32(x) SWAP32((x))
+#define be2cpu32(x) SWAP32((x))
+#define cpu2be16(x) SWAP16((x))
+#define be2cpu16(x) SWAP16((x))
+
+#endif	// BIG_ENDIAN
+
+typedef enum { FALSE = 0, TRUE = 1 } Boolean;
+
+#endif	// __RTMP_TYPE_H__
+
Index: /src/router/rt2860apd/sta_info.c
===================================================================
--- /src/router/rt2860apd/sta_info.c	(revision 10789)
+++ /src/router/rt2860apd/sta_info.c	(revision 10789)
@@ -0,0 +1,253 @@
+/*
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation. See README and COPYING for
+ * more details.
+
+	Module Name:
+	sta_info.c
+
+	Revision History:
+	Who 		When		  What
+	--------	----------	  ----------------------------------------------
+	Jan, Lee	Dec --2003	  modified
+
+*/
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+
+#include <linux/if.h>			/* for IFNAMSIZ and co... */
+#include <linux/wireless.h>
+
+#include "rt2860apd.h"
+#include "sta_info.h"
+#include "eloop.h"
+#include "ieee802_1x.h"
+#include "radius.h"
+
+struct sta_info* Ap_get_sta(rtapd *apd, u8 *sa, u8 *apidx, u16 ethertype, int stop)
+{
+	struct sta_info *s;
+
+	s = apd->sta_hash[STA_HASH(sa)];
+	while (s != NULL && memcmp(s->addr, sa, 6) != 0)
+		s = s->hnext;
+	
+	if (s == NULL)
+	{
+		if(stop)
+		{
+			DBGPRINT(RT_DEBUG_INFO, "Receive discard-notification form wireless driver, but no this STA.\n");
+			return NULL;
+		}
+
+		if (apd->num_sta >= MAX_STA_COUNT)
+		{
+			/* FIX: might try to remove some old STAs first? */
+			DBGPRINT(RT_DEBUG_ERROR,"No more room for new STAs (%d/%d)\n", apd->num_sta, MAX_STA_COUNT);
+			return NULL;
+		}
+
+		s = (struct sta_info *) malloc(sizeof(struct sta_info));
+		if (s == NULL)
+		{
+			DBGPRINT(RT_DEBUG_ERROR,"Malloc failed\n");
+			return NULL;
+		}
+		
+		memset(s, 0, sizeof(struct sta_info));
+		s->radius_identifier = -1;
+
+		s->ethertype = ethertype;
+		if (apd->conf->SsidNum > 1)
+			s->ApIdx = *apidx;
+		else
+			s->ApIdx = 0;
+
+		DBGPRINT(RT_DEBUG_TRACE,"Create a new STA(in %s%d)\n", apd->prefix_wlan_name, s->ApIdx);
+
+		memcpy(s->addr, sa, ETH_ALEN);
+		s->next = apd->sta_list;
+		apd->sta_list = s;
+		apd->num_sta++;
+		Ap_sta_hash_add(apd, s);
+		ieee802_1x_new_station(apd, s);
+		return s;
+	}
+	else
+	{
+		if(stop)
+		{
+			DBGPRINT(RT_DEBUG_TRACE,"Receive discard-notification form wireless driver and remove this station.\n");
+			
+			Ap_free_sta(apd, s);	
+			return NULL;	
+		}	
+		DBGPRINT(RT_DEBUG_TRACE,"A STA has existed(in %s%d)\n", apd->prefix_wlan_name, s->ApIdx);
+	}	
+	
+	return s;
+}
+
+struct sta_info* Ap_get_sta_radius_identifier(rtapd *apd, u8 radius_identifier)
+{
+	struct sta_info *s;
+
+	s = apd->sta_list;
+
+	while (s)
+	{
+		if (s->radius_identifier >= 0 && s->radius_identifier == radius_identifier)
+			return s;
+		s = s->next;
+	}
+
+	return NULL;
+}
+
+static void Ap_sta_list_del(rtapd *apd, struct sta_info *sta)
+{
+	struct sta_info *tmp;
+
+	if (apd->sta_list == sta)
+	{
+		apd->sta_list = sta->next;
+		return;
+	}
+
+	tmp = apd->sta_list;
+	while (tmp != NULL && tmp->next != sta)
+		tmp = tmp->next;
+	if (tmp == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"Could not remove STA " MACSTR " from list.\n", MAC2STR(sta->addr));
+	} else
+		tmp->next = sta->next;
+}
+
+void Ap_sta_hash_add(rtapd *apd, struct sta_info *sta)
+{
+	sta->hnext = apd->sta_hash[STA_HASH(sta->addr)];
+	apd->sta_hash[STA_HASH(sta->addr)] = sta;
+}
+
+static void Ap_sta_hash_del(rtapd *apd, struct sta_info *sta)
+{
+	struct sta_info *s;
+
+	s = apd->sta_hash[STA_HASH(sta->addr)];
+	if (s == NULL) return;
+	if (memcmp(s->addr, sta->addr, 6) == 0)
+	{
+		apd->sta_hash[STA_HASH(sta->addr)] = s->hnext;
+		return;
+	}
+
+	while (s->hnext != NULL && memcmp(s->hnext->addr, sta->addr, 6) != 0)
+		s = s->hnext;
+	if (s->hnext != NULL)
+		s->hnext = s->hnext->hnext;
+	else
+		DBGPRINT(RT_DEBUG_ERROR,"AP: could not remove STA " MACSTR " from hash table\n", MAC2STR(sta->addr));
+}
+
+/*
+	========================================================================
+	Routine Description:
+	   remove the specified input-argumented sta from linked list.. 
+	Arguments:
+		*sta	to-be-removed station.
+	Return Value:
+	========================================================================
+*/
+void Ap_free_sta(rtapd *apd, struct sta_info *sta)
+{
+	DBGPRINT(RT_DEBUG_TRACE," AP_free_sta \n")
+
+	Ap_sta_hash_del(apd, sta);
+	Ap_sta_list_del(apd, sta);
+
+	if (sta->aid > 0)
+		apd->sta_aid[sta->aid - 1] = NULL;
+
+	apd->num_sta--;
+
+	ieee802_1x_free_station(sta);
+
+	if (sta->last_assoc_req)
+		free(sta->last_assoc_req);
+
+	free(sta);
+}
+
+/*
+	========================================================================
+	Description:
+		remove all stations.
+	========================================================================
+*/
+void Apd_free_stas(rtapd *apd)
+{
+	struct sta_info *sta, *prev;
+
+	sta = apd->sta_list;
+	DBGPRINT(RT_DEBUG_TRACE,"Apd_free_stas\n");
+	while (sta)
+	{
+		prev = sta;
+		sta = sta->next;
+		DBGPRINT(RT_DEBUG_ERROR,"Removing station " MACSTR "\n", MAC2STR(prev->addr));
+		Ap_free_sta(apd, prev);
+	}
+}
+
+void Ap_handle_session_timer(void *eloop_ctx, void *timeout_ctx)
+{
+	char *buf;
+	rtapd *apd = eloop_ctx;
+	size_t len;
+	struct ieee8023_hdr *hdr3;
+	struct sta_info *sta = timeout_ctx;
+	
+	DBGPRINT(RT_DEBUG_TRACE,"AP_HANDLE_SESSION_TIMER \n");	  
+	len = sizeof(*hdr3) + 2;
+	buf = (char *) malloc(len);
+	if (buf == NULL)
+	{
+		DBGPRINT(RT_DEBUG_ERROR,"malloc() failed for ieee802_1x_send(len=%d)\n", len);
+		return;
+	}
+
+	memset(buf, 0, len);
+	hdr3 = (struct ieee8023_hdr *) buf;
+	memcpy(hdr3->dAddr, sta->addr, ETH_ALEN);
+	memcpy(hdr3->sAddr, apd->own_addr[sta->ApIdx], ETH_ALEN);
+	// send deauth
+	DBGPRINT(RT_DEBUG_TRACE,"AP_HANDLE_SESSION_TIMER : Send Deauth \n");	  
+	if (RT_ioctl(apd->ioctl_sock, RTPRIV_IOCTL_RADIUS_DATA, buf, len, apd->prefix_wlan_name, sta->ApIdx, 0))
+	{
+		DBGPRINT(RT_DEBUG_ERROR," ioctl \n");
+		return;
+	}
+	free(buf);
+
+//	Ap_free_sta(apd, sta);
+}
+
+void Ap_sta_session_timeout(rtapd *apd, struct sta_info *sta, u32 session_timeout)
+{
+	DBGPRINT(RT_DEBUG_TRACE,"AP_STA_SESSION_TIMEOUT %d seconds \n",session_timeout);
+	eloop_cancel_timeout(Ap_handle_session_timer, apd, sta);
+	eloop_register_timeout(session_timeout, 0, Ap_handle_session_timer, apd, sta);
+}
+
+void Ap_sta_no_session_timeout(rtapd *apd, struct sta_info *sta)
+{
+	eloop_cancel_timeout(Ap_handle_session_timer, apd, sta);
+}
Index: /src/router/rt2860apd/sta_info.h
===================================================================
--- /src/router/rt2860apd/sta_info.h	(revision 10789)
+++ /src/router/rt2860apd/sta_info.h	(revision 10789)
@@ -0,0 +1,12 @@
+#ifndef STA_INFO_H
+#define STA_INFO_H
+
+struct sta_info* Ap_get_sta(rtapd *apd, u8 *sa, u8 *apidx, u16 ethertype, int stop);
+struct sta_info* Ap_get_sta_radius_identifier(rtapd *apd, u8 radius_identifier);
+void Ap_sta_hash_add(rtapd *apd, struct sta_info *sta);
+void Ap_free_sta(rtapd *apd, struct sta_info *sta);
+void Apd_free_stas(rtapd *apd);
+void Ap_sta_session_timeout(rtapd *apd, struct sta_info *sta, u32 session_timeout);
+void Ap_sta_no_session_timeout(rtapd *apd, struct sta_info *sta);
+
+#endif /* STA_INFO_H */
